Add ability to specify jsonrpc context asynchronously

This commit is contained in:
Jerko Steiner 2019-09-05 09:25:38 +07:00
parent 927ccfa6e6
commit 1aa6cae0f3
2 changed files with 29 additions and 16 deletions

View File

@ -243,7 +243,7 @@ describe('jsonrpc', () => {
.expect(405) .expect(405)
}) })
describe('wrapCall', () => { describe('hook', () => {
let requests: IRequest[] = [] let requests: IRequest[] = []
let results: any[] = [] let results: any[] = []
@ -258,10 +258,10 @@ describe('jsonrpc', () => {
app.use(bodyParser.json()) app.use(bodyParser.json())
app.use('/', app.use('/',
jsonrpc( jsonrpc(
req => ({userId}), req => Promise.resolve({userId}),
noopLogger, noopLogger,
async (path, req, makeRequest) => { async (details, makeRequest) => {
requests.push(req) requests.push(details.request)
const result = await makeRequest() const result = await makeRequest()
results.push(result) results.push(result)
return result return result

View File

@ -11,7 +11,7 @@ import {
IRequest, IRequest,
} from './jsonrpc' } from './jsonrpc'
export type TGetContext<Context> = (req: Request) => Context export type TGetContext<Context> = (req: Request) => Promise<Context> | Context
export interface IJSONRPCReturnType { export interface IJSONRPCReturnType {
addService<T, F extends FunctionPropertyNames<T>>( addService<T, F extends FunctionPropertyNames<T>>(
@ -22,19 +22,26 @@ export interface IJSONRPCReturnType {
router(): Router router(): Router
} }
async function wrap<A, R>( export interface IInvocationDetails<A extends IRequest, Context> {
path: string, request: A, fn: () => Promise<R>): Promise<R> { context: Context
const result = await fn() path: string
request: A
}
async function defaultHook<A extends IRequest, R, Context>(
details: IInvocationDetails<A, Context>,
invoke: () => Promise<R>,
): Promise<R> {
const result = await invoke()
return result return result
} }
export function jsonrpc<Context>( export function jsonrpc<Context>(
getContext: TGetContext<Context>, getContext: TGetContext<Context>,
logger: ILogger, logger: ILogger,
wrapCall: <A extends IRequest, R>( hook: <A extends IRequest, R>(
path: string, details: IInvocationDetails<A, Context>,
request: A, invoke: (request?: A) => Promise<R>) => Promise<R> = defaultHook,
fn: (request?: A) => Promise<R>) => Promise<R> = wrap,
idempotentMethodRegex = IDEMPOTENT_METHOD_REGEX, idempotentMethodRegex = IDEMPOTENT_METHOD_REGEX,
): IJSONRPCReturnType { ): IJSONRPCReturnType {
@ -105,15 +112,21 @@ export function jsonrpc<Context>(
method: req.query.method, method: req.query.method,
params: JSON.parse(req.query.params), params: JSON.parse(req.query.params),
} }
wrapCall(path, request, Promise.resolve(getContext(req))
(body = request) => rpcService.invoke(body, getContext(req))) .then(context =>
hook(
{path, request, context},
(body = request) => rpcService.invoke(body, context)))
.then(response => handleResponse(response, res)) .then(response => handleResponse(response, res))
.catch(next) .catch(next)
}) })
router.post(path, (req, res, next) => { router.post(path, (req, res, next) => {
wrapCall(path, req.body, Promise.resolve(getContext(req))
(body = req.body) => rpcService.invoke(body, getContext(req))) .then(context =>
hook(
{path, request: req.body, context},
(body = req.body) => rpcService.invoke(body, context)))
.then(response => handleResponse(response, res)) .then(response => handleResponse(response, res))
.catch(next) .catch(next)
}) })