npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@teamjourney/api-mock-server

v0.2.6

Published

API mocking library that runs as a real HTTP server

Downloads

1,644

Readme

API Mock Server

API mocking library that runs as a real HTTP server in Node.js

API Mock Server can be used to test code that performs HTTP requests without calling the real service and allows full control over the request and responses.

Table of Contents

How it works

API Mock Server runs on a real port and responds to real HTTP requests. This means that it is ideal for testing or simulating HTTP requests made by any language or system without interacting with its code directly.

This approach differs to projects such as nock which work by overriding Node's http.request function.

Control of the mock is handled in Node.js and works well with testing frameworks such as Mocha or Jasmine.

Install

npm install --save-dev @teamjourney/api-mock-server

or

yarn add --dev @teamjourney/api-mock-server

Node version support

Tested on Node.js 10.x and 12.x

Usage

NodeJS

const server = require('@teamjourney/api-mock-server').default;

server.start(9001)
    .then(() => {
        server.mock(
            { path: '/my-endpoint' },
            { body: { data: 'something' } },
        );

        // Call GET http://localhost:9001/my-endpoint here
        // It will return with a JSON body of { data: 'something' }

        server.stop();
    });

ES6

import server from '@teamjourney/api-mock-server';

const init = async () => {
    await server.start(9001);

    server.mock(
        { path: '/my-endpoint' },
        { body: { data: 'something' } },
    );

    // Call GET http://localhost:9001/my-endpoint here
    // It will return with a JSON body of { data: 'something' }

    server.stop();
};

init();

Multiple instances (optional)

It's possible (but optional) to create multiple instances of the mock server running on different ports, each with their own routes and logging.

Use instances of the MockServer class to achieve this. The below example is in ES6 for simplicity.

import { MockServer } from '@teamjourney/api-mock-server';

const server = new MockServer();

MockServer has the same interface as the core library functions so all of the below functions should work.

Starting the server

Calling start with a port number allows you to specify a port.

server.start(9002)

Calling start without a port will attempt to start on a random port. It returns a promise which resolves to http.Server object. This allows for finding out the port it is being run on.

server.start()
    .then((httpServer) => {
        const { port } = serverInfo.address();

        ...
    });

Stopping the server

Calling stop will stop the server.

server.stop();

Resetting the server

Calling reset will keep the server running but will clear all mocks and logged requests.

server.reset();

It's also possible to reset specific mocks by passing an array to reset.

server.reset([ { path: '/my-endpoint' } ]);

This will remove the mock as well as removing it from the uncalled mocks list. If the mock has been called however, it will still appear in the called mocks list.

Trying to reset a mock that doesn't exist will fail silently.

Defining mocks

Mocking requests and responses simply involves calling mock with two arguments. The first defines the request shape and the second the response shape.

The simplest call would be

server.mock({ path: '/my-endpoint' });

This would handle any GET requests (the default method) to /my-endpoint and return am empty 200 response (the default response status).

There are numerous ways to configure specific behaviours that are defined below.

Unmocked requests

Any unmocked requests will return an empty 501 (Not Implemented) response.

Duplicate mocks

Calling mock with a request shape that matches an already mocked request will throw an error.

server.mock({ path: '/my-endpoint' });
server.mock({ path: '/my-endpoint' });

Will throw an error with the following message:

Request matching {
    "method": "GET",
    "path": "/my-endpoint"
} already mocked

Mocking requests

Specifying paths

The path is the only required property when defining the request shape.

server.mock({ path: '/my-endpoint' });

Specifying HTTP methods

Providing a method will match only requests using that method. If no method is specified and the request has a body (see below) then the method defaults to POST, otherwise it defaults to GET.

server.mock({ path: '/my-endpoint', method: 'DELETE' });

The method string is case-insensitive.

Supported methods are GET, POST, PUT, DELETE and HEAD.

Multiple mocks defined on the same endpoint with different methods are treated as independent mocks.

Specifying query strings

Query strings can be mocked in 2 ways; either by adding the query string to the path field or by providing a separate object on the query field.

server.mock({ path: '/my-endpoint?page=1&perPage=20' });

or

server.mock({ path: '/my-endpoint', query: { page: '1', perPage: '20' } });

In the second style, the object values should always be specified as strings.

If no query string is specified in the mock then any request to that endpoint will match, regardless of the query string.

Specifying request bodies

Request bodies can be mocked by providing the body property. Deeply nested object structures will be matched recursively.

server.mock({ path: '/my-endpoint', body: { foo: 'bar' } });

The data types of the mock and the request fields need to match exactly. This is by design, as many real servers are sensitive to this.

If a request body is specified but with no method, the method will default to POST.

If no request body is specified in the mock then any request to that endpoint using that method will match, regardless of the request body.

Specifying request headers

Request headers can be mocked by providing the headers property with header type and value being object properties and values respectively.

server.mock({ path: '/my-endpoint', headers: { 'X-Foo', 'bar' } });

Requests will be handled if all the headers specified in the mock match. Any other headers on the request will match, regardless of the headers.

Mocking Responses

Customise the response for a particular mock by passing an object as the second argument to mock to define the response shape.

The response argument is optional. If no response is provided the mock will return a 200 status with an empty body.

Specifying response statuses

The response status can be set by providing a status property.

server.mock({ path: '/my-endpoint' }, { status: 201 });

If no status is specified the response will default to 200.

Specifying response bodies

The response body can be set by providing a body property.

server.mock({ path: '/my-endpoint' }, { body: { foo: 'bar' } });

Specifying response headers

The response headers can be set by providing a headers property which should be an object with header type and value being object properties and values respectively.

server.mock({ path: '/my-endpoint' }, { headers: { 'x-foo': 'bar' } });

The response will always contain the specified headers but may also contain additional headers automatically added by the server.

Recording

All mocks and requests are logged by the server which provides easy access to this information in a format similar to the way mocks are defined. This structure is intended to make adding and adjusting mocks easier.

Getting unhandled requests

To get any requests that were not handled by a mock, call getUnhandledRequests.

server.getUnhandledRequests();

This will return an array of requests in the order that they occurred. For example:

[
    {
        "request": {
            "path": "/my-endpoint",
            "method": "GET"
        }
    },
]

Getting handled requests

To get requests that were handled by mocks including what response was returned, call getHandledRequests.

server.getHandledRequests();

This will return an array of requests and responses in the order that they occurred. For example:

[
    {
        "request": {
            "path": "/my-endpoint",
            "method": "GET"
        },
        "response": {
            "status": 200
        }
    }
]

Getting uncalled mocks

To get a list of any mocks that have not been called, call getUncalledMocks.

server.getUncalledMocks();

This will return an array of uncalled mocks in the order that they were defined. For example:

[
    {
        "request": {
            "path": "GET",
            "method": "/endpoint"
        },
        "response": {
            "status": 200
        }
    }
]

Proxying requests

In some situations it maybe useful to be able to proxy requests that aren't mocked to a real server.

server.start(9001, 'http://realserver.com');

When a request is proxied the mock server will return the response exactly as it was returned by the real server.

Both the request and the response are recorded and are available via the getProxiedRequests method.

server.getProxiedRequests();

Any mocks that match will be handled first and those requests won't be proxied. This allows for selective mocking of APIs.

Current Limitations

  • There is no support for non-JSON request or response bodies
  • The server cannot be run with any hostname other than localhost
  • The path matcher uses Express routes under the hood so theoretically any pattern that Express supports should work, but this functionality is untested

Credits

This library was inspired and influenced by:

License

MIT