@jenius2/j2-gateway
This node module contains convenience utilities to make API Gateway downstream requests and parse responses.
Last updated 2 years ago by j2techlead .
UNLICENSED · Repository · Original npm · Tarball · package.json
$ cnpm install @jenius2/j2-gateway 
SYNC missed versions from official npm registry.

node-j2-gateway build status coverage report

Description

Requirements

Engine: Node 8.5.0

Table of Contents

Install

npm install @jenius2/j2-gateway

Developer Guide

This module contains utility methods to make your life easier when dealing with the downstream API Gateway.

As HAPI plugin

@jenius2/j2-gateway can AND should be used as a Hapi plugin. The regular way of using @jenius2/j2-gateway will be deprecated

Registering

Register the plugin on create server

e.g.


const { j2gateway } = require('@jenius2/j2-gateway');

const plugins = [
  { register: j2ms,
    select: ['api', 'docs'],
    options: {
      config: Config.get('/')
    }
  },
  { register: j2gateway,
    select: ['api', 'docs'],
    options: {
      config: {
        idmRequest: Config.get('/resources/idmRequest'),
        gatewayRequest: Config.get('/resources/gatewayRequest')
      }
    }
  },
  { register: healthcheck,
    select: ['api', 'docs'],
    options: {
      config: Config.get('/'),
      pkg: { dependencies }
    }
  },
  { register: helloPlugin,
    select: ['api', 'docs'],
    options: {
      config: Config.get('/'),
      http: Config.get('resources/http')
    }
  }
];

@jenius2/j2-gateway will register request compatible methods on every request lifecycle. The names of the method will follow the naming on config. In above case, the names will be idmRequest and gatewayRequest. The methods will be available in request.plugins['@jenius2/j2-gateway']

@jenius2/j2-gateway accepts regular request.defaults options plus our standard configuration. e.g:

const idmRequest = {
  secure: (env.getString('MS_IDM_PROTOCOL')) !== 'http',
  hostname: env.getString('MS_IDM_HOST'),
  port: env.getInteger('MS_IDM_PORT'),
  timeout: env.getInteger('MS_IDM_TIMEOUT'),
  resolveWithFullResponse: false,
  headers: {
    'user-agent': `${pkg.name}/${pkg.version}`
  }
};

@jenius2/j2-gateway will forward some http headers received on each request to any subsequent http calls to other services.

The headers are:

  • authorization ==> can be removed by setting removeAuthenticationHeader to true in service configuration
  • x-id-token ==> can be removed by setting removeAuthenticationHeader to true in service configuration
  • X-Reference-No ==> will be generated if not exist on retrieved request
  • X-Transmission-Date-Time ==> will be generated if not exist on retrieved request
  • accept-language

Calling the created request instances

as long as @jenius2/j2-gateway is registered earlier, the request instances will be in request.plugins['@jenius2/j2-gateway'] which means it can be passed to models. E.g.:

server.ext('onPreHandler', (req, reply) => {
  const model = new Model({
    idmRequest: req.plugins['@jenius2/j2-gateway'].idmRequest,
    gatewayRequest: req.plugins['@jenius2/j2-gateway'].gatewayRequest,
    logger
  });

  // Assign this model to the request app property for access at run time route handlers
  // https://hapijs.com/api#request.app
  Object.assign(req.app, { model });
  reply.continue();
});

Enabling logger

@jenius2/j2-gateway can be made to log all request and response made by them by setting enableLogging to true in opts while Registering

e.g:

{ register: j2gateway,
  select: ['api', 'docs'],
  options: {
    enableLogging: Config.get('/logExternalRequests'),
    config: {
      idmRequest: Config.get('/resources/idmRequest'),
      gatewayRequest: Config.get('/resources/gatewayRequest')
    }
  }
},

see https://github.com/request/request-debug for further info.

Two additional log events are generated. Note that they follow the same structure as the messages in j2-logger wherever possible.

outgoing.request - Outgoing request, within a request:

{
  "name": "microservice-seed-logger",
  "hostname": "seed-ms-node-45-tf1sm",
  "pid": 1,
  "level": 20,
  "event": "outgoing.request",
  "id": "99999999-df3b-490d-82b6-eb2b85b9cfc9",
  "method": "get",
  "path": "https://appapisit01.dev.corp.btpn.co.id:19502/v1/users/123/accounts/infoandbalance",
  "headers": {
    "X-Request-ID": "99999999-df3b-490d-82b6-eb2b85b9cfc9",
    "X-Reference-No": "381326684761",
    "X-Transmission-Date-Time": "2018-02-13T16:32:20.966Z",
    "accept-language": "en-GB,en;q=0.9",
    "X-Node": "DCB",
    "X-Channel-ID": 6017,
    "host": "appapisit01.dev.corp.btpn.co.id:19502",
    "accept": "application/json"
  },
  "msg": "Request: GET https://appapisit01.dev.corp.btpn.co.id:19502/v1/users/123/accounts/infoandbalance",
  "time": "2018-02-13T16:32:20.969Z",
  "v": 0
}

outgoing.response - Incoming response, within a request:

