Summary
HttpRouter.toWebHandler's layer parameter is constrained to
Layer.Layer<A, E, R> with R extends HttpRouter | Request<"Requires", any> | Request<"GlobalRequires", any> | Request<"Error", any> | Request<"GlobalError", any>.
Layers produced by HttpApiBuilder.layer(api) (with handler groups provided) also carry the platform services that toWebHandler itself provides at runtime — FileSystem, HttpPlatform, Path, Generator — in their input channel. Those members are not assignable to the R constraint, so a handler layer that is perfectly valid at runtime is rejected at the type level, and every HttpApi-on-web-handler composition needs a requirements-channel cast.
Reproduction (effect@4.0.0-beta.101)
import { HttpRouter } from "effect/unstable/http"
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"
import * as Layer from "effect/Layer"
import * as Effect from "effect/Effect"
import * as Schema from "effect/Schema"
const Api = HttpApi.make("api").add(
HttpApiGroup.make("g").add(
HttpApiEndpoint.get("hello", "/", { success: Schema.String })
)
)
const Handlers = HttpApiBuilder.group(Api, "g", (handlers) =>
handlers.handleAll({ hello: () => Effect.succeed("hi") })
)
const layer = HttpApiBuilder.layer(Api).pipe(Layer.provide(Handlers))
// Type error: the layer's input channel includes FileSystem | HttpPlatform |
// Path | Generator (plus HttpRouter/Request phantoms), which the R constraint
// rejects — even though toWebHandler provides those services at runtime.
const { handler } = HttpRouter.toWebHandler(layer)
Error shape (abbreviated):
Argument of type 'Layer<..., ..., HttpRouter | Request<"GlobalError", unknown> |
Exclude<... FileSystem | Generator | HttpPlatform | Path ...>>' is not
assignable to parameter of type 'Layer<..., ..., never>'
Ask
Widen toWebHandler's R constraint (or Exclude the provided platform services from the input before constraining) so HttpApi handler layers typecheck without a cast. Currently the practical workaround is:
HttpRouter.toWebHandler(layer as Layer.Layer<unknown, E, never>)
centralized behind one sanctioned helper — it would be great to delete it.
Summary
HttpRouter.toWebHandler's layer parameter is constrained toLayer.Layer<A, E, R>withR extends HttpRouter | Request<"Requires", any> | Request<"GlobalRequires", any> | Request<"Error", any> | Request<"GlobalError", any>.Layers produced by
HttpApiBuilder.layer(api)(with handler groups provided) also carry the platform services thattoWebHandleritself provides at runtime —FileSystem,HttpPlatform,Path,Generator— in their input channel. Those members are not assignable to theRconstraint, so a handler layer that is perfectly valid at runtime is rejected at the type level, and every HttpApi-on-web-handler composition needs a requirements-channel cast.Reproduction (
effect@4.0.0-beta.101)Error shape (abbreviated):
Ask
Widen
toWebHandler'sRconstraint (orExcludethe provided platform services from the input before constraining) so HttpApi handler layers typecheck without a cast. Currently the practical workaround is:centralized behind one sanctioned helper — it would be great to delete it.