Add ability to wrap method calls in jsonrpc
This commit is contained in:
parent
4ea534293b
commit
9cc5a7affb
@ -1,10 +1,11 @@
|
||||
import bodyParser from 'body-parser'
|
||||
import express from 'express'
|
||||
import request from 'supertest'
|
||||
import {IRequest} from './jsonrpc'
|
||||
import {createClient} from './supertest'
|
||||
import {ensure} from './ensure'
|
||||
import {jsonrpc} from './express'
|
||||
import {noopLogger} from './test-utils'
|
||||
import {ensure} from './ensure'
|
||||
|
||||
describe('jsonrpc', () => {
|
||||
|
||||
@ -240,6 +241,54 @@ describe('jsonrpc', () => {
|
||||
.get(`/myService?jsonrpc=2.0&id=1&method=add¶ms=${params}`)
|
||||
.expect(405)
|
||||
})
|
||||
|
||||
describe('wrapCall', () => {
|
||||
|
||||
let requests: IRequest[] = []
|
||||
let results: any[] = []
|
||||
function create() {
|
||||
requests = []
|
||||
results = []
|
||||
|
||||
userId = 1000
|
||||
const app = express()
|
||||
const myService = new Service(5)
|
||||
// console.log('service', myService, Object.
|
||||
app.use(bodyParser.json())
|
||||
app.use('/',
|
||||
jsonrpc(
|
||||
req => ({userId}),
|
||||
noopLogger,
|
||||
async (path, req, makeRequest) => {
|
||||
requests.push(req)
|
||||
const result = await makeRequest()
|
||||
results.push(result)
|
||||
return result
|
||||
},
|
||||
)
|
||||
.addService('/myService', myService)
|
||||
.router(),
|
||||
)
|
||||
return app
|
||||
}
|
||||
|
||||
it('should wrap POST rpc method call', async () => {
|
||||
const req = {
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'add',
|
||||
params: [1, 2],
|
||||
}
|
||||
const response = await request(create())
|
||||
.post('/myService')
|
||||
.send(req)
|
||||
|
||||
expect(response.body.result).toEqual(3)
|
||||
expect(requests).toEqual([ req ])
|
||||
expect(results).toEqual([ response.body ])
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -8,6 +8,7 @@ import {NextFunction, Request, Response, Router} from 'express'
|
||||
import {createError, isJSONRPCError, IJSONRPCError, IError} from './error'
|
||||
import {
|
||||
createRpcService, ERROR_SERVER, ERROR_INVALID_PARAMS, ERROR_METHOD_NOT_FOUND,
|
||||
IRequest,
|
||||
} from './jsonrpc'
|
||||
|
||||
export type TGetContext<Context> = (req: Request) => Context
|
||||
@ -21,9 +22,19 @@ export interface IJSONRPCReturnType {
|
||||
router(): Router
|
||||
}
|
||||
|
||||
async function wrap<A, R>(
|
||||
path: string, request: A, fn: () => Promise<R>): Promise<R> {
|
||||
const result = await fn()
|
||||
return result
|
||||
}
|
||||
|
||||
export function jsonrpc<Context>(
|
||||
getContext: TGetContext<Context>,
|
||||
logger: ILogger,
|
||||
wrapCall: <A extends IRequest, R>(
|
||||
path: string,
|
||||
request: A,
|
||||
fn: (request?: A) => Promise<R>) => Promise<R> = wrap,
|
||||
idempotentMethodRegex = IDEMPOTENT_METHOD_REGEX,
|
||||
): IJSONRPCReturnType {
|
||||
|
||||
@ -94,13 +105,15 @@ export function jsonrpc<Context>(
|
||||
method: req.query.method,
|
||||
params: JSON.parse(req.query.params),
|
||||
}
|
||||
rpcService.invoke(request, getContext(req))
|
||||
wrapCall(path, request,
|
||||
(body = request) => rpcService.invoke(body, getContext(req)))
|
||||
.then(response => handleResponse(response, res))
|
||||
.catch(next)
|
||||
})
|
||||
|
||||
router.post(path, (req, res, next) => {
|
||||
rpcService.invoke(req.body, getContext(req))
|
||||
wrapCall(path, req.body,
|
||||
(body = req.body) => rpcService.invoke(body, getContext(req)))
|
||||
.then(response => handleResponse(response, res))
|
||||
.catch(next)
|
||||
})
|
||||
|
||||
@ -45,6 +45,21 @@ export function pick<T, K extends FunctionPropertyNames<T>>(t: T, keys: K[])
|
||||
}, {} as Pick<T, K>)
|
||||
}
|
||||
|
||||
export function getAllMethods<T>(obj: T): Array<FunctionPropertyNames<T>> {
|
||||
const props = new Set<string>()
|
||||
do {
|
||||
const l = Object.getOwnPropertyNames(obj)
|
||||
.filter((p, i, arr) => {
|
||||
return typeof (obj as any)[p] === 'function' &&
|
||||
p !== 'constructor'
|
||||
})
|
||||
.forEach(p => props.add(p))
|
||||
obj = Object.getPrototypeOf(obj)
|
||||
} while (Object.getPrototypeOf(obj))
|
||||
|
||||
return Array.from(props) as unknown as Array<FunctionPropertyNames<T>>
|
||||
}
|
||||
|
||||
export interface IRequest<M extends string = any, A = any[]> {
|
||||
jsonrpc: '2.0'
|
||||
id: TId | null
|
||||
@ -104,7 +119,9 @@ export const createRpcService = <T, M extends FunctionPropertyNames<T>>(
|
||||
service: T,
|
||||
methods?: M[],
|
||||
) => {
|
||||
const rpcService = methods ? pick(service, methods) : service
|
||||
|
||||
const rpcService = methods ? pick(service, methods) :
|
||||
pick(service, getAllMethods(service))
|
||||
return {
|
||||
async invoke<Context>(
|
||||
req: IRequest<M, ArgumentTypes<T[M]>>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user