Closed Almaju closed 1 month ago
When using a service inside a custom Security, it becomes a requirement of the client endpoint although it should be only used on the server side.
Look below how the effect has the type: Effect.Effect<string, ClientError<number>, UserStorage>
Effect.Effect<string, ClientError<number>, UserStorage>
import { Schema } from '@effect/schema'; import { Effect, Layer, pipe } from 'effect'; import { Api, ApiEndpoint, Client, Middlewares, RouterBuilder, Security, } from 'effect-http'; interface UserInfo { email: string; } class UserStorage extends Effect.Tag('UserStorage')< UserStorage, { getInfo: (user: string) => Effect.Effect<UserInfo> } >() { static dummy = Layer.succeed( UserStorage, UserStorage.of({ getInfo: (_: string) => Effect.succeed({ email: 'email@gmail.com' }), }), ); } const mySecurity = pipe( Security.basic({ description: 'My basic auth' }), Security.map((creds) => creds.user), Security.mapEffect((user) => UserStorage.getInfo(user)), ); const api = Api.make().pipe( Api.addEndpoint( Api.post('endpoint', '/my-secured-endpoint').pipe( Api.setResponseBody(Schema.String), Api.setSecurity(mySecurity), ), ), ); const app = RouterBuilder.make(api).pipe( RouterBuilder.handle('endpoint', (_, security) => Effect.succeed(`Logged in`), ), RouterBuilder.build, Middlewares.errorLog, ); const client = Client.make(api); // BAD: Effect.Effect<string, ClientError<number>, UserStorage> const effect = client.endpoint({});
I have written a quick type helper as a workaround:
type ApiClient<T> = T extends Api.Api<infer Endpoints> ? Api.Api<MapEndpoints<Endpoints>> : never; type MapEndpoints<T> = T extends ApiEndpoint.ApiEndpoint< infer Endpoint, infer Req, infer Resp, Security.Security<infer A, infer E, unknown> > ? ApiEndpoint.ApiEndpoint< Endpoint, Req, Resp, Security.Security<A, E, never> > : never; const client = Client.make(api as ApiClient<typeof api>); // GOOD: Effect.Effect<string, ClientError<number>, never> const effect = client.endpoint({});
I will try to do a PR when I find the time.
Nice catch! I'll take a look.
When using a service inside a custom Security, it becomes a requirement of the client endpoint although it should be only used on the server side.
Look below how the effect has the type:
Effect.Effect<string, ClientError<number>, UserStorage>
I have written a quick type helper as a workaround:
I will try to do a PR when I find the time.