{
  "name": "microservice-seed-logger",
  "hostname": "seed-ms-node-45-tf1sm",
  "pid": 1,
  "level": 20,
  "event": "outgoing.response",
  "id": "99999999-df3b-490d-82b6-eb2b85b9cfc9",
  "statusCode": 400,
  "headers": {
    "max-forwards": "19",
    "via": "1.0 APPAPISIT01 (), 1.0 APPAPISIT01 ()",
    "connection": "close",
    "x-correlationid": "Id-1413835a28c690378d275c64 0; Id-1413835a0fe87315d18b4093 0",
    "btpn-responsecode": "96",
    "btpn-responsedesc": "10||does not exist on the database-123",
    "date": "Tue, 13 Feb 2018 16:32:20 GMT",
    "x-reference-no": "381326684761",
    "content-type": "application/json"
  },
  "body": {
    "responseCode": "96",
    "responseDesc": "10||does not exist on the database-123 "
  },
  "msg": "Response: 400",
  "time": "2018-02-13T16:32:21.227Z",
  "v": 0
}

Making Requests as regular npm module (DEPRECATED)

A method is included to make a request to a downstream system, adding the necessary headers at request time.

e.g.

const { request, utils: { formatBaseUrl } } = require('@jenius2/j2-gateway');

// Creates an instance of api gateway request with default params
const apiGatewayRequest = request({
  baseUrl: formatBaseUrl(CONFIG)
});

// Takes default `request` parameters to make request
apiGatewayRequest({
  method: 'GET'
  url: '/accounts'
})
.then(response => {
  // Will return all responses (including non-2xx status codes)
})
.catch(err => {
  // Will return network errors / timeouts etc
})

Parsing API Gateway responses

Given the quirkiness of Gateway responses being in both 2xx and non 2xx status codes, we should rely on the responseCode when determining the status of the response. A convenience method has been created to parse the response with expected responseCode's (also found in constants.js) and will resolve with the body of the response. If an unexpected responseCode is returned we throw a DownstreamError which also contains reference to the response for logging and debugging purposes.

e.g.

const { request, parse, constants: { RESPONSE_CODES } } = require('@jenius2/j2-gateway');

// Creates an instance of api gateway request with default params
const apiGatewayRequest = request({
  baseUrl: 'http://apigateway.com/'
});

// Takes default `request` parameters to make request
apiGatewayRequest({
  method: 'GET'
  url: '/accounts'
})
.then(response => parse(response, [RESPONSE_CODES.SUCCESS]))
.then({ result } => {
  // Do something with my response
  // Anything other than a `00` will throw a DownstreamError
})

Authenticating with the Gateway

Some services (those which call privileged APIs) will need to first authenticate with the API gateway, using a Client ID and Secret. This essentially follows an OAuth flow, where a short lived token is requested.

This flow is documented at: https://jenius.atlassian.net/wiki/spaces/IN/pages/138118540/Internal+API+Gateway

The library contains two helpers for this. The first is a basic 'one shot' auth flow:

const { auth } = require('@jenius2/j2-gateway');

const clientId = 'jenius';
const clientSecret = 'shh';
const host = 'https://APPAPISIT02.dev.corp.btpn.co.id:8089';

auth.auth({ clientId, clientSecret, host })
.then({ accessToken, expiresIn } => { /* ... */ });

The other option is to use the stateful gateway function:

const { auth } = require('@jenius2/j2-gateway');

const clientId = 'jenius';
const clientSecret = 'shh';
const host = 'https://APPAPISIT02.dev.corp.btpn.co.id:8089';

const gateway = auth.gateway({ clientId, clientSecret, host });

gateway.auth()
.then(accessToken => { /* ... */ });

The stateful function caches credentials and handles token expiry, automatically re-authenticating for a new token as needed.

A simple example of the auth code is in ./test/auth.js.

Migration

If migrating to Node 8.5.0, please ensure you've done the following:

  1. Update Node version in package.json – engine – to >=8.5.0
  2. Follow the latest configuration from the seed to ensure you've gotten rid of Backpack and Babel. Similarly, there are no build or compile steps, and there is also no dist or build target. We use src/main.js as the main entry point to our modules.

What's Included?

Current Tags

  • 4.2.0-0                                ...           beta (2 years ago)
  • 4.6.3                                ...           latest (2 years ago)
  • 4.2.0-alpha.2                                ...           prerelease (2 years ago)

32 Versions

  • 4.6.3                                ...           2 years ago
  • 4.6.2                                ...           2 years ago
  • 4.6.1                                ...           2 years ago
  • 4.6.0                                ...           2 years ago
  • 4.5.0                                ...           2 years ago
  • 4.4.1                                ...           2 years ago
  • 4.4.0                                ...           2 years ago
  • 4.3.1                                ...           2 years ago
  • 4.3.0                                ...           2 years ago
  • 4.2.1                                ...           2 years ago
  • 4.2.0                                ...           2 years ago
  • 4.2.0-alpha.2                                ...           2 years ago
  • 4.2.0-alpha.1                                ...           2 years ago
  • 4.2.0-alpha.0                                ...           2 years ago
  • 4.2.0-0                                ...           2 years ago
  • 4.1.3                                ...           2 years ago
  • 4.1.2                                ...           2 years ago
  • 4.1.1                                ...           2 years ago
  • 4.1.0                                ...           2 years ago
  • 4.0.0                                ...           2 years ago
  • 3.1.0-1                                ...           2 years ago
  • 3.1.0-0                                ...           2 years ago
  • 3.0.0                                ...           2 years ago
  • 2.3.2                                ...           2 years ago
  • 2.3.1                                ...           2 years ago
  • 2.3.0                                ...           2 years ago
  • 2.2.0                                ...           2 years ago
  • 2.1.0                                ...           3 years ago
  • 2.0.0                                ...           3 years ago
  • 1.1.0                                ...           3 years ago
  • 1.0.3                                ...           3 years ago
  • 1.0.2                                ...           3 years ago

Copyright 2014 - 2017 © taobao.org |