Effect CommunityEC
Effect Community14mo ago
2 replies
jakubryska

Adding Error Verification for API Handlers in Effect Typescript Library

Hi, would be good if there were an option to verify that all reported errors are being thrown in the handler. In this way, the api won't report errors that are then not being used in the handler. I created some helper code for that, is there some existing way how to do this?

api:
  .add(
    HttpApiEndpoint.get('abc', '/abc')
      .addSuccess(HttpApiSchema.NoContent)
      .addError(DataNotAvaiable)
      .addError(EndpointNotImplementedError)
  )

handler:
    handlers.handle('abc', () => Effect.succeed(null) )

this will compile just fine even though no error is being thrown, because type of R in handler is a subtype of type of R in api

If I use helper that I created:
    handlers.pipe(
      handleExact('abc', () =>
        Effect.gen(function* () {
          if (Math.random() > 0.5) {
            return yield* new EndpointNotImplementedError();
          }
          if (Math.random() > 0.5) {
            return yield* new DataNotAvaiable();
          }
          return;
        }),
      ),
    )

then if I wouldn't throw any of those errors, then I would get compile error.

Implementation of the .handleExect helper:
type Result<Handler, DeclaredErrors, Returns> = Handler extends (
  request: any,
) => Effect.Effect<any, infer ActualErrors, any>
  ? [DeclaredErrors] extends [ActualErrors] // <-- the actual check
    ? Returns
    : never
  : never;

export const handleExact =
  <
    E,
    Provides,
    R,
    Endpoints extends HttpApiEndpoint.Any,
    Name extends HttpApiEndpoint.Name<Endpoints>,
    R1,
    Handler extends HttpApiEndpoint.HandlerWithName<Endpoints, Name, E, R1>,
  >(
    name: Name,
    handler: Handler,
  ) =>
  (
    handlers: HttpApiBuilder.Handlers<E, Provides, R, Endpoints>,
  ): Result<
    Handler,
    H.HttpApiEndpoint.Error<H.HttpApiEndpoint.WithName<Endpoints, Name>>,
    ReturnType<typeof handlers.handle<Name, R1>>
  > => {
    // @ts-ignore
    return handlers.handle(name, handler);
  };
Was this page helpful?