UNPKG

@bbc/http-transport

Version:

A flexible, modular REST client built for ease-of-use and resilience.

464 lines (411 loc) 13 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>client.js - Documentation</title> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger" /> <label for="nav-trigger" class="navicon-button x"> <div class="navicon"></div> </label> <label for="nav-trigger" class="overlay"></label> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="HttpTransportBuilder.html">HttpTransportBuilder</a><ul class='methods'><li data-type='method'><a href="HttpTransportBuilder.html#createClient">createClient</a></li><li data-type='method'><a href="HttpTransportBuilder.html#retries">retries</a></li><li data-type='method'><a href="HttpTransportBuilder.html#retryDelay">retryDelay</a></li><li data-type='method'><a href="HttpTransportBuilder.html#use">use</a></li><li data-type='method'><a href="HttpTransportBuilder.html#userAgent">userAgent</a></li></ul></li><li><a href="HttpTransportClient.html">HttpTransportClient</a><ul class='methods'><li data-type='method'><a href="HttpTransportClient.html#asBody">asBody</a></li><li data-type='method'><a href="HttpTransportClient.html#asResponse">asResponse</a></li><li data-type='method'><a href="HttpTransportClient.html#delete">delete</a></li><li data-type='method'><a href="HttpTransportClient.html#get">get</a></li><li data-type='method'><a href="HttpTransportClient.html#head">head</a></li><li data-type='method'><a href="HttpTransportClient.html#headers">headers</a></li><li data-type='method'><a href="HttpTransportClient.html#patch">patch</a></li><li data-type='method'><a href="HttpTransportClient.html#post">post</a></li><li data-type='method'><a href="HttpTransportClient.html#put">put</a></li><li data-type='method'><a href="HttpTransportClient.html#query">query</a></li><li data-type='method'><a href="HttpTransportClient.html#redirect">redirect</a></li><li data-type='method'><a href="HttpTransportClient.html#retry">retry</a></li><li data-type='method'><a href="HttpTransportClient.html#retryDelay">retryDelay</a></li><li data-type='method'><a href="HttpTransportClient.html#timeout">timeout</a></li><li data-type='method'><a href="HttpTransportClient.html#use">use</a></li></ul></li></ul> </nav> <div id="main"> <h1 class="page-title">client.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>'use strict'; const compose = require('koa-compose'); const context = require('./context'); const rejectedPromise = require('./rejectedPromise'); const bind = require('./bind'); /** Core client */ class HttpTransportClient { /** * Create a HttpTransport. * @param {Transport} transport - Transport instance. * @param {object} defaults - default configuration */ constructor(transport, defaults) { this._transport = transport; this._instancePlugins = defaults.plugins || []; this._defaults = defaults; this._initContext(); bind(this); } /** * Registers a per request plugin * * @return a HttpTransport instance * @param {function} fn - per request plugin * @example * const toError = require('@bbc/http-transport-to-error'); * const httpTransport = require('@bbc/http-transport'); * * httpTransport.createClient() * .use(toError(404)); */ use(plugin) { validatePlugin(plugin); this._ctx.addPlugin(plugin); return this; } /** * Make a HTTP GET request * * @param {string} baseUrl * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .get(url) * .asResponse(); */ get(baseUrl) { this._ctx.req.method('GET').baseUrl(baseUrl); return this; } /** * Make a HTTP POST request * * @param {string} baseUrl * @param {object} request body * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .post(baseUrl, requestBody) * .asResponse(); */ post(baseUrl, body) { this._ctx.req .method('POST') .body(body) .baseUrl(baseUrl); return this; } /** * Make a HTTP PUT request * * @param {string} baseUrl * @param {object} request body * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .put(baseUrl, requestBody) * .asResponse(); */ put(baseUrl, body) { this._ctx.req .method('PUT') .body(body) .baseUrl(baseUrl); return this; } /** * Make a HTTP DELETE request * * @param {string} baseUrl * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .delete(baseUrl) * .asResponse(); */ delete(baseUrl) { this._ctx.req.method('DELETE').baseUrl(baseUrl); return this; } /** * Make a HTTP PATCH request * * @param {string} baseUrl * @param {object} request body * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .put(baseUrl, requestBody) * .asResponse(); */ patch(baseUrl, body) { this._ctx.req .method('PATCH') .body(body) .baseUrl(baseUrl); return this; } /** * Make a HTTP HEAD request * * @param {string} baseUrl * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .head(baseUrl) * .asResponse(); */ head(baseUrl) { this._ctx.req.method('HEAD').baseUrl(baseUrl); return this; } /** * Sets the request headers * * @param {string|object} name - header name or headers object * @param {string|object} value - header value * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .headers({ * 'User-Agent' : 'someUserAgent' * }) * .asResponse(); */ headers() { const args = normalise(arguments); Object.keys(args).forEach((key) => { this._ctx.req.addHeader(key, args[key]); }); return this; } /** * Sets the query strings * * @param {string|object} name - query name or query object * @param {string|object} value - query value * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .query({ * 'perPage' : 1 * }) * .asResponse(); */ query() { const args = normalise(arguments); Object.keys(args).forEach((key) => { this._ctx.req.addQuery(key, args[key]); }); return this; } /** * Sets a request timeout * * @param {integer} time - timeout in seconds * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .timeout(1) * .asResponse(); */ timeout(time) { this._ctx.req.timeout(time); return this; } /** * Set the redirect handling: * `follow` (default) to follow the redirects automatically, * `manual` to extract redirect headers, * `error` to reject redirect * * @param {'follow'|'manual'|'error'} redirect - redirect handling * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .redirect('manual') // for this request only * .asResponse(); */ redirect(redirectType) { this._ctx.req.redirect(redirectType); return this; } /** * Set the number of retries on failure for the request * * @param {integer} retries - number of times to retry a failed request * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .retry(5) // for this request only * .asResponse(); */ retry(retries) { this._ctx.retries = retries; return this; } /** * Set the delay between retries in ms * * @param {integer} delay - number of ms to wait between retries (default: 100) * @return a HttpTransport instance * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .retry(2) * .retryDelay(200) * .asResponse(); */ retryDelay(delay) { this._ctx.retryDelay = delay; return this; } /** * Initiates the request, returning the response body, if successful. * * @return a Promise. If the Promise fulfils, * the fulfilment value is the response body. The body type defaults to string. * If the content-type response header contains 'json' * or the json: true option has been set on transport layer * then the body type will be json. * * @example * const httpTransport = require('@bbc/http-transport'); * * const body = await httpTransport.createClient() * .asBody(); * * console.log(body); */ async asBody() { const res = await this.asResponse(); return res.body; } /** * Initiates the request, returning a http transport response object, if successful. * * @return a Promise. If the Promise fulfils, * the fulfilment value is response object. * @example * const httpTransport = require('@bbc/http-transport'); * * const response = await httpTransport.createClient() * .asResponse() * * console.log(response); * */ async asResponse() { const currentContext = this._ctx; this._initContext(); const ctx = await retry(this._executeRequest, currentContext); return ctx.res; } _getPlugins(ctx) { return this._instancePlugins.concat(ctx.plugins); } _applyPlugins(ctx, next) { const fn = compose(this._getPlugins(ctx)); return fn(ctx, next); } async _executeRequest(ctx) { await this._applyPlugins(ctx, this._handleRequest); return ctx; } async _handleRequest(ctx, next) { await this._transport.execute(ctx); return next(); } _initContext() { this._ctx = context.create(this._defaults); this.headers('User-Agent', this._ctx.userAgent); } } function isCriticalError(err) { if (err &amp;&amp; err.statusCode &lt; 500) { return false; } return true; } function toRetry(err) { return { reason: err.message, statusCode: err.statusCode }; } function retry(fn, ctx) { ctx.retryAttempts = []; const maxAttempts = ctx.retries; function attempt(i) { return fn(ctx) .catch((err) => { if (maxAttempts > 0) { const delayBy = rejectedPromise(ctx.retryDelay); return delayBy(err); } throw err; }) .catch((err) => { if (i &lt; maxAttempts &amp;&amp; isCriticalError(err)) { ctx.retryAttempts.push(toRetry(err)); return attempt(++i); } throw err; }); } return attempt(0); } function toObject(arr) { const obj = {}; for (let i = 0; i &lt; arr.length; i += 2) { obj[arr[i]] = arr[i + 1]; } return obj; } function isObject(value) { return value !== null &amp;&amp; typeof value === 'object'; } function normalise(args) { args = Array.from(args); if (isObject(args[0])) { return args[0]; } return toObject(args); } function validatePlugin(plugin) { if (typeof plugin !== 'function') throw new TypeError('Plugin is not a function'); } module.exports = HttpTransportClient; </code></pre> </article> </section> </div> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a> on Mon Feb 19 2024 16:02:59 GMT+0100 (Central European Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. </footer> <script>prettyPrint();</script> <script src="scripts/linenumber.js"></script> </body> </html>