Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Simple API Mocking Tool with Node

0.00/5 (No votes)
10 Sep 2018 2  
A guide to creating an API Mocking utility in Node

Introduction

  1. Does your work depend on other's API?
  2. Does your work delay due to API unavailability?
  3. Are you interested in developing a Node utility?

If your answer to any of the above questions is YES, then this article is for you.

Background

Constant change in API breaks the endpoints and also consumes time for deployment. These changes in API delays frontend team's work. So I thought of using some API mocking tools, but all those tools have their own learning curve. This encouraged me to quickly create a simple and straightforward API mocking utility.

About the Utility

This utility helps developers to continue their task independently of API availability. A developer just needs to route all their API requests through this tool and it will cache the response and return mocked response in case of errors.

Uses

  • Install api-mock-proxy

    npm install -g api-mock-proxy
  • Now, you can run your mock proxy as:

    api-mock-proxy -p 8000 -t http://your.api.com

    Now your proxy server is ready at http://localhost:8000. Just use this URL in all clients and you will get the response from http://your.api.com. The best part is, it will return the mocked response if the actual API is not working.

Available Options

  • port or -p: (default:8080) - to specify the port to which mock server will listen

  • targetUrl or -t: (default:http://localhost:80) - to specify the target URL where the mock server will forward all requests and return the response back. This will be URL for your actual API and the mock server will save the response for mocking when API responds with an error.

  • errorCodes or -e: (default:*) - this will provide options for mocking on errors, error code will be provided in comma separated list, e.g., 404,500,ECONNREFUSED The default value is *, which means it will return a mocked response for any error unless not running in record mode.

  • mode or -m: (default:mix) - It can take any of the three values mock|record|mix
    • mock: mock all the requests, there is no need to call actual API
    • record: always return response from actual API and create a cache for future mocking
    • mix: call the actual API and return actual response except error code passed as mockedError
  • dataPath or -d: (default:./data.json) - path for the mock data, it should be a valid data file. For the first time, just specify the path and mock will be created at that location. For running in mock mode, there must be pre-populated mock data.

  • --cors - use this to enable cors header for all origin, methods and headers

  • allowOrigin - provide a string to be used in response header 'Access-Control-Allow-Origin'

  • allowMethods - provide a string to be used in response header 'Access-Control-Allow-Methods'

  • allowHeaders - provide a string to be used in response header 'Access-Control-Allow-Headers'

  • sslKey - provide a string to be used as Key for https server, https server will be created only if both key and certificates are provided

  • sslCert - provide a string to be used as Certificate for https server

  • keyFile - provide pat for a Key file to be used for https server

  • certFile - provide pat for Certificate file to be used for https server

About the Code

The code is written in simple steps listed below:

  1. Read user input or command line argument
  2. Create HTTP Server based on passed arguments
  3. Request target server
  4. Return actual or mocked response

Now we will understand this one by one.

Process Command Line Arguments

There are lots of NPM packages for processing command line arguments like yargs, commander, etc., but to keep minimum dependency, this utility is processing command line arguments without any third party library. Node provides all command line arguments in an array that can be processed easily. For example, a command api-mock-proxy -p 8000 -t http://your.api.com will receive arguments in your program as:

JavaScript
[ 'C:\\Program Files\\nodejs\\node.exe',
  'C:\Users\admin\AppData\Roaming\npm\node_modules\api-mock-proxy',
  '-p',
  '8000',
  '-t',
  'http://your.api.com' ]

Notice the first two elements of the array, these are the path of node and, package so the argument should start from the third element of the array.

Another important part of argument processing is providing default values, so for the same lodash is used, which is a utility library for all such tasks:

JavaScript
const options = _.defaults(getOptions(myArgs), defaults);

Creating Proxy Server

After processing all the arguments, we are ready to create a Proxy server based on provided options. A user can choose either to create HTTP or HTTPS server, which can be created by using native node modules for these tasks:

JavaScript
const createServer = options.ssl ? _.curry(https.createServer)(sslOptions) : http.createServer;
const server = createServer((req, res) => { 
   // Request handling here 
}

sslOptions contains key and certificate for HTTPS server.

After creating a server, an important part is to set response headers as provided in options via CORS related headers or via --cors flag.

Request to target Server

Now, the next step is to forward the request to the target server. If a user has not opted to receive a mocked response only by using -m mock or --mode mock. Each response from the server will be stored as mocked data for future use. The response will be saved against three keys, the first is a hash of the entire request object, the second is a hash of request without header and the third is a hash of request without header and body. This way, we can get matching mocked response minimum details:

JavaScript
const fullHash = getHash(req);
const withOutHeader = getHash({ ...req, headers: "" });
const minHash = getHash({ ...req, headers: "", body: "" });

Serving Response

The actual response to any request will depend on user preference. Target server response will be forwarded after saving it for future uses if a user is running on record mode (-m record or --mode record) or response without error in mix mode (-m mix or --mode mix or avoid providing this option). A mock response will be returned if a user is running on mock mode (-m mock or --mode mock) or target server responded with an error code specified by -e 404,500,ECONNREFUSED or --errorCodes *.

To fetch mocked response from mocked data, the first step is to find a response for any of three hashed request keys created while saving request:

JavaScript
for (let i = 0; i < reqHash.length; i++) {
  const item = reqHash[i];
  const existing = data[item];

  if (existing) {
    if (existing.length == 0) {

     return existing[0].res;
    } 

   return findBestMatch(existing, reqObj);
  }
}

If it returned multiple values for hash, then it will find the best match user using epsilonjs, which is an approximate string matching library and the same will be used in the entire data if no match is found by hash:

JavaScript
const findBestMatch = (data, matchObj) => {
  const diffIndex = data.map(item => {
    return epsilon.leven(JSON.stringify(matchObj), JSON.stringify(item.req));
  });

  const minIndex = diffIndex.indexOf(Math.min(...diffIndex));
  const mock = data[Math.max(minIndex, 0)];

  return (mock || {}).res;
};

Points of Interest

  1. Creating utilities in nodejs is very simple.
  2. Add #!/usr/bin/env node as a first line in your main file (file mentioned in the main key of package.json) to make your node file executable.
  3. Node passes the first two arguments as the path of node executable and executing package/file path.

History

The next important step for this utility is to provide UI to create mock data.

For future updates, feature requests and issues, please see on GitHub. If you want to contribute, please raise a PR and/or join the conversation on git.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here