serverless-docker
Version:
This is a proof of concept to see if we can replicate Amazon API Gateway using docker images to run lambda
111 lines (80 loc) • 2.98 kB
JavaScript
const BbPromise = require('bluebird')
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const morgan = require('morgan')
const lambdaLocal = require('./invoke/local')
const lambdaRemote = require('./invoke/remote')
const authorizer = require('./authorizer/middleware')
const integration = require('./integration/middleware')
const OPTIONS = 'OPTIONS'
const noOp = () => (undefined)
const messageTemplate = (endpoint) => {
const http = endpoint.http
const method = `[${http.method.toUpperCase()} ${http.path}]`
const authorizerName = http.authorizer
? ` => λ:${http.authorizer.name}`
: ''
const functionName = ` => λ:${endpoint.functionName}`
return `${method}${authorizerName}${functionName}`
}
const configureLogger = (logger) => (req, res, next) => {
req.logger = logger // eslint-disable-line no-param-reassign
next()
}
const createContext = (endpoints) => (req, res, next) => {
const endpoint = endpoints
.filter(e =>
e.http.method.toUpperCase() === req.method ||
(e.http.cors && req.method === OPTIONS)
)
.find(e => e.http.path === req.url)
if (!endpoint) {
// this is what API Gateway does
req.logger('HTTP Event Not Found: Try checking your serverless.yml')
res.status(403)
res.json({ message: 'Forbidden' })
res.send()
return
}
req.context = endpoint // eslint-disable-line no-param-reassign
next()
}
const start = (endpoints, port, lambdaPort, logger) => {
const log = logger || noOp
// When simulating API Gateway use remove lambda if available otherwise local
const lambda = lambdaPort ? lambdaRemote(`http://localhost:${lambdaPort}`) : lambdaLocal()
const server = express()
server.use(configureLogger(log))
server.use(morgan('dev'))
server.use(bodyParser.json())
server.use(bodyParser.urlencoded({ extended: true }))
server.use(createContext(endpoints))
server.use(authorizer(lambda))
endpoints.forEach(endpoint => {
log(messageTemplate(endpoint))
const http = endpoint.http
const middleware = []
if (http.cors) {
const corsConfig = http.cors
// eslint-disable-next-line max-len
log(`[OPTIONS ${http.path}] => CORS origin: ${corsConfig.origins} methods: ${corsConfig.methods}`)
const corsOptions = {
origin: corsConfig.origins.length === 1 ? corsConfig.origins[0] : corsConfig.origins,
methods: corsConfig.methods,
credentials: corsConfig.allowCredentials || undefined,
allowedHeaders: corsConfig.headers,
optionsSuccessStatus: 200,
}
middleware.push(cors(corsOptions))
server.options(http.path, cors(corsOptions))
}
server[http.method.toLowerCase()](http.path, middleware, integration(lambda))
})
log(`Invoke URL: http://localhost:${port}`)
return BbPromise.fromCallback(callback => server.listen(port, callback))
}
module.exports = {
start,
}