Add middleware abstraction

This commit is contained in:
Jerko Steiner 2019-09-25 11:15:04 +07:00
parent 42bda32985
commit 00192d2f3b
14 changed files with 161 additions and 2 deletions

View File

@ -19,7 +19,8 @@
"@rondo.dev/test-utils": "file:packages/test-utils",
"@rondo.dev/validator": "file:packages/validator",
"@rondo.dev/db": "file:packages/db",
"@rondo.dev/db-typeorm": "file:packages/db-typeorm"
"@rondo.dev/db-typeorm": "file:packages/db-typeorm",
"@rondo.dev/middleware": "file:packages/middleware"
},
"devDependencies": {
"@types/bcrypt": "^3.0.0",
@ -104,4 +105,4 @@
"watchify": "^3.11.1"
},
"name": "node"
}
}

View File

@ -0,0 +1,7 @@
# @rondo.dev/middleware
This package provides a framework-agnostic way to define middlewares for any
framework by using the Node's `http.IncomingMessage` and `http.ServerResponse`
types.
See tests for more information.

View File

@ -0,0 +1,16 @@
module.exports = {
roots: [
'<rootDir>/src',
],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
testRegex: '(/__tests__/.*|\\.(test|spec))\\.tsx?$',
moduleFileExtensions: [
'ts',
'tsx',
'js',
'jsx',
],
setupFiles: ['<rootDir>/jest.setup.js'],
}

View File

@ -0,0 +1,4 @@
if (!process.env.LOG) {
process.env.LOG = 'sql:warn'
}
process.chdir(__dirname)

4
packages/middleware/package-lock.json generated Normal file
View File

@ -0,0 +1,4 @@
{
"name": "@rondo.dev/middleware",
"lockfileVersion": 1
}

View File

@ -0,0 +1,14 @@
{
"name": "@rondo.dev/middleware",
"private": true,
"scripts": {
"test": "jest",
"lint": "tslint --project .",
"compile": "tsc",
"clean": "rm -rf lib/"
},
"dependencies": {},
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts"
}

View File

@ -0,0 +1,6 @@
import { IncomingMessage, ServerResponse } from 'http'
export type Context = {
req: IncomingMessage
res: ServerResponse
}

View File

@ -0,0 +1,3 @@
import { Context } from './Context'
export type Middleware = <C extends Context>(ctx: C) => unknown

View File

@ -0,0 +1,7 @@
import { Context } from './Context'
export const createMiddleware =
<C extends Context = Context>(fn: (ctx: C) => unknown) => async (ctx: C) => {
await fn(ctx)
return undefined
}

View File

@ -0,0 +1,49 @@
import express from 'express'
import { expressify } from './expressify'
import request from 'supertest'
import { createMiddleware } from './createMiddleware'
describe('expressify', () => {
describe('middleware', () => {
it('acts as a middleware when returned value is undefined', async () => {
const app = express()
app.use(
expressify(
createMiddleware(ctx => (ctx.req as any).id = 'test')))
app.get('/test', (req, res) => res.json({ id: (req as any).id }))
await request(app)
.get('/test')
.expect(200)
.expect('{"id":"test"}')
})
})
describe('response', () => {
it('sends a response', async () => {
const app = express()
app.use(
expressify(
createMiddleware(ctx => (ctx.req as any).id = 'test')))
app.get('/test', expressify(ctx => (ctx.req as any).id))
request(app)
.get('/test')
.expect(200)
.expect('"test"')
})
it('can send a response using a custom fn', () => {
const app = express()
app.use(
expressify(
createMiddleware(ctx => (ctx.req as any).id = 'test')))
app.get('/test',
expressify(ctx => (ctx.req as any).id, (res, value) => res.send(value)))
request(app)
.get('/test')
.expect(200)
.expect('test')
})
})
})

View File

@ -0,0 +1,28 @@
import { NextFunction, Request, Response } from 'express'
import { IncomingMessage, ServerResponse } from 'http'
import { Middleware } from './Middleware'
export const expressify = (
handleMiddleware: Middleware,
sendResponse: (res: Response, result: unknown) => void =
(res, result) => res.json(result),
) => async (
req: Request,
res: Response,
next: NextFunction,
) => {
let result: unknown
try {
const r: IncomingMessage = req
const rr: ServerResponse = res
result = await handleMiddleware({req: r, res: rr})
} catch (err) {
next(err)
return
}
if (result === undefined) {
next()
return
}
sendResponse(res, result)
}

View File

@ -0,0 +1,3 @@
export * from './Context'
export * from './expressify'
export * from './Middleware'

View File

@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "esm"
},
"references": [
]
}

View File

@ -0,0 +1,9 @@
{
"extends": "../tsconfig.common.json",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"references": [
]
}