Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# fast-gateway
A super fast Node.js API Gateway for the masses!
A super fast, framework agnostic Node.js API Gateway for the masses ❤️

## Medium articles:
- https://medium.com/@kyberneees/node-js-api-gateway-a-developer-perspective-8defe575ed21
Expand Down Expand Up @@ -35,8 +35,16 @@ service.start(3000)
## Configuration options explained
```js
{
// Optional server instance. Any HTTP framework that supports the following signature is compatible:
// - server[HTTP_METHOD](pattern, [middleware1, middleware2,], handler)
//
// Known compatible frameworks: Restana, Express.js
// If omitted, restana is used as default HTTP framework
server,
// Optional restana library configuration (https://www.npmjs.com/package/restana#configuration)
// If the given value is a function instead of an object, it will be considered a restana service factory.
// If the given value is a function instead of an object, it will be considered a restana server factory.
//
// If "server" is provided, this settings are ignored.
restana: {},
// Optional global middlewares in the format: (req, res, next) => next()
// Default value: []
Expand Down
42 changes: 42 additions & 0 deletions demos/basic-express.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const gateway = require('../index')
const express = require('express')
const PORT = process.env.PORT || 8080

gateway({
server: express(),

middlewares: [
require('cors')(),
require('helmet')()
],

routes: [{
prefix: '/public',
target: 'http://localhost:3000',
docs: {
name: 'Public Service',
endpoint: 'swagger.json',
type: 'swagger'
}
}, {
prefix: '/admin',
target: 'http://localhost:3001',
middlewares: [
require('express-jwt')({
secret: 'shhhhhhared-secret'
})
]
}]
}).listen(PORT, () => {
console.log(`API Gateway listening on ${PORT} port!`)
})

const service1 = require('restana')({})
service1
.get('/hi', (req, res) => res.send('Hello World!'))
.start(3000).then(() => console.log('Public service listening on 3000 port!'))

const service2 = require('restana')({})
service2
.get('/users', (req, res) => res.send([]))
.start(3001).then(() => console.log('Admin service listening on 3001 port!'))
27 changes: 17 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
/* eslint-disable no-useless-call */

const fastProxy = require('fast-proxy')
const restana = require('restana')
const pump = require('pump')
const toArray = require('stream-to-array')
const defaultProxyHandler = (req, res, url, proxy, proxyOpts) => proxy(req, res, url, proxyOpts)
const DEFAULT_METHODS = require('restana/libs/methods')
const send = require('@polka/send-type')

const gateway = (opts) => {
opts = Object.assign({
middlewares: [],
pathRegex: '/*'
}, opts)

const server = (opts.restana instanceof Function) ? opts.restana() : restana(opts.restana || {
const server = opts.server || ((opts.restana instanceof Function) ? opts.restana() : restana(opts.restana || {
disableResponseEvent: true
})
}))

// registering global middlewares
opts.middlewares.forEach(middleware => {
Expand All @@ -26,7 +29,7 @@ const gateway = (opts) => {
docs: route.docs
}))
server.get('/services.json', (req, res) => {
res.send(services)
send(res, 200, services)
})

// processing routes
Expand All @@ -40,6 +43,9 @@ const gateway = (opts) => {
route.hooks.onRequest = route.hooks.onRequest || onRequestNoOp
route.hooks.onResponse = route.hooks.onResponse || onResponse

// populating route middlewares
route.middlewares = route.middlewares || []

// populating pathRegex if missing
route.pathRegex = undefined === route.pathRegex ? opts.pathRegex : String(route.pathRegex)

Expand All @@ -62,14 +68,14 @@ const gateway = (opts) => {
method = method.toLowerCase()

if (server[method]) {
server[method](
// path
server[method].apply(server, [
// path
route.prefix + route.pathRegex,
// route handler
handler(route, proxy, proxyHandler),
// route middlewares
route.middlewares
)
...route.middlewares,
// route handler
handler(route, proxy, proxyHandler)
])
}
})
})
Expand Down Expand Up @@ -100,7 +106,8 @@ const onResponse = async (req, res, stream) => {
res.statusCode = stream.statusCode
res.end(resBuffer)
} catch (err) {
res.send(err)
res.statusCode = 500
res.end(err.message)
}
} else {
res.statusCode = stream.statusCode
Expand Down
Loading