jsonrpc: Add ability to specify context via high-order functions
This commit is contained in:
parent
401e5b481a
commit
cfc6933e78
@ -5,12 +5,18 @@ import bodyParser from 'body-parser'
|
|||||||
|
|
||||||
describe('jsonrpc', () => {
|
describe('jsonrpc', () => {
|
||||||
|
|
||||||
|
interface IContext {
|
||||||
|
userId: number
|
||||||
|
}
|
||||||
|
|
||||||
interface IService {
|
interface IService {
|
||||||
add(a: number, b: number): number
|
add(a: number, b: number): number
|
||||||
delay(): Promise<void>
|
delay(): Promise<void>
|
||||||
syncError(message: string): void
|
syncError(message: string): void
|
||||||
asyncError(message: string): Promise<void>
|
asyncError(message: string): Promise<void>
|
||||||
httpError(statusCode: number, message: string): Promise<void>
|
httpError(statusCode: number, message: string): Promise<void>
|
||||||
|
|
||||||
|
addWithContext(a: number, b: number): (ctx: IContext) => number
|
||||||
}
|
}
|
||||||
|
|
||||||
class Service implements IService {
|
class Service implements IService {
|
||||||
@ -40,6 +46,9 @@ describe('jsonrpc', () => {
|
|||||||
}]
|
}]
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
addWithContext = (a: number, b: number) => (ctx: IContext): number => {
|
||||||
|
return a + b + ctx.userId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createApp() {
|
function createApp() {
|
||||||
@ -51,14 +60,17 @@ describe('jsonrpc', () => {
|
|||||||
'syncError',
|
'syncError',
|
||||||
'asyncError',
|
'asyncError',
|
||||||
'httpError',
|
'httpError',
|
||||||
]))
|
'addWithContext',
|
||||||
|
], req => ({userId: 1000})))
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArgumentTypes<T> = T extends (...args: infer U) => infer R ? U : never
|
type ArgumentTypes<T> = T extends (...args: infer U) => infer R ? U : never
|
||||||
type RetType<T> = T extends (...args: any[]) => infer R ? R : never
|
type RetType<T> = T extends (...args: any[]) => infer R ? R : never
|
||||||
|
type UnwrapHOC<T> = T extends (...args: any[]) => infer R ? R : T
|
||||||
type RetProm<T> = T extends Promise<any> ? T : Promise<T>
|
type RetProm<T> = T extends Promise<any> ? T : Promise<T>
|
||||||
type PromisifyReturnType<T> = (...a: ArgumentTypes<T>) => RetProm<RetType<T>>
|
type PromisifyReturnType<T> = (...a: ArgumentTypes<T>) =>
|
||||||
|
RetProm<UnwrapHOC<RetType<T>>>
|
||||||
type Asyncified<T> = {
|
type Asyncified<T> = {
|
||||||
[K in keyof T]: PromisifyReturnType<T[K]>
|
[K in keyof T]: PromisifyReturnType<T[K]>
|
||||||
}
|
}
|
||||||
@ -157,6 +169,10 @@ describe('jsonrpc', () => {
|
|||||||
const response = await client.delay()
|
const response = await client.delay()
|
||||||
expect(response).toEqual(undefined)
|
expect(response).toEqual(undefined)
|
||||||
})
|
})
|
||||||
|
it('can use context', async () => {
|
||||||
|
const response = await client.addWithContext(5, 7)
|
||||||
|
expect(response).toEqual(1000 + 5 + 7)
|
||||||
|
})
|
||||||
it('handles synchronous notifications', async () => {
|
it('handles synchronous notifications', async () => {
|
||||||
await request(createApp())
|
await request(createApp())
|
||||||
.post('/myService')
|
.post('/myService')
|
||||||
|
|||||||
@ -95,9 +95,10 @@ function isPromise(value: any): value is Promise<unknown> {
|
|||||||
* Adds middleware for handling JSON RPC requests. Expects JSON middleware to
|
* Adds middleware for handling JSON RPC requests. Expects JSON middleware to
|
||||||
* already be configured.
|
* already be configured.
|
||||||
*/
|
*/
|
||||||
export function jsonrpc<T, F extends FunctionPropertyNames<T>>(
|
export function jsonrpc<T, F extends FunctionPropertyNames<T>, Ctx>(
|
||||||
service: T,
|
service: T,
|
||||||
functions: F[],
|
functions: F[],
|
||||||
|
getContext: (req: Request) => Ctx,
|
||||||
) {
|
) {
|
||||||
const rpcService = pick(service, functions)
|
const rpcService = pick(service, functions)
|
||||||
|
|
||||||
@ -135,6 +136,9 @@ export function jsonrpc<T, F extends FunctionPropertyNames<T>>(
|
|||||||
let retValue
|
let retValue
|
||||||
try {
|
try {
|
||||||
retValue = (rpcService as any)[method](...params)
|
retValue = (rpcService as any)[method](...params)
|
||||||
|
if (typeof retValue === 'function') {
|
||||||
|
retValue = retValue(getContext(req))
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return handleError(err, req, res, next)
|
return handleError(err, req, res, next)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user