Add middleware abstraction
This commit is contained in:
parent
42bda32985
commit
00192d2f3b
@ -19,7 +19,8 @@
|
|||||||
"@rondo.dev/test-utils": "file:packages/test-utils",
|
"@rondo.dev/test-utils": "file:packages/test-utils",
|
||||||
"@rondo.dev/validator": "file:packages/validator",
|
"@rondo.dev/validator": "file:packages/validator",
|
||||||
"@rondo.dev/db": "file:packages/db",
|
"@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": {
|
"devDependencies": {
|
||||||
"@types/bcrypt": "^3.0.0",
|
"@types/bcrypt": "^3.0.0",
|
||||||
@ -104,4 +105,4 @@
|
|||||||
"watchify": "^3.11.1"
|
"watchify": "^3.11.1"
|
||||||
},
|
},
|
||||||
"name": "node"
|
"name": "node"
|
||||||
}
|
}
|
||||||
7
packages/middleware/README.md
Normal file
7
packages/middleware/README.md
Normal 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.
|
||||||
16
packages/middleware/jest.config.js
Normal file
16
packages/middleware/jest.config.js
Normal 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'],
|
||||||
|
}
|
||||||
4
packages/middleware/jest.setup.js
Normal file
4
packages/middleware/jest.setup.js
Normal 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
4
packages/middleware/package-lock.json
generated
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "@rondo.dev/middleware",
|
||||||
|
"lockfileVersion": 1
|
||||||
|
}
|
||||||
14
packages/middleware/package.json
Normal file
14
packages/middleware/package.json
Normal 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"
|
||||||
|
}
|
||||||
6
packages/middleware/src/Context.ts
Normal file
6
packages/middleware/src/Context.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { IncomingMessage, ServerResponse } from 'http'
|
||||||
|
|
||||||
|
export type Context = {
|
||||||
|
req: IncomingMessage
|
||||||
|
res: ServerResponse
|
||||||
|
}
|
||||||
3
packages/middleware/src/Middleware.ts
Normal file
3
packages/middleware/src/Middleware.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { Context } from './Context'
|
||||||
|
|
||||||
|
export type Middleware = <C extends Context>(ctx: C) => unknown
|
||||||
7
packages/middleware/src/createMiddleware.ts
Normal file
7
packages/middleware/src/createMiddleware.ts
Normal 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
|
||||||
|
}
|
||||||
49
packages/middleware/src/expressify.test.ts
Normal file
49
packages/middleware/src/expressify.test.ts
Normal 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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
28
packages/middleware/src/expressify.ts
Normal file
28
packages/middleware/src/expressify.ts
Normal 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)
|
||||||
|
}
|
||||||
3
packages/middleware/src/index.ts
Normal file
3
packages/middleware/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './Context'
|
||||||
|
export * from './expressify'
|
||||||
|
export * from './Middleware'
|
||||||
8
packages/middleware/tsconfig.esm.json
Normal file
8
packages/middleware/tsconfig.esm.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "esm"
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
]
|
||||||
|
}
|
||||||
9
packages/middleware/tsconfig.json
Normal file
9
packages/middleware/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.common.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user