Simple, configurable part mock part proxy

Related tags

Node.js HTTP moxy
Overview

Moxy

Simple, configurable mock / proxy server.

npm (scoped) Docker Image Version (latest semver) GitHub tag (latest SemVer)


Table of Contents

Quick start

Programatic

npm i -D @acrontum/moxy
import { MoxyServer } from '@acrontum/moxy';

const moxy = new MoxyServer();

moxy.on('hello/world', {
  get: {
    status: 200,
    body: {
      message: 'Welcome!'
    }
  }
});

await moxy.listen(5000);

CLI

npx @acrontum/moxy --port 5000 --routes ./routes/

Docker

docker run \
  --name moxy \
  --publish 5000:5000 \
  --volume $PWD/routes:/opt/routes \
   acrontum/moxy --port 5000 --routes /opt/routes

Docker compose

version: "3.7"

services:
  moxy:
    image: acrontum/moxy
    container_name: moxy
    volumes:
      - ./routes:/opt/routes
    environment:
      - PORT=80
    ports:
      - 5000:80
    init: true
    command: --allowHttpRouteConfig --routes /opt/routes

Usage

The example config (found here) has configuration options with comments.

Programatic

import { MoxyServer } from '@acrontum/moxy';

// initialize with default settings (optional)
const moxy = new MoxyServer({
  logging: 'verbose',
  router: {
    allowHttpRouteConfig: false
  }
});

// start listening on port 5000 (can be done before or after route configuration)
await moxy.listen(5000);

// configure listener for a GET /some/path, responding with a 200 and text body "Hi!"
moxy.on('/some/path', {
  get: {
    status: 200,
    body: 'Hi!',
    headers: { 'Content-Type': 'text/plain' }
  }
});

// configure multiple routes (/auth/login, /auth/logout, and /auth/register) by prefix:
moxy.onAll('/auth/', {
  '/login/': {
    post: {
      status: 401, 
      body: { message: 'Unauthorized' }
    }
  },
  '/logout/': {
    post: {
      stauts: 204
    }
  },
  '/register/': {
    post: {
      status: 201,
      body: { message: 'welcome' }
    }
  }
});

// handle all methods with an HTTP request handler
moxy.on('/not/a/test', (req: MoxyRequest, res: MoxyResponse, variables: HandlerVariables) => {
  console.log('Hi world.');
  return res.sendJson({ pewPew: 'lazors' });
});

// using basic variable replacement, search in a static folder and return an image
moxy.on('/users/:userId/profile-picture', '/static/images/:userId.png');

// ... make requests against moxy

// stop the server. closeConnections: true will not wait for any requests to finish.
await moxy.close({ closeConnections: true });

See API for full usage.

Via HTTP requests

Assuming moxy is running at localhost:5000, and has HTTP config enabled:

# hit the moxy api
curl localhost:5000/_moxy/

# add a new handler that responds to GET /test/path with a 204 no content
curl localhost:5000/_moxy/routes \
  -H 'Content-Type: application/json' \
  -d '{ 
    "path": "/test/path", 
    "config": { 
      "get": { 
        "status": 200, 
        "body": "neat" 
      } 
    } 
  }'

# will show the array of paths avaiable
curl localhost:5000/_moxy/routes

# will show paths and their handler object currently configured
curl localhost:5000/_moxy/router

# test our new route
curl localhost:5000/test/path

# remove our new route
curl -X DELETE localhost:5000/_moxy/routes/test/path

# add a "once" route handler
curl localhost:5000/_moxy/routes?once=true \
  -H 'Content-Type: application/json' \
  -d '{ 
    "path": "/pew/pew", 
    "config": { 
      "get": { 
        "status": 200, 
        "body": "neat" 
      } 
    } 
  }'

# 200
curl localhost:5000/pew/pew

# 404
curl localhost:5000/pew/pew

Note that you will not be able to configure the response using a function via HTTP.

See API for full usage.

From files

Moxy can load routing configs from the filesystem, searching recursively for .js or .json files matching <anything>.routes.js(on). This allows you to organize routes into files, and put them in a routes folder (see example).

await moxy.router.addRoutesFromFolder('/path/to/routes/folder');
# npx cli
npx @acrontum/moxy --routes /path/to/routes/folder

# docker run
docker run acrontum/moxy --routes /path/to/routes/folder
version: "3.7"

services:
  moxy:
    image: acrontum/moxy
    volumes:
      - ./routes:/opt/routes
    command: --routes /opt/routes

