Express.js-based mock server for RESTful APIs inspired by Wiremock.
- Set up mock response per HTTP method and route/resource path
- For each mock response define
- Status code
- Response headers
- JSON body
- Set up lists of responses
- Set a request delay (e.g. to simulate lag)
- Query number of calls for assertions
To run aietes-js Node.js v16 or newer is recommended.
Install Aietes-js using your preferred dependency manager:
$ npm install aietes-js
$ yarn install aietes-js
or
$ yarn add aietes-js
To run aietes-js as a standalone application run the following command
$ yarn run start
Optional command-line arguments
--port=4321
Start the server on the given port if it is free, a random free port otherwise.
--json=response.json
Absolute or relative path to a response definition file (see below)
The project includes a Dockerfile to create an image with a single Aietes instance. To build the image run:
$ docker build .
You can optionally set your preferred port to expose and start Aietes on. The default port is 8080.
$ docker build --build-arg container_port=<port> .
When starting the container, map the exposed port to a port on the host.
$ docker run -p <host port>:<exposed port> <container id from build>
Example usage in Jest style tests.
let mockServer;
// instantiate the mock server with config and a free port to run on and start it
beforeAll(() => {
mockServer = new AietesServer(defaultResponseConfiguration, someFreePort);
mockServer.start();
});
// optionally reload your config after each test case without restarting the server
afterEach(() => {
mockServer.update(defaultResponseConfiguration);
});
// stop and destroy the mock server instance
afterAll(() => {
mockServer.stop();
});
// ...
// update (some or all) existing endpoints with new response definitions
// endpoints missing in this config are not altered
it('some test case', async () => {
mockServer.update(partialCustomResponseConfiguration);
// ...
});
Caution: You can also reset the server. This means that the mock server instance is stopped, torn down and restarted with new routes and response configuration. All previously defined routes and responses are dropped!
mockServer.reset(newRoutesAndResponseConfiguration);
The response configuration object that needs to be passed to the AietesServer constructor, broken down here for clarity.
{
"/endpoint1": {
// currently supported HTTP methods
get: someResponseObject,
post: someResponseObject,
delete: someResponseObject,
put: someResponseObject
},
"/endpoint2": {
// empty response, default status is 200
get: {}
},
"/endpoint3": {
// list of responses
get: [
someResponseObject,
someResponseObject2
]
}
}
NB some simple wildcard expressions are possible in route names (since the underlying ExpressJs server allows it).
{
// matches all paths /endpoint1, /endpoint1/pathVariable, etc.
"/endpoint1(/*)?": {
// ...
},
// matches all paths /endpoint2/pathVariable, etc.
"/endpoint2/*": {
// ...
}
}
Format of an individual response object.
{
status: 201,
headers: {
"some-header": "header-value"
},
data: {
"field1": 1,
"field2": "value",
"field3": false
}
}
A delay in mock request processing can be set to simulate network lag or long running operations. This can be done per route and method or globally.
Setting the delay in milliseconds:
mockServer.setDelayMs(200);
Resetting the delay:
mockServer.setDelayMs(0);
or
mockServer.setDelayMs();
Setting the delay in milliseconds:
mockServer.setDelayMs(200, "/endpoint1", "get");
Resetting the delay:
mockServer.setDelayMs(null, "/endpoint1", "get");
This will only take effect for this request/response pair, meaning if it is part of a list of responses the delay will only be applied to the response with meta
block.
A delay configured in this way can be overridden by using one of the above calls to set a global or per-route delay.
{
status: ...,
headers: ...,
data: ...,
meta: {
delayMs: 200
}
}
To facilitate assertions the Aietes server instance offers an API to query the number of calls to the combination of endpoint and HTTP method. In its simplest form the query takes two string arguments:
mockServer.timesCalled('/endpoint1/', 'get')
- Note: Even though NodeJs routes are by default not case-sensitive and ignore the trailing '/', this is not true of the Aietes server.
i.E.mockServer.timesCalled('/endpoint1/', 'get')
!=mockServer.timesCalled('/endpoint1', 'get')
andmockServer.timesCalled('/ENDpoint1/', 'get')
!=mockServer.timesCalled('/endPOINT1/', 'get')
The first argument may also be a single-argument predicate to filter by:
mockServer.timesCalled(path => { return path.startsWith('/endpoint'); }, 'get')
The second argument may also be a list of HTTP methods:
mockServer.timesCalled('/endpoint1/', ['get', 'post'])
The Aietes server instances also offers an API call to obtain the query parameters passed to the mock on a per call basis. The matching of calls is stricter since parameters can only apply to a single call, so only the exact strings for path and method are allowed. Assuming a call to the mock endpoint such as
GET /endpoint1/?param1=foo¶m2=bar¶m3=42
a call to
mockServer.queryParameters('/endpoint1/', 'get')
will return a list of objects with the single element
{ param1: 'foo', param2: 'bar', param3: '42' }
Objects for further calls are appended to this list.
To clear the call stats:
mockServer.clearStats()
- Note: stats are also cleared when the response config is reset. They are left unchanged on update.
A complete example project including the above can be found in the /example
directory of the project.
Issues, bugs and feature requests
Inspired by Mock-Json-Server and Wiremock
Aietes (or one of the official English spellings, "Aeëtes", "Aeeta", or "Æëtes") was the king of Colchis in the myth of Jason and the Argonauts. He subjected Jason, who had come for the golden fleece, to several wicked tests (and may have mocked him in the process). See Wikipedia on Aietes and Jason in Colchis.