effect-http
effect-http copied to clipboard
[QUESTION]: Adding Groups endpoints and Build Routes in a modular way
Issue Description:
Currently, there's a challenge regarding the modularity and scalability of routes within the presentation layer of the application, particularly when employing DDD (Domain-Driven Design). The goal is to enhance the architecture to better separate concerns and facilitate maintainability and extensibility.
To address this issue, we aim to refactor the code to achieve a more modular approach, allowing for greater flexibility and abstraction in handling routes.
there's a way to build the routes in a way to be modular with a native technique with Effect or there is a bit limitation for now of effect-http to do that? this is the structure of the folders 📦src ┣ 📂data-access ┃ ┗ 📜user.repository.ts ┣ 📂domain ┃ ┣ 📂user ┃ ┃ ┗ 📜user.model.ts ┃ ┗ 📜models.ts ┣ 📂entry-points ┃ ┣ 📜routes.ts ┃ ┗ 📜server.ts ┣ 📂presentation ┃ ┗ 📂user ┃ ┃ ┗ 📜user.route.ts ┣ 📂test ┃ ┗ 📜.gitkeep ┗ 📜env.ts
in order to be scalable and preserve the modularity i tried this way per example using DDD, having three layers, first the presentation layer, the domain layer and the data-layer, the main issue is in the presentation layer i need to pull up the implementation of the route away from the main pipe to run the effect
src/entry-points/server.ts
import { findAllUsers } from "@api-gateway-app/presentation/user/user.route";
import { NodeRuntime } from "@effect/platform-node";
import { Effect, Layer, LogLevel, Logger, pipe } from "effect";
import { RouterBuilder } from "effect-http";
import { NodeServer } from "effect-http-node";
import { PrettyLogger } from "effect-log";
import { AppRouter } from "./routes";
export const debugLogger = pipe(
PrettyLogger.layer(),
Layer.merge(Logger.minimumLogLevel(LogLevel.All))
)
pipe(
RouterBuilder.make(AppRouter, { docsPath: '/api', parseOptions: { errors: "all" } }),
RouterBuilder.handle("findAllUsers", ({ query }) => findAllUsers(query)), // ==== i want to move this handle away from
// the pipe ( the best i can do for now is this passing the callback with the implementation but isn't the goal )
RouterBuilder.build,
Effect.provide(debugLogger),
NodeServer.listen({ port: 3001 }),
NodeRuntime.runMain
)
src/entry-points/routes.ts
// this implementation of definition of the AppRouter is Ok because from here we
// can define from each scope int presentation layer in this case is user but can be
// added others scopes / collections
import { userApi } from "@api-gateway-app/presentation/user/user.route";
import { Api } from "effect-http";
export const AppRouter = Api.make({
title: "API Gateway",
servers: [{ url: "http://localhost:3001" }],
}).pipe(Api.addGroup(userApi));
import { Criteria, getPaginatedResponse } from "@api-gateway-app/domain/models";
import { User } from "@api-gateway-app/domain/user/user.model";
import { pipe } from "effect";
import { Effect } from "effect";
import { Api, ApiGroup, Security } from "effect-http";
// this is perfect because in the presentation layer we define the interface of the endpoint
export const userApi = pipe(
ApiGroup.make("Users", {
description: "All about Users",
}),
ApiGroup.addEndpoint(
ApiGroup.get("findAllUsers", "/api/users").pipe(
Api.setRequestQuery(Criteria),
Api.setResponseBody(getPaginatedResponse(User)),
Api.setSecurity(
Security.bearer({ name: "mySecurity", description: "test" })
),
)
)
);
// this is my concern and the ugly part (its working though) that only can
// export the callback of the implementation but no the actual implementation definition,
// this should be place the RouterBuilder.handle()
export const findAllUsers = (query: Criteria) => Effect.succeed({
data: [{ name: "mike", id: JSON.stringify(query) }],
cursor: "x",
hasMore: false,
});
there's a way to achieve this ? i'm new on Effect and I am very interested in learn and contribute on examples with TDD, DDD and monorepos with Effect
Thank you in advance!
Best regards,