Reducing Boilerplate Error Handling in tTRPC + Effect
Hey all, I'm using tTRPC + Effect and have a lot of boilerplate error handling that will be identical between different functions because those functions could throw the same errors. Any ideas on how to DRY this up?
byLocationSlug: publicProcedure
.input((input) => v.parse(serviceByLocationSlugInput, input))
.query(
async ({ input }) =>
await tracer.startActiveSpan('router.services.location.slug', async (span) => {
try {
span.setAttributes({ 'location.slug': input.slug });
return await servicesForLocation(input).pipe(
Effect.provideLayer(DatabaseLive),
Effect.tap(() =>
Effect.sync(() => {
span.setStatus({ code: SpanStatusCode.OK });
}),
),
Effect.tapError((exception) =>
Effect.sync(() => {
span.setStatus({
code: SpanStatusCode.ERROR,
message: String(exception.error),
});
}),
),
Effect.tapDefect((defect) =>
Effect.sync(() => {
span.setStatus({ code: SpanStatusCode.ERROR, message: String(defect) });
}),
),
Effect.either,
Effect.catchAllDefect(Option.none),
Effect.runPromise,
);
} finally {
span.end();
}
}),
),byLocationSlug: publicProcedure
.input((input) => v.parse(serviceByLocationSlugInput, input))
.query(
async ({ input }) =>
await tracer.startActiveSpan('router.services.location.slug', async (span) => {
try {
span.setAttributes({ 'location.slug': input.slug });
return await servicesForLocation(input).pipe(
Effect.provideLayer(DatabaseLive),
Effect.tap(() =>
Effect.sync(() => {
span.setStatus({ code: SpanStatusCode.OK });
}),
),
Effect.tapError((exception) =>
Effect.sync(() => {
span.setStatus({
code: SpanStatusCode.ERROR,
message: String(exception.error),
});
}),
),
Effect.tapDefect((defect) =>
Effect.sync(() => {
span.setStatus({ code: SpanStatusCode.ERROR, message: String(defect) });
}),
),
Effect.either,
Effect.catchAllDefect(Option.none),
Effect.runPromise,
);
} finally {
span.end();
}
}),
),