From ae4f531763a7053993a27419ebac311ea9b4ea0c Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Sat, 27 Mar 2021 10:37:25 -0700 Subject: [PATCH 1/7] Remove createAsyndMiddleware --- README.md | 69 +++--------------- src/createAsyncMiddleware.ts | 81 --------------------- src/index.ts | 1 - test/createAsyncMiddleware.spec.js | 113 ----------------------------- 4 files changed, 11 insertions(+), 253 deletions(-) delete mode 100644 src/createAsyncMiddleware.ts delete mode 100644 test/createAsyncMiddleware.spec.js diff --git a/README.md b/README.md index 96efbc6..1e08f82 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,17 @@ They can let processing continue down the stack with `next()`, or complete the r engine.push(function(req, res, next, end){ if (req.skipCache) return next() res.result = getResultFromCache(req) - end() + return end() +}) +``` + +Middleware functions can be `async`: + +```js +engine.push(async function(req, res, next, end){ + if (req.method !== targetMethod) return next() + res.result = await processTargetMethodRequest(req) + return end() }) ``` @@ -61,63 +71,6 @@ const subengine = new JsonRpcEngine() engine.push(subengine.asMiddleware()) ``` -### `async` Middleware - -If you require your middleware function to be `async`, use `createAsyncMiddleware`: - -```js -const { createAsyncMiddleware } = require('json-rpc-engine') - -let engine = new RpcEngine() -engine.push(createAsyncMiddleware(async (req, res, next) => { - res.result = 42 - next() -})) -``` - -`async` middleware do not take an `end` callback. -Instead, the request ends if the middleware returns without calling `next()`: - -```js -engine.push(createAsyncMiddleware(async (req, res, next) => { - res.result = 42 - /* The request will end when this returns */ -})) -``` - -The `next` callback of `async` middleware also don't take return handlers. -Instead, you can `await next()`. -When the execution of the middleware resumes, you can work with the response again. - -```js -engine.push(createAsyncMiddleware(async (req, res, next) => { - res.result = 42 - await next() - /* Your return handler logic goes here */ - addToMetrics(res) -})) -``` - -You can freely mix callback-based and `async` middleware: - -```js -engine.push(function(req, res, next, end){ - if (!isCached(req)) { - return next((cb) => { - insertIntoCache(res, cb) - }) - } - res.result = getResultFromCache(req) - end() -}) - -engine.push(createAsyncMiddleware(async (req, res, next) => { - res.result = 42 - await next() - addToMetrics(res) -})) -``` - ### Gotchas Handle errors via `end(err)`, *NOT* `next(err)`. diff --git a/src/createAsyncMiddleware.ts b/src/createAsyncMiddleware.ts deleted file mode 100644 index 9076cac..0000000 --- a/src/createAsyncMiddleware.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - JsonRpcMiddleware, - JsonRpcRequest, - PendingJsonRpcResponse, -} from './JsonRpcEngine'; - -export type AsyncJsonRpcEngineNextCallback = () => Promise; - -export type AsyncJsonrpcMiddleware = ( - req: JsonRpcRequest, - res: PendingJsonRpcResponse, - next: AsyncJsonRpcEngineNextCallback -) => Promise; - -type ReturnHandlerCallback = (error: null | Error) => void; - -/** - * JsonRpcEngine only accepts callback-based middleware directly. - * createAsyncMiddleware exists to enable consumers to pass in async middleware - * functions. - * - * Async middleware have no "end" function. Instead, they "end" if they return - * without calling "next". Rather than passing in explicit return handlers, - * async middleware can simply await "next", and perform operations on the - * response object when execution resumes. - * - * To accomplish this, createAsyncMiddleware passes the async middleware a - * wrapped "next" function. That function calls the internal JsonRpcEngine - * "next" function with a return handler that resolves a promise when called. - * - * The return handler will always be called. Its resolution of the promise - * enables the control flow described above. - */ -export function createAsyncMiddleware( - asyncMiddleware: AsyncJsonrpcMiddleware, -): JsonRpcMiddleware { - return async (req, res, next, end) => { - // nextPromise is the key to the implementation - // it is resolved by the return handler passed to the - // "next" function - let resolveNextPromise: () => void; - const nextPromise = new Promise((resolve) => { - resolveNextPromise = resolve; - }); - - let returnHandlerCallback: unknown = null; - let nextWasCalled = false; - - // This will be called by the consumer's async middleware. - const asyncNext = async () => { - nextWasCalled = true; - - // We pass a return handler to next(). When it is called by the engine, - // the consumer's async middleware will resume executing. - // eslint-disable-next-line node/callback-return - next((runReturnHandlersCallback) => { - // This callback comes from JsonRpcEngine._runReturnHandlers - returnHandlerCallback = runReturnHandlersCallback; - resolveNextPromise(); - }); - await nextPromise; - }; - - try { - await asyncMiddleware(req, res, asyncNext); - - if (nextWasCalled) { - await nextPromise; // we must wait until the return handler is called - (returnHandlerCallback as ReturnHandlerCallback)(null); - } else { - end(null); - } - } catch (error) { - if (returnHandlerCallback) { - (returnHandlerCallback as ReturnHandlerCallback)(error); - } else { - end(error); - } - } - }; -} diff --git a/src/index.ts b/src/index.ts index e47ee53..f551a54 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ export * from './idRemapMiddleware'; -export * from './createAsyncMiddleware'; export * from './createScaffoldMiddleware'; export * from './getUniqueId'; export * from './JsonRpcEngine'; diff --git a/test/createAsyncMiddleware.spec.js b/test/createAsyncMiddleware.spec.js deleted file mode 100644 index 09c4e27..0000000 --- a/test/createAsyncMiddleware.spec.js +++ /dev/null @@ -1,113 +0,0 @@ -/* eslint-env mocha */ -/* eslint require-await: 0 */ -'use strict'; - -const { strict: assert } = require('assert'); -const { JsonRpcEngine, createAsyncMiddleware } = require('../dist'); - -describe('createAsyncMiddleware', function () { - it('basic middleware test', function (done) { - const engine = new JsonRpcEngine(); - - engine.push(createAsyncMiddleware(async (_req, res, _next) => { - res.result = 42; - })); - - const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; - - engine.handle(payload, function (err, res) { - assert.ifError(err, 'did not error'); - assert.ok(res, 'has res'); - assert.equal(res.result, 42, 'has expected result'); - done(); - }); - }); - - it('next middleware test', function (done) { - const engine = new JsonRpcEngine(); - - engine.push(createAsyncMiddleware(async (_req, res, next) => { - assert.ifError(res.result, 'does not have result'); - await next(); // eslint-disable-line node/callback-return - assert.equal(res.result, 1234, 'value was set as expected'); - // override value - res.result = 42; // eslint-disable-line require-atomic-updates - })); - - engine.push(function (_req, res, _next, end) { - res.result = 1234; - end(); - }); - - const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; - - engine.handle(payload, function (err, res) { - assert.ifError(err, 'did not error'); - assert.ok(res, 'has res'); - assert.equal(res.result, 42, 'has expected result'); - done(); - }); - }); - - it('basic throw test', function (done) { - const engine = new JsonRpcEngine(); - - const error = new Error('bad boy'); - - engine.push(createAsyncMiddleware(async (_req, _res, _next) => { - throw error; - })); - - const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; - - engine.handle(payload, function (err, _res) { - assert.ok(err, 'has err'); - assert.equal(err, error, 'has expected result'); - done(); - }); - }); - - it('throw after next test', function (done) { - const engine = new JsonRpcEngine(); - - const error = new Error('bad boy'); - - engine.push(createAsyncMiddleware(async (_req, _res, next) => { - await next(); // eslint-disable-line node/callback-return - throw error; - })); - - engine.push(function (_req, res, _next, end) { - res.result = 1234; - end(); - }); - - const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; - - engine.handle(payload, function (err, _res) { - assert.ok(err, 'has err'); - assert.equal(err, error, 'has expected result'); - done(); - }); - }); - - it('doesn\'t await next', function (done) { - const engine = new JsonRpcEngine(); - - engine.push(createAsyncMiddleware(async (_req, _res, next) => { - next(); - })); - - engine.push(function (_req, res, _next, end) { - res.result = 1234; - end(); - }); - - const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; - - engine.handle(payload, function (err, _res) { - assert.ifError(err, 'has err'); - done(); - }); - }); -}); From 83784eaeb5087eace2c9f5672c2eada79476a578 Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Sat, 27 Mar 2021 11:51:34 -0700 Subject: [PATCH 2/7] Handle errors async middleware function rejections --- package.json | 5 +-- src/JsonRpcEngine.ts | 86 +++++++++++++++++++++++--------------------- test/engine.spec.js | 35 +++++++++++++++++- 3 files changed, 83 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index bfba194..d7f444f 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,9 @@ "scripts": { "build": "tsc --project .", "lint": "eslint . --ext ts,js,json", - "lint:fix": "eslint . --ext ts,js,json --fix", - "test": "mocha ./test", + "lint:fix": "yarn lint --fix", + "test:nobuild": "mocha ./test", + "test": "yarn build && yarn test:nobuild", "coverage": "nyc --check-coverage yarn test", "prepublishOnly": "yarn && yarn lint && yarn build && yarn coverage" }, diff --git a/src/JsonRpcEngine.ts b/src/JsonRpcEngine.ts index 6e38057..1dc300a 100644 --- a/src/JsonRpcEngine.ts +++ b/src/JsonRpcEngine.ts @@ -388,55 +388,61 @@ export class JsonRpcEngine extends SafeEventEmitter { * @returns An array of any error encountered during middleware exection, * and a boolean indicating whether the request should end. */ - private static _runMiddleware( + private static async _runMiddleware( req: JsonRpcRequest, res: PendingJsonRpcResponse, middleware: JsonRpcMiddleware, returnHandlers: JsonRpcEngineReturnHandler[], ): Promise<[unknown, boolean]> { - return new Promise((resolve) => { - const end: JsonRpcEngineEndCallback = (err?: unknown) => { - const error = err || res.error; - if (error) { - res.error = serializeError(error); - } - // True indicates that the request should end - resolve([error, true]); - }; - - const next: JsonRpcEngineNextCallback = ( - returnHandler?: JsonRpcEngineReturnHandler, - ) => { - if (res.error) { - end(res.error); - } else { - if (returnHandler) { - if (typeof returnHandler !== 'function') { - end( - new EthereumRpcError( - errorCodes.rpc.internal, - `JsonRpcEngine: "next" return handlers must be functions. ` + - `Received "${typeof returnHandler}" for request:\n${jsonify( - req, - )}`, - { request: req }, - ), - ); - } - returnHandlers.push(returnHandler); - } + let resolve: (value: [unknown, boolean]) => void; + const middlewareCallbackPromise = new Promise<[unknown, boolean]>( + (_resolve) => { + resolve = _resolve; + }, + ); + + const end: JsonRpcEngineEndCallback = (err?: unknown) => { + const error = err || res.error; + if (error) { + res.error = serializeError(error); + } + // True indicates that the request should end + resolve([error, true]); + }; - // False indicates that the request should not end - resolve([null, false]); + const next: JsonRpcEngineNextCallback = ( + returnHandler?: JsonRpcEngineReturnHandler, + ) => { + if (res.error) { + end(res.error); + } else { + if (returnHandler) { + if (typeof returnHandler !== 'function') { + end( + new EthereumRpcError( + errorCodes.rpc.internal, + `JsonRpcEngine: "next" return handlers must be functions. ` + + `Received "${typeof returnHandler}" for request:\n${jsonify( + req, + )}`, + { request: req }, + ), + ); + } + returnHandlers.push(returnHandler); } - }; - try { - middleware(req, res, next, end); - } catch (error) { - end(error); + // False indicates that the request should not end + resolve([null, false]); } - }); + }; + + try { + await middleware(req, res, next, end); + } catch (error) { + end(error); + } + return middlewareCallbackPromise; } /** diff --git a/test/engine.spec.js b/test/engine.spec.js index 192934e..3725576 100644 --- a/test/engine.spec.js +++ b/test/engine.spec.js @@ -380,8 +380,10 @@ describe('JsonRpcEngine', function () { }); }); - engine.push(function (_req, _res, next, _end) { + // Async middleware function + engine.push(async function (_req, _res, next, _end) { events.push('2-next'); + await delay(); next(function (cb) { events.push('2-return'); cb(); @@ -432,6 +434,31 @@ describe('JsonRpcEngine', function () { }); }); + it('calls back next handler even if async middleware rejects', function (done) { + const engine = new JsonRpcEngine(); + + let sawNextReturnHandlerCalled = false; + + engine.push(function (_req, _res, next, _end) { + next(function (cb) { + sawNextReturnHandlerCalled = true; + cb(); + }); + }); + + engine.push(async function (_req, _res, _next, _end) { + throw new Error('boom'); + }); + + const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; + + engine.handle(payload, (err, _res) => { + assert.ok(err, 'did error'); + assert.ok(sawNextReturnHandlerCalled, 'saw next return handler called'); + done(); + }); + }); + it('handles error in next handler', function (done) { const engine = new JsonRpcEngine(); @@ -500,3 +527,9 @@ describe('JsonRpcEngine', function () { } }); }); + +function delay(ms = 1) { + return new Promise((resolve) => { + setTimeout(() => resolve(), ms); + }); +} From ed5b3f295ec4268dfea302fbe3da7fb3665a25cf Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Sat, 27 Mar 2021 12:57:05 -0700 Subject: [PATCH 3/7] Update readme --- README.md | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1e08f82..d30e155 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ engine.push(async function(req, res, next, end){ }) ``` -By passing a _return handler_ to the `next` function, you can get a peek at the result before it returns. +By passing a _return handler_ to the `next` function, you can get a peek at the response before it is returned to the requester. ```js engine.push(function(req, res, next, end){ @@ -71,28 +71,43 @@ const subengine = new JsonRpcEngine() engine.push(subengine.asMiddleware()) ``` -### Gotchas +### Error Handling -Handle errors via `end(err)`, *NOT* `next(err)`. +Errors should be handled by throwing inside middleware functions. + +For backwards compatibility, you can also pass an error to the `end` callback, +or set the error on the response object, and then call `end` or `next`. +However, errors must **not** be passed to the `next` callback. + +Errors always take precedent over results. +If an error is detected, the response's `result` property will be deleted. + +All of the following examples are equivalent. +It does not matter of the middleware function is synchronous or asynchronous. ```js -/* INCORRECT */ +// Throwing is preferred. engine.push(function(req, res, next, end){ - next(new Error()) + throw new Error() }) -/* CORRECT */ +// For backwards compatibility, you can also do this: engine.push(function(req, res, next, end){ end(new Error()) }) -``` -However, `next()` will detect errors on the response object, and cause -`end(res.error)` to be called. +engine.push(function(req, res, next, end){ + res.error = new Error() + end() +}) -```js engine.push(function(req, res, next, end){ res.error = new Error() - next() /* This will cause end(res.error) to be called. */ + next() +}) + +// INCORRECT. Do not do this: +engine.push(function(req, res, next, end){ + next(new Error()) }) ``` From df8b6a33db5999207953bff47536b15c3e31e392 Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Sat, 27 Mar 2021 21:08:37 -0700 Subject: [PATCH 4/7] Fix JsonRpcMiddleware type --- src/JsonRpcEngine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonRpcEngine.ts b/src/JsonRpcEngine.ts index 1dc300a..d0e92d3 100644 --- a/src/JsonRpcEngine.ts +++ b/src/JsonRpcEngine.ts @@ -84,7 +84,7 @@ export type JsonRpcMiddleware = ( res: PendingJsonRpcResponse, next: JsonRpcEngineNextCallback, end: JsonRpcEngineEndCallback -) => void; +) => void | Promise; /** * A JSON-RPC request and response processor. From 31ccf7970dc3710f1d9b499b317dd33305ccfb9a Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Sat, 27 Mar 2021 20:41:50 -0700 Subject: [PATCH 5/7] Remove callback from next return handlers --- src/JsonRpcEngine.ts | 17 +++------- src/idRemapMiddleware.ts | 3 +- test/asMiddleware.spec.js | 10 +++--- test/engine.spec.js | 64 +++++++++++++++++++++++++++--------- test/mergeMiddleware.spec.js | 6 ++-- 5 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/JsonRpcEngine.ts b/src/JsonRpcEngine.ts index d0e92d3..f71b2cf 100644 --- a/src/JsonRpcEngine.ts +++ b/src/JsonRpcEngine.ts @@ -67,9 +67,7 @@ export interface PendingJsonRpcResponse extends JsonRpcResponseBase { export type JsonRpcEngineCallbackError = Error | JsonRpcError | null; -export type JsonRpcEngineReturnHandler = ( - done: (error?: JsonRpcEngineCallbackError) => void -) => void; +export type JsonRpcEngineReturnHandler = () => void | Promise; export type JsonRpcEngineNextCallback = ( returnHandlerCallback?: JsonRpcEngineReturnHandler @@ -186,13 +184,8 @@ export class JsonRpcEngine extends SafeEventEmitter { return end(middlewareError as JsonRpcEngineCallbackError); } - return next(async (handlerCallback) => { - try { - await JsonRpcEngine._runReturnHandlers(returnHandlers); - } catch (error) { - return handlerCallback(error); - } - return handlerCallback(); + return next(async () => { + await JsonRpcEngine._runReturnHandlers(returnHandlers); }); } catch (error) { return end(error); @@ -453,9 +446,7 @@ export class JsonRpcEngine extends SafeEventEmitter { handlers: JsonRpcEngineReturnHandler[], ): Promise { for (const handler of handlers) { - await new Promise((resolve, reject) => { - handler((err) => (err ? reject(err) : resolve())); - }); + await handler(); } } diff --git a/src/idRemapMiddleware.ts b/src/idRemapMiddleware.ts index d4c7b61..b9972d6 100644 --- a/src/idRemapMiddleware.ts +++ b/src/idRemapMiddleware.ts @@ -7,10 +7,9 @@ export function createIdRemapMiddleware(): JsonRpcMiddleware { const newId = getUniqueId(); req.id = newId; res.id = newId; - next((done) => { + next(() => { req.id = originalId; res.id = originalId; - done(); }); }; } diff --git a/test/asMiddleware.spec.js b/test/asMiddleware.spec.js index fc9cf82..9f0d7d8 100644 --- a/test/asMiddleware.spec.js +++ b/test/asMiddleware.spec.js @@ -108,9 +108,8 @@ describe('asMiddleware', function () { const subengine = new JsonRpcEngine(); subengine.push((_req, res, next, _end) => { - next((cb) => { + next(() => { res.copy = res.result; - cb(); }); }); @@ -134,9 +133,8 @@ describe('asMiddleware', function () { const subengine = new JsonRpcEngine(); subengine.push((_req, res, next, _end) => { - next((cb) => { + next(() => { res.copy = res.result; - cb(); }); }); @@ -181,7 +179,7 @@ describe('asMiddleware', function () { const subengine = new JsonRpcEngine(); subengine.push((_req, _res, next, _end) => { - next((_cb) => { + next(() => { throw new Error('foo'); }); }); @@ -206,7 +204,7 @@ describe('asMiddleware', function () { const subengine = new JsonRpcEngine(); subengine.push((_req, _res, next, _end) => { - next((_cb) => { + next(() => { throw new Error('foo'); }); }); diff --git a/test/engine.spec.js b/test/engine.spec.js index 3725576..6a50d91 100644 --- a/test/engine.spec.js +++ b/test/engine.spec.js @@ -346,9 +346,20 @@ describe('JsonRpcEngine', function () { const engine = new JsonRpcEngine(); engine.push(function (_req, res, next, _end) { - next(function (cb) { - res.sawReturnHandler = true; - cb(); + next(function () { + res.sawReturnHandler.push(3); + }); + }); + + engine.push(function (_req, res, next, _end) { + next(async function () { + res.sawReturnHandler.push(2); + }); + }); + + engine.push(function (_req, res, next, _end) { + next(function () { + res.sawReturnHandler = [1]; }); }); @@ -360,9 +371,13 @@ describe('JsonRpcEngine', function () { const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; engine.handle(payload, function (err, res) { - assert.ifError(err, 'did not error'); - assert.ok(res, 'has res'); - assert.ok(res.sawReturnHandler, 'saw return handler'); + assert.ifError(err, 'should not error'); + assert.ok(res, 'should have res'); + assert.deepStrictEqual( + res.sawReturnHandler, + [1, 2, 3], + 'should interact with all return handlers', + ); done(); }); }); @@ -374,9 +389,8 @@ describe('JsonRpcEngine', function () { engine.push(function (_req, _res, next, _end) { events.push('1-next'); - next(function (cb) { + next(function () { events.push('1-return'); - cb(); }); }); @@ -384,9 +398,8 @@ describe('JsonRpcEngine', function () { engine.push(async function (_req, _res, next, _end) { events.push('2-next'); await delay(); - next(function (cb) { + next(function () { events.push('2-return'); - cb(); }); }); @@ -415,9 +428,8 @@ describe('JsonRpcEngine', function () { let sawNextReturnHandlerCalled = false; engine.push(function (_req, _res, next, _end) { - next(function (cb) { + next(function () { sawNextReturnHandlerCalled = true; - cb(); }); }); @@ -440,9 +452,8 @@ describe('JsonRpcEngine', function () { let sawNextReturnHandlerCalled = false; engine.push(function (_req, _res, next, _end) { - next(function (cb) { + next(function () { sawNextReturnHandlerCalled = true; - cb(); }); }); @@ -463,7 +474,30 @@ describe('JsonRpcEngine', function () { const engine = new JsonRpcEngine(); engine.push(function (_req, _res, next, _end) { - next(function (_cb) { + next(function () { + throw new Error('foo'); + }); + }); + + engine.push(function (_req, res, _next, end) { + res.result = 42; + end(); + }); + + const payload = { id: 1, jsonrpc: '2.0', method: 'hello' }; + + engine.handle(payload, (err, _res) => { + assert.ok(err, 'did error'); + assert.equal(err.message, 'foo', 'error has expected message'); + done(); + }); + }); + + it('handles error in async next handler', function (done) { + const engine = new JsonRpcEngine(); + + engine.push(function (_req, _res, next, _end) { + next(async function () { throw new Error('foo'); }); }); diff --git a/test/mergeMiddleware.spec.js b/test/mergeMiddleware.spec.js index fc99473..f5f8ecf 100644 --- a/test/mergeMiddleware.spec.js +++ b/test/mergeMiddleware.spec.js @@ -34,9 +34,8 @@ describe('mergeMiddleware', function () { engine.push(mergeMiddleware([ (_req, res, next, _end) => { - next((cb) => { + next(() => { res.copy = res.result; - cb(); }); }, (_req, res, _next, end) => { @@ -130,9 +129,8 @@ describe('mergeMiddleware', function () { engine.push(mergeMiddleware([ (_req, res, next, _end) => { - next((cb) => { + next(() => { res.copy = res.result; - cb(); }); }, ])); From ee6638035fe2cda325950f9b0928778ddb2d9325 Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Sat, 27 Mar 2021 20:44:01 -0700 Subject: [PATCH 6/7] Update readme --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d30e155..dca0dec 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,16 @@ engine.push(async function(req, res, next, end){ By passing a _return handler_ to the `next` function, you can get a peek at the response before it is returned to the requester. ```js -engine.push(function(req, res, next, end){ - next(function(cb){ - insertIntoCache(res, cb) +engine.push((req, res, next, end) => { + next(() => { + await insertIntoCache(res) }) }) ``` +Return handlers can be synchronous or asynchronous. +They take no callbacks, and should only interact with the request and/or the response. + Engines can be nested by converting them to middleware using `JsonRpcEngine.asMiddleware()`: ```js From b62d79f9569b740d3d10501a16242a24fddd5ea5 Mon Sep 17 00:00:00 2001 From: Erik Marks <25517051+rekmarks@users.noreply.github.com> Date: Wed, 23 Jun 2021 23:28:46 -0700 Subject: [PATCH 7/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dca0dec..9d5cdea 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ By passing a _return handler_ to the `next` function, you can get a peek at the ```js engine.push((req, res, next, end) => { - next(() => { + next(async () => { await insertIntoCache(res) }) })