nats-micro
Version:
NATS micro compatible extra-lightweight microservice library
104 lines (88 loc) • 2.91 kB
text/typescript
import { ZodError } from 'zod';
// eslint-disable-next-line import/no-cycle
import { callHandler } from './callHandler.js';
import { errorToString } from './misc.js';
import { addContextHeadersToThreadContext, threadContext } from './threadContext.js';
import { Broker } from '../broker.js';
import { debug } from '../debug.js';
import { Handler, MessageHandler, MicroserviceHandlerInfo } from '../types/index.js';
export function wrapMethodSafe<T, R>(
broker: Broker,
callback: Handler<T, R>,
handlerInfo: MicroserviceHandlerInfo<T, R>,
): MessageHandler<T> {
return async (msg, subject) => {
try {
const store = new Map();
threadContext.enterWith(store);
let input = msg.data;
if (handlerInfo.methodConfig.request) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((handlerInfo.methodConfig.request._def as any).typeName === 'ZodVoid')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
input = undefined as any;
else
try {
input = handlerInfo.methodConfig.request.parse(input);
}
catch (err) {
if (err instanceof ZodError) {
throw new Error(`Error parsing request fields: ${err.issues.map((i) => `${i.path.join('.')} (${i.message})`).join(', ')}`);
}
throw err;
}
}
addContextHeadersToThreadContext(msg.headers);
debug.ms.thread.debug(`Executing safe ${handlerInfo.method}(${JSON.stringify(msg.data)})`);
const output = await callHandler(
callback,
input,
subject,
msg.headers ?? [],
handlerInfo,
);
if ((typeof (output.data) !== 'symbol') && 'replyTo' in msg && msg.replyTo) {
if (handlerInfo.methodConfig.response) {
try {
output.data = handlerInfo.methodConfig.response.parse(output.data);
}
catch (err) {
if (err instanceof ZodError)
throw new Error(`Invalid response type: ${err.issues.map((i) => i.message).join(',')}`);
else
throw err;
}
}
broker.send(
msg.replyTo,
output.data,
{
headers: output.headers,
},
);
}
}
catch (err: unknown) {
const error = errorToString(err);
debug.error(error);
if ('replyTo' in msg && msg.replyTo) {
const headers: [string, string][] = [
...(
(typeof (err) === 'object') && err && ('status' in err)
? [['X-Error-Status', String(err.status)] as [string, string]]
: []
),
['X-Error-Message', error],
];
broker.send(
msg.replyTo,
'ERROR',
{
headers,
},
);
}
// throw err;
}
};
}