When loading routes from folders, the tree structure will determine the routing. For instance, if your folder structure looks like this:

public/
├── routes
│   ├── a
│   │   ├── a.routes.js
│   │   └── b
│   │       └── b.routes.js
│   └── c
│       └── c.routes.json
└── static
    ├── css
    ├── js
    └── index.html

And you loaded the public folder into moxy's router, your route config would look like:

{
  "/public/routes/a/": "...config from a.routes.js file",
  "/public/routes/a/b/": "...config from b.routes.js file",
  "/public/routes/c": "...config from c.routes.json file"
}

If you instead loaded the a folder, it would look like:

{
  "/a/": "...config from a.routes.js file",
  "/a/b/": "...config from b.routes.js file",
}

Static files

When you configure a method to be a string, moxy will serve files from disk:

export const routes = {
  '/static/(?<file>.*)': {
    get: '/public/:file',
  },
  '/assets/(?<file>.*)': {
    get: '/images/:file',
  }
}

// or 

moxy
  .on('/static/(?<file>.*)', { get: '/public/:file' })
  .on('/assets/(?<file>.*)', { get: '/images/:file' });

With the above config, moxy will look in the ./public folder for requests to /static/path/to/file, and the ./images folder for requests to /assets/path/to/file.

These are relative to the process's current directory, so if you ran from this folder it would look in ./images and ./public and try to return the file.

More examples

example config (found here):

import { HandlerVariables, MoxyRequest, MoxyResponse, Routes } from '@acrontum/moxy';

export const routeConfig: Routes = {
  // example using basic path params and replacements.
  '/:machineId/measurements/:measurementId': {
    get: {
      status: 200,
      // variables from the path can be injected into the response.
      // The simple version is ":variableName" in the path params and body. By
      // default, this will only match word boundaries (eg /:variable/).
      body: `<!DOCTYPE html><html>
        <head>
          <meta charset="utf-8">
          <title>:machineId/:measurementId</title>
        </head>
        <body>
          <h1>Machine: :machineId - measurement: :measurementId</h1>
        </body>
      </html>`,
      headers: {
        'Content-Type': 'text/html',
      },
    },
  },
  // The more complicated method is using regex capture groups. This allows for
  // more control over how groups are captured (eg for matching slashes in the
  // path.
  '/static/(?<file>.*)': {
    // When the value for a method is a simple string, a file is assumed.
    get: '/public/:file',
  },
  'auth/login': {
    post: {
      status: 200,
      body: {
        active: true,
        user_id: 'user_id',
      },
    },
  },
  '/users/:username': {
    patch: {
      status: 200,
      body: {
        firstName: 'pat',
        username: ':username',
      },
    },
    get: {
      status: 200,
      body: {
        firstName: 'pat',
        username: ':username',
      },
    },
  },
  // example which proxies requests from moxy.test/proxied-server/<target> to google/<target>
  'proxied-server(?<path>.*)': {
    // here, everything after proxied-server is passed through to the proxy target
    proxy: 'https://www.google.com:path',
    // proxy options are the same as http request options, and are passed through.
    proxyOptions: {
      headers: {
        'x-auth-token': 'totally-real',
      },
    },
  },
  'manual-override': (request: MoxyRequest, response: MoxyResponse, variables: HandlerVariables) => {
    response.writeHead(418);
    response.end('I am a teapot');
  },
  'partly-manual-override/:userId': {
    get: {
      status: 418,
      body: 'I am a teapot',
    },
    post: (request: MoxyRequest, response: MoxyResponse, variables: HandlerVariables) => {
      response.writeHead(201);
      response.end(`Brew started for ${variables.userId}`);
    },
  },
  '/glacial/': {
    // slow all methods by 100ms
    delay: 100,
    get: {
      // slow only 1 method by 100ms
      delay: 100,
      status: 204,
    },
    delete: {
      status: 204,
    },
  },
  // note that by default, the path is converted to a regex, so special chars
  // should be escaped
  '/path/with/query\\?search=:theSearchThing': {
    get: {
      body: 'you searched for :theSearchThing',
      headers: { 'Content-Type': 'text/plain' },
    },
  },
  // passing exact: true will prevent the path from being converted to a regex.
  // NOTE: this will also disable simple or regex replacements. Parsed query
  // params will still be returned in HandlerVariables if you use a request 
  // handler (see below).
  '/exact/match/:notCaptured?queryMustHave': {
    exact: true,
    get: {
      status: 204,
    },
  },
  // if the handler would normally be a function and exact matching is desired,
  // the 'all' method can be used to achieve this.
  '/exact/match/handler?ignore=(.*)': {
    exact: true,
    all: (request: MoxyRequest, response: MoxyResponse, variables: HandlerVariables) => {
      return response.sendJson({ matchedExactly: true });
    },
  },
};

