-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Route and Group Middlewares #640
Comments
Hey, a middleware in /platform is simply a function |
Only
What if I wanted to set a header on an You say that it is possible already to apply it to an individual endpoint handler, can you provide a quick example on how to do this? Can the same be done with an |
I think this is what you meant by composition? const effectHttpApp = pipe(
RouterBuilder.make(api),
RouterBuilder.handle(getUserHandler),
RouterBuilder.build,
withMiddleware("middleware1"),
)
const router = HttpRouter.empty.pipe(
HttpRouter.mount("/r1", router1),
// Apply Middleware affecting all routes under /r1
HttpRouter.use(withMiddleware("M3")),
// Apply Middleware affecting all routes
HttpRouter.use(withMiddleware("M4")),
HttpRouter.mountApp('/r2', effectHttpApp)
)
router.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain) |
yeah, that's more or less what I meant, tho I didn't realised the import { HttpServerRequest } from "@effect/platform"
import { NodeRuntime } from "@effect/platform-node"
import { Schema } from "@effect/schema"
import { Effect, pipe } from "effect"
import { Api, Handler, RouterBuilder } from "effect-http"
import { NodeServer } from "effect-http-node"
const logUrlMiddleware = <A, E, R>(self: Effect.Effect<A, E, R>) =>
Effect.gen(function*(_) {
const request = yield* HttpServerRequest.HttpServerRequest
console.log(request.url)
return yield* self
})
const testEndpoint = Api.get("test", "/test").pipe(
Api.setResponseBody(Schema.String)
)
const testHandler = Handler.make(
testEndpoint,
() => Effect.succeed("test").pipe(logUrlMiddleware)
)
const api = Api.make().pipe(
Api.addEndpoint(testEndpoint)
)
const app = pipe(
RouterBuilder.make(api),
RouterBuilder.handle(testHandler),
RouterBuilder.build
)
app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain) |
If we're talking about /platform
Currently, there is no specific API for it. Tho, you can always do something like this. const rateLimit = (paths: ReadonlyArray<string>) =>
HttpMiddleware.make((app) =>
Effect.gen(function*(_) {
const request = yield* HttpServerRequest.HttpServerRequest
if (paths.some((path) => request.url.startsWith(path))) {
// do your stuff
}
return yield* app
})
)
const app = pipe(
RouterBuilder.make(api),
RouterBuilder.handle(...),
RouterBuilder.build,
rateLimit(["/test", "/another"])
) |
Based on the way I personally use this lib right now, I'm thinking about refactoring (or maybe getting rid of completely) the So I'm on the same page with you and the limitation you describe is result of the current design which tries too much to hide the underlaying /platform http details while it should rather try to build around it. |
Oh actually, I forgot there is RouterBuilder.mapRouter. Therefore, even in the current state, you can apply middlewares using this mapping and if you create multiple router builders, you can use middlewares more granularly. Router builders can be merged into a final one using RouterBuilder.merge. |
So I guess |
btw. maybe a bit off topic, but was I was splitting up my endpoints into groups, and was surprised that I had to use the full api spec to create partial The problem is that when testing individual groups, I had to implement the entire api, so instead of: NodeTesting.make(
RouterBuilder.build(groupRouterbuilder),
groupApiSpec,
) I had to do: NodeTesting.make(
RouterBuilder.build(ExampleServer.handleRemaining(groupRouterbuilder)),
groupApiSpec,
) |
The |
My point is that at type level it all worked with partial apis provided to partial builders but I got an error at runtime when running the merged router |
Ah, my bad, now I got it. For the router builder, it's not possible to recognise different Api instances on the type level so there is at least this runtime check in case of a miss-use. |
It would be great if one could create a partial router for given partial api, and then compose the partial apis and the partial routers. Currently the partial router seems like just a way of splitting implementation of the final larger api into multiple files, but the partial router on its own is not usable. |
@effect/platform allows middleware at the request, router and server level. It would be really neat to do the same here with ApiGroups or RouterBuilder.handle for an individual route
The text was updated successfully, but these errors were encountered: