Closed jrovira-kumori closed 3 months ago
Hey, interesting use-case. I don't think this is something we'd like to support because the aim for this lib is to be as type safe as possible. For this use-case with feature flags, I'd create the selected endpoints the usual way and deal with the allowance in the endpoint handlers. That way you can add a documentation to the OpenAPI explaining the endpoint is behind a feature flag and in case the feature flag is off, you can return meaningful info about in the HTTP response.
Tho, if you really need something like this, you can fallback to the raw @effect/platform
. Be aware that this way, the /another
endpoint won't be part of the Api spec, so while the endpoint will be available it won't be documented in the OpenAPI and it won't be part of generated mock client, example server, client, etc.
import { HttpServer } from "@effect/platform"
import { NodeRuntime } from "@effect/platform-node"
import { Effect, identity } from "effect"
import { Api, RouterBuilder } from "effect-http"
import { NodeServer } from "effect-http-node"
export const api = Api.make().pipe(
Api.addEndpoint(
Api.post("test", "/test")
)
)
const myFlag = false
const addGetAnother = HttpServer.router.get("/another", HttpServer.response.json("hello there"))
const app = RouterBuilder.make(api).pipe(
RouterBuilder.handle("test", () => Effect.unit),
RouterBuilder.mapRouter(myFlag ? addGetAnother : identity),
RouterBuilder.build
)
app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain)
I see. Thank you for the quick response!
@sukovanej I have been trying to implement a handle
function similar to RouterBuilder.handle()
so I can handle the case when the flag is not defined without having to modify the original function. Perhaps short-circuiting with a 404 or any other arbitrary behaviour.
It escapes me how to specify the appropriate types for this middleware-like function and I cannot find anything similar in the docs. Any pointers would be greatly appreciated.
RouterBuilder.build
returns HttpServer.app.Default<R | SwaggerFiles, E>
so from the point you build your application you can do whatever you like using the @effect/platform
primitives. I'm sorry this is not properly documented. I think the official platform package will have its place in the official effect docs at some point, so I won't probably cover these parts in this project but I'll try to document how the effect platform is used so that the usage of e.g. middlewares is more obvious - note taken 👍 .
Anyway, you can do something like this.
import { HttpServer } from "@effect/platform"
import { NodeRuntime } from "@effect/platform-node"
import { Effect } from "effect"
import { Api, RouterBuilder } from "effect-http"
import { NodeServer } from "effect-http-node"
export const api = Api.make().pipe(
Api.addEndpoint(Api.post("test", "/test")),
Api.addEndpoint(Api.get("another", "/another"))
)
const disablePaths = (disabledPaths: ReadonlyArray<string>) =>
HttpServer.middleware.make((app) =>
Effect.gen(function*(_) {
const request = yield* _(HttpServer.request.ServerRequest)
if (disabledPaths.includes(request.url)) {
return yield* _(HttpServer.response.text("path disabled", { status: 404 }))
}
return yield* _(app)
})
)
const app = RouterBuilder.make(api).pipe(
RouterBuilder.handle("test", () => Effect.unit),
RouterBuilder.handle("another", () => Effect.unit),
RouterBuilder.build,
disablePaths(["/another"])
)
app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain)
Thank you very much! I was looking at the @effect/platform
docs without success. This will work great.
I am opening this issue to ask if it is possible to register endpoints conditionally. I have been unsuccessfully looking around for a way to do this and I am beginning to think it is not possible.
Referenced code can be found @
jrovira-kumori/http-effect-optional-endpoint
.Attempt 1
Trying to add a ternary condition when defining the API with
process.env.SOME_FEATURE_FLAG ? ... : e => e
produces a runtime error when running withnpm run serve
.Details
```text Error: Operation id optional not found at getRemainingEndpoint (http-effect-repro/node_modules/effect-http/dist/cjs/internal/router-builder.js:77:11) at http-effect-repro/node_modules/effect-http/dist/cjs/internal/router-builder.js:82:20 at pipe (http-effect-repro/node_modules/effect/dist/cjs/Function.js:352:17) at Object.Attempt 2
Also adding a ternary condition when defining the API with
process.env.SOME_FEATURE_FLAG ? ... : e => e
produces a compilation error building withnpm run build
.Details
```text index.ts:19:5 - error TS2345: Argument of type '