API

See full API docs.

CLI options

# npx @acrontum/moxy --help

Start a mocking server

options:
-r, --routes FOLDER     Add routes from FOLDER. Can be called multiple times,
                        FOLDER can be multiple separated by comma (,).
-p, --port PORT         Run on port PORT. If none specified, will find an
                        avaiable port.
-q, --quiet             Decrease log verbosity.
-a, --allowHttpConfig   Allow routes config via HTTP methods. Default false.
-h, --help              Show this menu.

HTTP API

Moxy exposes some default HTTP routes for checking routing configurations. With allowHttpRouteConfig enabled:

const server = new MoxyServer({ router: { allowHttpRouteConfig: true } });
npx @acrontum/moxy --allowHttpConfig

it will also expose HTTP CRUD routes.

The HTTP API offers most of the functionality that programatic or file configs offer, although it is not possible to send request handler methods at this time.

GET /_moxy:

Returns the list of api methods:

{
  "GET /router?once=false&serializeMethods=true": "show router",
  "GET /routes?once=false": "show router routes"
}
 - or -
{
  "GET /router?once=false&serializeMethods=true": "show router",
  "GET /routes?once=false": "show router routes",
  "POST /routes?once=false": "create route",
  "PUT /routes/:route": "create or update route",
  "PATCH /routes/:route": "update route",
  "DELETE /routes/:route": "delete route",
}

GET /_moxy/routes

Display a list of routes which moxy is listening to with default query params (if applicable).

Query params:

once=true: Show routes which will fire once then be removed (eg for testing).

serializeMethods=false: Don't call .toString() on methods (removes some noise).

GET /_moxy/router

Will return the current router config, including response handlers.

Query params:

once=true: Show routes which will fire once then be removed (eg for testing).

serializeMethods=false: Don't call .toString() on methods (removes some noise).

POST /_moxy/router

Will add a json payload to the router.

The payload should contain path and config, where path is the router path and config is RouteConfig:

{
  "path": "/some/path",
  "config": {
    "get": {
      "status": 200
    }
  }
}

Query params:

once=true: As soon as this route is hit, remove it.

The response will be a 200 containing the newly added route.

PATCH /_moxy/router/:route

Will update the route specified by :route (:route will match everything after /router/ including slashes).

Payload: RouteConfig.

The response will be a 200 containing the newly updated route.

PUT /_moxy/router/:route

Will replace the route specified by :route (:route will match everything after /router/ including slashes).

Payload: RouteConfig.

The response will be a 200 or 201 containing the created or updated route.

DELETE /_moxy/router/:route

Will delete the route specified by :route (:route will match everything after /router/ including slashes).

The response will be a 200 containing { message: 'Ok' };

You might also like...

Highly sophisticated proxy used for evading internet censorship or accessing websites in a controlled sandbox using the power of service-workers and more! Easy deployment version (Node.js)

Highly sophisticated proxy used for evading internet censorship or accessing websites in a controlled sandbox using the power of service-workers and more! Easy deployment version (Node.js)

Ultraviolet-Node The deployable version of Ultraviolet, a highly sophisticated proxy used for evading internet censorship or accessing websites in a c

Jan 2, 2023

Highly sophisticated proxy used for evading internet censorship or accessing websites in a controlled sandbox using the power of service-workers and more! Easy deployment version (Node.js)

Highly sophisticated proxy used for evading internet censorship or accessing websites in a controlled sandbox using the power of service-workers and more! Easy deployment version (Node.js)

Ultraviolet-Node The deployable version of Ultraviolet, a highly sophisticated proxy used for evading internet censorship or accessing websites in a c

Apr 15, 2022

A simple NodeJS WebSocket WebApp vulnerable to blind SQL injection

A simple NodeJS WebSocket WebApp vulnerable to blind SQL injection

NodeJS WebSocket SQLi vulnerable WebApp A one-day build of a vulnerable WebSocket app on NodeJS to practice boolean based SQLi over WebSocket. I made

Dec 27, 2022

