Skip to content
This repository was archived by the owner on Nov 9, 2023. It is now read-only.

Commit 1d9f07c

Browse files
committed
Remove createAsyndMiddleware
* Handle errors fro masync middleware function rejections * Update readme * Update JsonRpcMiddleware type
1 parent a49cc10 commit 1d9f07c

File tree

6 files changed

+113
-331
lines changed

6 files changed

+113
-331
lines changed

README.md

Lines changed: 32 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,21 @@ They can let processing continue down the stack with `next()`, or complete the r
3939
engine.push(function (req, res, next, end) {
4040
if (req.skipCache) return next();
4141
res.result = getResultFromCache(req);
42-
end();
42+
return end();
43+
});
44+
```
45+
46+
Middleware functions can be `async`:
47+
48+
```js
49+
engine.push(async function (req, res, next, end) {
50+
if (req.method !== targetMethod) return next();
51+
res.result = await processTargetMethodRequest(req);
52+
return end();
4353
});
4454
```
4555

46-
By passing a _return handler_ to the `next` function, you can get a peek at the result before it returns.
56+
By passing a _return handler_ to the `next` function, you can get a peek at the response before it is returned to the requester.
4757

4858
```js
4959
engine.push(function (req, res, next, end) {
@@ -61,105 +71,43 @@ const subengine = new JsonRpcEngine();
6171
engine.push(subengine.asMiddleware());
6272
```
6373

64-
### `async` Middleware
74+
### Error Handling
6575

66-
If you require your middleware function to be `async`, use `createAsyncMiddleware`:
76+
Errors should be handled by throwing inside middleware functions.
6777

68-
```js
69-
const { createAsyncMiddleware } = require('json-rpc-engine');
70-
71-
let engine = new RpcEngine();
72-
engine.push(
73-
createAsyncMiddleware(async (req, res, next) => {
74-
res.result = 42;
75-
next();
76-
}),
77-
);
78-
```
78+
For backwards compatibility, you can also pass an error to the `end` callback,
79+
or set the error on the response object, and then call `end` or `next`.
80+
However, errors must **not** be passed to the `next` callback.
7981

80-
`async` middleware do not take an `end` callback.
81-
Instead, the request ends if the middleware returns without calling `next()`:
82+
Errors always take precedent over results.
83+
If an error is detected, the response's `result` property will be deleted.
8284

83-
```js
84-
engine.push(
85-
createAsyncMiddleware(async (req, res, next) => {
86-
res.result = 42;
87-
/* The request will end when this returns */
88-
}),
89-
);
90-
```
91-
92-
The `next` callback of `async` middleware also don't take return handlers.
93-
Instead, you can `await next()`.
94-
When the execution of the middleware resumes, you can work with the response again.
95-
96-
```js
97-
engine.push(
98-
createAsyncMiddleware(async (req, res, next) => {
99-
res.result = 42;
100-
await next();
101-
/* Your return handler logic goes here */
102-
addToMetrics(res);
103-
}),
104-
);
105-
```
106-
107-
You can freely mix callback-based and `async` middleware:
85+
All of the following examples are equivalent.
86+
It does not matter of the middleware function is synchronous or asynchronous.
10887

10988
```js
89+
// Throwing is preferred.
11090
engine.push(function (req, res, next, end) {
111-
if (!isCached(req)) {
112-
return next((cb) => {
113-
insertIntoCache(res, cb);
114-
});
115-
}
116-
res.result = getResultFromCache(req);
117-
end();
91+
throw new Error();
11892
});
11993

120-
engine.push(
121-
createAsyncMiddleware(async (req, res, next) => {
122-
res.result = 42;
123-
await next();
124-
addToMetrics(res);
125-
}),
126-
);
127-
```
128-
129-
### Gotchas
130-
131-
Handle errors via `end(err)`, _NOT_ `next(err)`.
132-
133-
```js
134-
/* INCORRECT */
94+
// For backwards compatibility, you can also do this:
13595
engine.push(function (req, res, next, end) {
136-
next(new Error());
96+
end(new Error());
13797
});
13898

139-
/* CORRECT */
14099
engine.push(function (req, res, next, end) {
141-
end(new Error());
100+
res.error = new Error();
101+
end();
142102
});
143-
```
144-
145-
However, `next()` will detect errors on the response object, and cause
146-
`end(res.error)` to be called.
147103

148-
```js
149104
engine.push(function (req, res, next, end) {
150105
res.error = new Error();
151-
next(); /* This will cause end(res.error) to be called. */
106+
next();
152107
});
153-
```
154-
155-
## Running tests
156108

157-
Build the project if not already built:
158-
159-
```bash
160-
yarn build
161-
```
162-
163-
```bash
164-
yarn test
109+
// INCORRECT. Do not do this:
110+
engine.push(function (req, res, next, end) {
111+
next(new Error());
112+
});
165113
```

src/JsonRpcEngine.ts

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export type JsonRpcMiddleware<T, U> = (
8484
res: PendingJsonRpcResponse<U>,
8585
next: JsonRpcEngineNextCallback,
8686
end: JsonRpcEngineEndCallback,
87-
) => void;
87+
) => void | Promise<void>;
8888

8989
/**
9090
* A JSON-RPC request and response processor.
@@ -382,55 +382,61 @@ export class JsonRpcEngine extends SafeEventEmitter {
382382
* @returns An array of any error encountered during middleware exection,
383383
* and a boolean indicating whether the request should end.
384384
*/
385-
private static _runMiddleware(
385+
private static async _runMiddleware(
386386
req: JsonRpcRequest<unknown>,
387387
res: PendingJsonRpcResponse<unknown>,
388388
middleware: JsonRpcMiddleware<unknown, unknown>,
389389
returnHandlers: JsonRpcEngineReturnHandler[],
390390
): Promise<[unknown, boolean]> {
391-
return new Promise((resolve) => {
392-
const end: JsonRpcEngineEndCallback = (err?: unknown) => {
393-
const error = err || res.error;
394-
if (error) {
395-
res.error = serializeError(error);
396-
}
397-
// True indicates that the request should end
398-
resolve([error, true]);
399-
};
400-
401-
const next: JsonRpcEngineNextCallback = (
402-
returnHandler?: JsonRpcEngineReturnHandler,
403-
) => {
404-
if (res.error) {
405-
end(res.error);
406-
} else {
407-
if (returnHandler) {
408-
if (typeof returnHandler !== 'function') {
409-
end(
410-
new EthereumRpcError(
411-
errorCodes.rpc.internal,
412-
`JsonRpcEngine: "next" return handlers must be functions. ` +
413-
`Received "${typeof returnHandler}" for request:\n${jsonify(
414-
req,
415-
)}`,
416-
{ request: req },
417-
),
418-
);
419-
}
420-
returnHandlers.push(returnHandler);
421-
}
391+
let resolve: (value: [unknown, boolean]) => void;
392+
const middlewareCallbackPromise = new Promise<[unknown, boolean]>(
393+
(_resolve) => {
394+
resolve = _resolve;
395+
},
396+
);
397+
398+
const end: JsonRpcEngineEndCallback = (err?: unknown) => {
399+
const error = err || res.error;
400+
if (error) {
401+
res.error = serializeError(error);
402+
}
403+
// True indicates that the request should end
404+
resolve([error, true]);
405+
};
422406

423-
// False indicates that the request should not end
424-
resolve([null, false]);
407+
const next: JsonRpcEngineNextCallback = (
408+
returnHandler?: JsonRpcEngineReturnHandler,
409+
) => {
410+
if (res.error) {
411+
end(res.error);
412+
} else {
413+
if (returnHandler) {
414+
if (typeof returnHandler !== 'function') {
415+
end(
416+
new EthereumRpcError(
417+
errorCodes.rpc.internal,
418+
`JsonRpcEngine: "next" return handlers must be functions. ` +
419+
`Received "${typeof returnHandler}" for request:\n${jsonify(
420+
req,
421+
)}`,
422+
{ request: req },
423+
),
424+
);
425+
}
426+
returnHandlers.push(returnHandler);
425427
}
426-
};
427428

428-
try {
429-
middleware(req, res, next, end);
430-
} catch (error) {
431-
end(error);
429+
// False indicates that the request should not end
430+
resolve([null, false]);
432431
}
433-
});
432+
};
433+
434+
try {
435+
await middleware(req, res, next, end);
436+
} catch (error) {
437+
end(error);
438+
}
439+
return middlewareCallbackPromise;
434440
}
435441

436442
/**

src/createAsyncMiddleware.ts

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export * from './idRemapMiddleware';
2-
export * from './createAsyncMiddleware';
32
export * from './createScaffoldMiddleware';
43
export * from './getUniqueId';
54
export * from './JsonRpcEngine';

0 commit comments

Comments
 (0)