shogowada / json-rpc-2.0

Let your client and server talk over function calls under JSON-RPC 2.0 spec. Strongly typed. No external dependencies.

Home Page:https://www.npmjs.com/package/json-rpc-2.0

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Middleware can't intercept errors in case of async method's function

stubbornick opened this issue · comments

Here is an example of the issue:

const {
  JSONRPCServer, createJSONRPCErrorResponse, JSONRPCErrorCode, JSONRPC,
} = require('json-rpc-2.0');

const server = new JSONRPCServer();
server.applyMiddleware(async (next, request, serverParams) => {
  try {
    console.log('MIDDLEWARE');
    const res = await next(request, serverParams);
    console.log('MIDDLEWARE RESULT', res);
    return res;
  } catch (error) {
    console.log('MIDDLEWARE EXCEPT', error);
    return createJSONRPCErrorResponse(
      request.id,
      error.code || JSONRPCErrorCode.InternalError,
      error.message,
    );
  }
});

server.addMethod('myMethod', async () => {
  throw new Error('TEST ERROR');
});

const main = async () => {
  const result = await server
    .receive({
      jsonrpc: JSONRPC,
      id: 0,
      method: 'myMethod',
      params: {},
    });

  console.log('RESULT', result);
};

main();

The output is:

MIDDLEWARE
JSON-RPC method myMethod responded an error Error: TEST ERROR
   ... <stacktrace> ...
MIDDLEWARE RESULT { jsonrpc: '2.0', id: 0, error: { code: 0, message: 'TEST ERROR' } }
RESULT { jsonrpc: '2.0', id: 0, error: { code: 0, message: 'TEST ERROR' } }

Moreover, in such case the error is posted in console with console.warn which makes it impossible to control logging of errors by lib's user.

Oh, just noticed to this issue. Let me take a look at it by next week.

It looks like I already have a test case for this (and it's passing):

describe("using middleware that catches exception", () => {
beforeEach(() => {
server.applyMiddleware(async (next, request, serverParams) => {
try {
return await next(request, serverParams);
} catch (error) {
return createJSONRPCErrorResponse(
request.id!,
error.code || JSONRPCErrorCode.InternalError,
error.message
);
}
});
});
describe("throwing", () => {
let error: any;
let actualResponse: JSONRPCResponse;
beforeEach(() => {
server
.receive({
jsonrpc: JSONRPC,
id: 0,
method: methodName,
params: {},
})
.then((response) => (actualResponse = response!));
error = { code: 123, message: "test" };
throwFromMethod(error);
return consumeAllEvents();
});
it("should catch the exception on middleware", () => {
const expected: JSONRPCErrorResponse = createJSONRPCErrorResponse(
0,
error.code,
error.message
);
expect(actualResponse).to.deep.equal(expected);
});
});
});

Can you please tell what's missing from the test case?

Sure. In your test case echoMethod is a synchronous one. The problem arrives when you throw in asynchronous method like in example I posted above.

Ah, I see now that method is actually asynchronous... Maybe the reason is that method is defined by addMethodAdvanced instead of addMethod.

Thanks! I could reproduce it by using non-advanced method & async 😄

Both fix for the original issue and support for injecting custom error logger are published under v1.1.0: