fast-gateway
A super fast Node.js API Gateway for the masses!
Medium articles:
Install
npm i fast-gateway
Usage
Gateway
const gateway = require('fast-gateway')
const server = gateway({
routes: [{
prefix: '/service',
target: 'http://127.0.0.1:3000'
}]
})
server.start(8080)
Remote Service
const service = require('restana')()
service.get('/get', (req, res) => res.send('Hello World!'))
service.start(3000)
Configuration options explained
{
restana: {},
middlewares: [],
pathRegex: '/*',
routes: [{
fastProxy: {},
http2: false,
pathRegex: '/*',
prefix: '/public',
docs: {
name: 'Public Service',
endpoint: '/api-docs',
type: 'swagger'
},
prefixRewrite: '',
target: 'http://localhost:3000',
methods: ['GET', 'POST', ...],
middlewares: [],
hooks: {
async onRequest (req, res) {
},
onResponse (req, res, stream) {
}
}
}]
}
onResponse Hook default implementation
For developers reference, next we describe how the default onResponse
hook looks like:
const pump = require('pump')
const toArray = require('stream-to-array')
const onResponse = async (req, res, stream) => {
if (!res.hasHeader('content-length')) {
try {
const resBuffer = Buffer.concat(await toArray(stream))
res.statusCode = stream.statusCode
res.setHeader('content-length', '' + Buffer.byteLength(resBuffer))
res.end(resBuffer)
} catch (err) {
res.send(err)
}
} else {
res.statusCode = stream.statusCode
pump(stream, res)
}
}
The "GET /services.json" endpoint
Since version 1.3.5
the gateway exposes minimal documentation about registered services at: GET /services.json
Example output:
[
{
"prefix":"/public",
"docs":{
"name":"Public Service",
"endpoint":"/swagger.json",
"type":"swagger"
}
},
{
"prefix":"/admin"
}
]
NOTE: Please see docs
configuration entry explained above.
Gateway level caching
Caching support is provided by the http-cache-middleware
module. https://www.npmjs.com/package/http-cache-middleware
Why?
Because caching
is the last mile for low latency distributed systems!
Enabling proper caching strategies at gateway level will drastically reduce the latency of your system,
as it reduces network round-trips and remote services processing.
We are talking here about improvements in response times from X ms
to ~2ms
, as an example.
We use the http-cache-middleware
module to support gateway level caching. Read more about it: https://github.com/jkyberneees/http-cache-middleware
Setting up gateway level cache available for all services
Single node cache (memory):
const cache = require('http-cache-middleware')()
const gateway = require('fast-gateway')
const server = gateway({
middlewares: [cache],
routes: [...]
})
Memory storage is recommended if there is only one gateway instance and you are not afraid of losing cache data.
Multi nodes cache (redis):
const CacheManager = require('cache-manager')
const redisStore = require('cache-manager-ioredis')
const redisCache = CacheManager.caching({
store: redisStore,
db: 0,
host: 'localhost',
port: 6379,
ttl: 30
})
const cache = require('http-cache-middleware')({
stores: [redisCache]
})
const gateway = require('fast-gateway')
const server = gateway({
middlewares: [cache],
routes: [...]
})
Required if there are more than one gateway instances
How to cache remote services endpoints response?
https://github.com/jkyberneees/http-cache-middleware#enabling-cache-for-service-endpoints
How to invalidate caches?
https://github.com/jkyberneees/http-cache-middleware#invalidating-caches
Custom cache keys
Cache keys are generated using: req.method + req.url
, however, for indexing/segmenting requirements it makes sense to allow cache keys extensions.
Unfortunately, this feature can't be implemented at remote service level, because the gateway needs to know the entire lookup key when a request
reaches the gateway.
For doing this, we simply recommend using middlewares on the service configuration:
routes: [{
prefix: '/users',
target: 'http://localhost:3000',
middlewares: [(req, res, next) => {
req.cacheAppendKey = (req) => req.user.id
return next()
}]
}]
In this example we also distinguish cache entries by user.id
, very common case!
Disable cache for custom endpoints
You can also disable cache checks for certain requests programmatically:
routes: [{
prefix: '/users',
target: 'http://localhost:3000',
middlewares: [(req, res, next) => {
req.cacheDisabled = true
return next()
}]
}]
Want to contribute?
This is your repo ;)
Note: We aim to be 100% code coverage, please consider it on your pull requests.
Related projects
Benchmarks
Benchmark scripts can be found in benchmark folder.
Laptop: MacBook Pro 2016, 2,7 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3
wrk -t8 -c50 -d20s http://127.0.0.1:8080/service/get
- fast-gateway: 18069.77 reqs/secs
- k-fastify-gateway: 9763.61 reqs/secs