一个基于node.js,express,socket.io的websocket非常棒的聊天室,代码简单很适合新手. A very nice websocket chat room based on node.js, express, socket.io. the code is simple, very suitable for novices

一个基于node.js,express,socket.io的websocket非常棒的聊天室,代码简单很适合新手.  A very nice websocket chat room based on node.js, express, socket.io. the code is simple, very suitable for novices

来来往下看,虽然教程又臭又长但是一步步地保姆式教学很简单的,毕竟我是真菜鸟嘛,当然什么都往细了说╮(╯_╰)╭ 一、使用方法 该教程内容所有指令都为Linux CentOS 7.x环境下指令,其他平台请您自行查询(⊙x⊙;) 1.下载node.js并下载Sakura_Chat_Room node.j

Jul 21, 2022

A simple emitter npm package

Emitter A simple emitter package This package is pretty self explanatory... need to get and send events? use an emitter Table of content How to use? P

Feb 26, 2022

Global HTTP/HTTPS proxy agent configurable using environment variables.

global-agent Global HTTP/HTTPS proxy configurable using environment variables. Usage Setup proxy using global-agent/bootstrap Setup proxy using bootst

Dec 20, 2022

The official proxy of Titanium Network with enhanced support for a large majority of sites with hCAPTCHA support. Successor to Alloy Proxy.

Corrosion Titanium Networks main web proxy. Successor to Alloy Installation: npm i corrosion Example: const Corrosion = require('corrosion'); const p

Dec 21, 2022

proxy 🦄 yxorp is your Web Proxy as a Service (SAAS) Multi-tenant, Multi-Threaded, with Cache & Article Spinner

proxy 🦄 yxorp is your Web Proxy as a Service (SAAS) Multi-tenant, Multi-Threaded, with Cache & Article Spinner

proxy 🦄 yxorp is your Web Proxy as a Service (SAAS) Multi-tenant, Multi-Threaded, with Cache & Article Spinner. Batteries are included, Content Spinning and Caching Engine, all housed within a stunning web GUI. A unique high-performance, plug-and-play, multi-threaded website mirror and article spinner

Dec 30, 2022

Proxy but misspelled -- closed proxy for the internet

pyrox Proxy that runs on Cloudflare Workers. Setup Install wrangler2. npm install wrangler. Generate a public Ed25519 key, exported under SPKI mode wi

Sep 9, 2022

:dash: Simple yet powerful file-based mock server with recording abilities

:dash: Simple yet powerful file-based mock server with recording abilities

💨 smoke Simple yet powerful file-based mock server with recording abilities Just drop a bunch of (JSON) files in a folder and you're ready to go! Bas

Dec 13, 2022

TChart.js - simple and configurable Bar and Line Chart library in Javascript

TChart.js - simple and configurable Bar and Line Chart library in Javascript

TChart.js Simple and configurable Bar and Line Chart library in Javascript Description TChart.js is a canvas-based simple Javascript Bar and Line Char

Mar 3, 2021

Simple and configurable tool to manage daily huddles in a remote team.

Daily Huddle Simple and configurable tool to manage daily huddles in a remote team. See working version. What's this? This repo has been developed as

Oct 2, 2022

Mockpay Checkout for developers to mock payment gateway

Mockpay Checkout Mockpay Checkout is a simple js library that allows you to integrate mockpay into your web apps. Checkout the documentation at: https

Nov 26, 2022

Base-mock-api - Repo to storage my fake api's to use in my 2022 projects.

Base Mock API's Project made 100% with JavaScript, with the objective of creating endpoints to use in projects. Prerequisites Before you begin, ensure

Nov 20, 2022

Quickly create an interactive HTML mock-up by auto sourcing lorem ipsum/images generators, with minimal html markup, and no server side code

RoughDraft.js v0.1.5 Quickly mockup / prototype HTML pages with auto-generated content, without additional JavaScript or server side code. section

Dec 21, 2022

Linely is inspired by LocalStack. Goal of this tool is to create a mock service for LINE.

Linely Linely is inspired by LocalStack. Goal of this tool is to create a mock service for LINE. Setup Docker docker run -d -p 3000:3000 dyoshikawa/li

Jan 24, 2022

NiseLine is inspired by LocalStack. Goal of this tool is to create a mock service for LINE.

NiseLine NiseLine is inspired by LocalStack. Goal of this tool is to create a mock service for LINE. Getting Started Launch NiseLine server. docker ru

Jan 24, 2022

A cli tool to generate random mock data from OpenAPI definition for msw.

