-
-
Notifications
You must be signed in to change notification settings - Fork 531
Open
Labels
bugSomething isn't workingSomething isn't working
Description
What version of Effect is running?
3.19.18
What steps can reproduce the bug?
It seems like middleware is being ignored entirely under certain conditions.
This is as minimally I could reproduce the issue:
import { createServer } from "node:http";
import {
HttpApi,
HttpApiBuilder,
HttpApiEndpoint,
HttpApiError,
HttpApiGroup,
HttpApiMiddleware,
HttpApiSecurity,
HttpLayerRouter,
} from "@effect/platform";
import { NodeHttpServer, NodeRuntime } from "@effect/platform-node";
import { Context, Effect, Layer, Schema } from "effect";
export class Session extends Context.Tag("app/Session")<
Session,
{
id: string;
}
>() {}
class InternalAuthorization extends HttpApiMiddleware.Tag<InternalAuthorization>()(
"InternalAuthorization",
{
failure: HttpApiError.Unauthorized,
provides: Session,
security: {
apiKey: HttpApiSecurity.bearer,
},
}
) {}
const externalApi = HttpApi.make("external-api").add(
HttpApiGroup.make("Posts")
.add(
HttpApiEndpoint.get("posts", "/")
.addSuccess(Schema.String)
.addError(HttpApiError.BadRequest)
)
.prefix("/posts")
);
const internalApi = HttpApi.make("internal-api")
.add(
HttpApiGroup.make("Customers")
.add(
HttpApiEndpoint.get("customers", "/").addSuccess(
Schema.Array(Schema.String)
)
)
.prefix("/customers")
)
.add(
HttpApiGroup.make("Users")
.add(
HttpApiEndpoint.get("users", "/").addSuccess(
Schema.Array(Schema.String)
)
)
.prefix("/users")
)
.middleware(InternalAuthorization);
const InternalAuthorizationLive = Layer.succeed(InternalAuthorization, {
apiKey: () => Effect.fail(new HttpApiError.Unauthorized()),
});
const PostsLive = HttpApiBuilder.group(externalApi, "Posts", (handlers) =>
handlers.handle("posts", () => Effect.succeed("ok"))
);
const CustomersLive = HttpApiBuilder.group(
internalApi,
"Customers",
(handlers) =>
handlers.handle(
"customers",
Effect.fnUntraced(function* () {
const session = yield* Session;
return ["customer1", "customer2", session.id];
})
)
);
const UsersLive = HttpApiBuilder.group(internalApi, "Users", (handlers) =>
handlers.handle("users", () => Effect.succeed(["user1", "user2"]))
);
const ExternalRoutes = HttpLayerRouter.addHttpApi(externalApi).pipe(
Layer.provide([PostsLive])
);
const InternalRoutes = HttpLayerRouter.addHttpApi(internalApi).pipe(
Layer.provide([UsersLive, CustomersLive]),
Layer.provide(InternalAuthorizationLive)
);
const Routes = Layer.mergeAll(ExternalRoutes, InternalRoutes);
const HttpLive = HttpLayerRouter.serve(Routes).pipe(
Layer.provide(NodeHttpServer.layer(createServer, { port: 3001 }))
);
NodeRuntime.runMain(Layer.launch(HttpLive));
I would then hit the internal API:
curl -i http://localhost:3001/users
What is the expected behavior?
The users endpoint should be protected by the internal authorization middleware. Expected status code 401.
What do you see instead?
⨯ curl -i http://localhost:3001/users
HTTP/1.1 200 OK
content-type: application/json
content-length: 17
Date: Wed, 11 Mar 2026 15:41:16 GMT
Connection: keep-alive
Keep-Alive: timeout=5
["user1","user2"]
Additional information
Hitting the customers endpoint defects due to "Service not found: app/Session".
Applying the middleware to the group or route instead of the http api results in another unexpected response of 500 Internal Server Error.
@effect/platform: 0.94.5
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working