REST API Performance. Test APIs from the perspective of both a Mobile phone and a Node server
Switch branches/tags
Nothing to show
Clone or download
Latest commit 98a50a3 May 10, 2018
Permalink
Failed to load latest commit information.
example clean up read me Aug 31, 2017
src refactor api perf testing to fix bug with inconsistant timings Aug 31, 2017
.gitignore Initial commit Jul 18, 2017
.nvmrc fix all the proxy references Aug 31, 2017
LICENSE Initial commit Jul 18, 2017
README.md Update README.md May 10, 2018
package-lock.json 2.1.0 Aug 31, 2017
package.json 2.1.0 Aug 31, 2017

README.md

RAPIP

[ra-peep] REST API Performance. Test APIs from the perspective of both a Mobile phone and a Node server.

This module will help you collect performance metrics of any REST API, giving you to not just the response time but how long it will take to parse, size and any compression used (currently only supporting gzip).

RAPIP uses Async/Await so needs Node 8 and Chrome 55

Set up

npm install --save RAPIP

Usage

const { server, client } = require('rapip');

Reference

client(api, headers, emulator, headless, url)

Start a mobile client performance audit, it uses the Lighthouse Nexus 5 emulator (https://github.com/GoogleChrome/lighthouse/blob/63b4ac14d0a871ade0630db2885edd7848843243/lighthouse-core/lib/emulation.js).

You will get results for both an XHR and Fetch request.

Parameters
  • api - Required. String url of the api you want to benchmark.
  • headers - Object of request headers you want to add to the api call.
  • emulation - Object for the emulation configuration.
    • cpuThrottling - Boolean for toggling CPU throttling (Default: true).
    • networkThrottling - Boolean for toggling Network throttling (Default: true).
  • headless - Boolean for toggling Chrome headless (Default: true).
  • url - String for the URL to run the framework (Default: "http://localhost:3000").
Response
{
  response: {
    api: 'https://httpbin.org/user-agent'
    emulation: {
      deviceEmulation: 'Nexus 5X',
      cpuThrottling: '4x slowdown',
      networkThrottling: '562.5ms RTT, 1.4Mbps down, 0.7Mbps up',
      userAgent: 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36(KHTML, like Gecko) Chrome/61.0.3116.0 Mobile Safari/537.36'
    },
    gzipEnabled: false,
    size: {
      raw: 0.08,
      message: '0.08kb',
      // if the api returned content length
      // if not RAPIP will give you an estimate
      'content-length': true
    },
    fetch: {
      name: 'Fetch',
      request: { raw: 448, message: '448ms' },
      parse: { raw: 4, message: '4ms' }
    },
    xhr: {
      name: 'XHR',
      request: { raw: 135, message: '135ms' },
      parse: { raw: 0, message: '0ms' }
    }
  }
}
  • api - api called.
  • emulation - Metadata about the emulator the test was run on.
  • gzipEnabled - If the code is encoded.
  • fetch - Request and parse metrics for a fetch request.
  • xhr - Request and parse metrics for a xhr request.

server(api, headers)

Start a server performance audit.

Parameters
  • api - Required. String url of the api you want to benchmark.
  • headers - Object of request headers you want to add to the api call.
Response
{ response: {
    request: { raw: '462', message: '462ms' },
    parse: { raw: '1', message: '1ms' },
    responseSize: { raw: '0.08', message: '0.08kb' },
    stringify: { raw: '8', message: '8ms' },
    gzipEnabled: false,
    api: 'https://httpbin.org/user-agent'
  }
}
  • request - How long in milliseconds the fetch request took.
  • parse - How long in milliseconds it took to parse the data.
  • responseSize - How large the response was in Kilobytes.
  • stringify - How long in milliseconds it took to stringify the parsed the data (can be interesting for serializing data for universial apps).
  • gzipEnabled - If the code is encoded.
  • api - api called.

Clientside framework

If you want to use the clientside performance framework you can use the command:

  npm start

Performance benchmarking

This will start a local instance of the framework which you can view in your browser with the url:

  # Default
  http://localhost:3000

You can then trigger a performance audit in the console but running the command:

performanceDemo()

This will console log the response of a demo request to: https://httpbin.org/user-agent with both Fetch and XHR.

If you want to try your own API call within the framework you can use either performanceTestApiWithFetch() or performanceTestApiWithXHR(). Both use the same interface:

performanceTestApiWithFetch(api, headers);
performanceTestApiWithXHR(api, headers);
  • api - Required. String url of the api you want to benchmark.
  • headers - Object of request headers you want to add to the api call.

Proxying API calls.

If you are performance testing an API from the perspective of a mobile phone you are constrained by the browser sandbox. If the API doesn't include CORS headers you will not be able to call it from your tests.

However to help this the client framework provides a (hopefully) transparent proxy. You can use it in the following way:

const { client } = require('rapip');

const PROXY = 'https://localhost:3000/api';
const API = 'https://httpbin.org/user-agent';
const HEADERS = {
  'x-rapip-api': API,
  'x-rapip-headers': "{'custom-headers':'wft'}",
}

async function runPerformanceTest() {
  const results = await client.performanceTestApi(PROXY, HEADERS);
  console.log(results);
  process.exit(0);
}

client.framework.listen(3000, () => {
  console.log('Listening on port 3000!');
  runPerformanceTest();
});

The call will now goto the proxy service and make a request to the URL set in the header x-rapip-api.

If you want the Proxy to forward on headers to the API, you can do this by giving the header x-rapip-headers a stringified JSON object.

The proxy should be completely transparent and any over headers it might have are removed from the request time. However if you do use the proxy your performance audit will include a proxy property which will include metadata about any processing time taken.

Response
{
  response: {
    api: 'https://httpbin.org/user-agent'
    emulation: {
      deviceEmulation: 'Nexus 5X',
      cpuThrottling: '4x slowdown',
      networkThrottling: '562.5ms RTT, 1.4Mbps down, 0.7Mbps up',
      userAgent: 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36(KHTML, like Gecko) Chrome/61.0.3116.0 Mobile Safari/537.36'
    },
    gzipEnabled: false,
    size: {
      raw: 0.08,
      message: '0.08kb',
      'content-length': true
    },
    fetch: {
      name: 'Fetch',
      request: { raw: 448, message: '448ms' },
      parse: { raw: 4, message: '4ms' },
      proxy: {
        requestTime : { raw: 445, message: '445ms' },
        proxyOverhead: { raw: 3, message: '3ms' },
        requestTimeWithCorrection: { raw: 448, message: '448ms' }
      }
    },
    xhr: {
      name: 'XHR',
      request: { raw: 135, message: '135ms' },
      parse: { raw: 0, message: '0ms' },
      proxy: {
        requestTime : { raw: 445, message: '445ms' },
        proxyOverhead: { raw: 3, message: '3ms' },
        requestTimeWithCorrection: { raw: 448, message: '448ms' }
      }
    }
  }
}

Examples

You can configure both server and clientside runners.

Clientside

With CORS example

Performance test API with CORS from a mobile device.

const { client } = require('rapip');

const API = 'https://httpbin.org/user-agent';

async function runPerformanceTest() {
  const results = await client.performanceTestApi(API);
  console.log(results);
  process.exit(0);
}

client.framework.listen(3000, () => {
  console.log('Listening on port 3000!');
  runPerformanceTest();
});

You can try this example with the command:

  npm run example:client

Without CORS example

If you want to Performance test API without CORS RAPIP offers a proxy that will add them for you.

const { client } = require('rapip');

const PROXY = 'https://localhost:3000/api';
const API = 'https://httpbin.org/user-agent';
const HEADERS = {
  'x-rapip-api': API
}

async function runPerformanceTest() {
  const results = await client.performanceTestApi(PROXY, HEADERS);
  console.log(results.response.fetch);
  process.exit(0);
}

client.framework.listen(3000, () => {
  console.log('Listening on port 3000!');
  runPerformanceTest();
});

You can try this example with the command:

  npm run example:client:proxy

Server

Performance test API on the server side.

const { server } = require('rapip');

const API = 'https://httpbin.org/user-agent';

async function getPerformanceMetrics() {
  const results = await server(`${API}`);
  console.log(results);
  process.exit(0);
}

getPerformanceMetrics();

You can try this example with the command:

  npm run example:server

TODO

  • update to use puppeter over CDP
  • add build and deploy steps
  • Clean the code
  • Add some tests
  • Make the code isomorphic
  • Move to use imports
  • Add more than gZip compression