msw-auto-mock A cli tool to generate random mock data from OpenAPI descriptions for msw. Why We already have all the type definitions from OpenAPI spe

Dec 15, 2022

NiseLine is inspired by LocalStack. Goal of this tool is to create a mock service for LINE.

NiseLine is inspired by LocalStack. Goal of this tool is to create a mock service for LINE.

NiseLine NiseLine is inspired by LocalStack. Goal of this tool is to create a mock service for LINE. Getting Started Launch NiseLine server by Docker

Jul 29, 2022
Comments
  • Feat/improve documentation

    Feat/improve documentation

    • added: many more examples of usage, and fixed typos in readme
    • fix: issue with npx parsing --on when inline json contains \n char for multiline json string
    • fix: parsing moxy.on('path','files') failed to properly parse as regex
    • fix: req body is read on demand (fixes issue with no 'end' event emitted)
    • fix: disable file paths with .. by default (can override by handling manually)
    opened by p-mcgowan 0
  • Feat/cli inline route config

    Feat/cli inline route config

    • added: cli support for -o, --on <json_config> (same as http post routes)
    • added: error handling and basic validation
    • changed: minor performance improvements in tests
    • docs: added example for programatic path loading and cli with --on and cleaned up formatting
    • breaking change: --allowHttpConfig cli option renamed to --allow-http-config
    opened by p-mcgowan 0
  • Fix/query parsing logic

    Fix/query parsing logic

    • fixed: url parsing failed on querystring or anything that looked like a regex but is not
    • fixed: buffer was beng serialized and dumped to term
    • added: moxy 'onAll' api to simplify Routes vs Config parsing
    • added: 'exact' option to prevent regex parsing the url
    • added: 'all' option to RouteConfig to enable exact for handler functions
    • added: logging config api and instance-scoped logger
    • added: more example routes and comments
    • changed: moved files around
    • changed: improved doxy comments and interface and variable names
    opened by p-mcgowan 0
Owner
Acrontum GmbH
Acrontum GmbH
The official proxy of Titanium Network with enhanced support for a large majority of sites with hCAPTCHA support. Successor to Alloy Proxy.

Corrosion Titanium Networks main web proxy. Successor to Alloy Installation: npm i corrosion Example: const Corrosion = require('corrosion'); const p

Titanium Network 79 Dec 21, 2022
:dash: Simple yet powerful file-based mock server with recording abilities

?? smoke Simple yet powerful file-based mock server with recording abilities Just drop a bunch of (JSON) files in a folder and you're ready to go! Bas

Yohan Lasorsa 159 Dec 13, 2022
Build a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.

http-fake-backend Build a fake backend by providing the content of JSON files or JavaScript objects through configurable routes. It actually can serve

Micromata GmbH 279 Dec 11, 2022
Simple proxy that is intended to support on chaos testing.

Proxy with Behavior Proxy with Behavior is a node application that work as a reverse proxy, and enables apply some behaviors to be executed in request

José Carlos de Moraes Filho 7 Jan 28, 2022
A full-featured http proxy for node.js

node-http-proxy node-http-proxy is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as

http ... PARTY! 13.1k Jan 3, 2023
Full-featured, middleware-oriented, programmatic HTTP and WebSocket proxy for node.js

rocky A multipurpose, full-featured, middleware-oriented and hackable HTTP/S and WebSocket proxy with powerful built-in features such as versatile rou

Tom 370 Nov 24, 2022
A proxy web app that serves ABC iView content outside of the iView webplayer, avoiding intrusive data harvesting.

iview-proxy A proxy web app that serves ABC iView content outside of the iView webplayer, avoiding intrusive data harvesting. There's also a cool Andr

The OpenGov Australia Project 11 Jul 16, 2022
DSC-AlarmServer - Creates web interface to DSC/Envisalink with proxy.

DSC-AlarmServer Creates web interface to DSC/Envisalink with proxy. Since the Envisalink module can only have one connection, this phython script can

null 4 Oct 11, 2022
Prefect API Authentication/Authorization Proxy for on-premises deployments

Proxy Authorization Service for Prefect UI and Prefect CLI Prefect is a great platform for building data flows/pipelines. It supports hybrid execution

Softrams 20 Dec 10, 2022
wabac.js CORS Proxy

wabac.js CORS Proxy This provides a simple CORS proxy, which is designed to run as a Cloudflare Worker. This system is compatible with wabac.js-based

Webrecorder 3 Mar 8, 2022