I’m working on a server application and trying to make it as clean as possible, considering the patterns and principles of Clean Architecture. However, I’m not sure how to proceed with the controllers.
My idea would be to have a framework-agnostic controller, which is called by the Elysia router. Something like this:
export const signInRotuer = new Elysia().use(SignInControllerAdapter).post(
'/signin',
async ({ body, signInController }) => {
await signInController.handle(body);
}
);
This way I’d be handling all the controller validations outside of Elysia context, which seems the right think to do, since if I want to replace Elysia by another framework, I’ll have no problem doing so. My controller will work the same way.
But on Elysia docs, it’s explicitly said that it’s not recommended to create a separated controller because Elysia is a controller itself, and that would break the Single-Responsibility Principle. So my controller ended up being like this:
export const signInController = new Elysia().use(SignInUsecaseAdapter).post(
'/signin',
async ({ body, signIn }) => {
const { sessionId } = await signIn.invoke(body);
return new CreationSuccessResponse({
message: 'User logged in succesfully!',
sessionId,
});
},
{
body: t.Object({
email: t.String({
error: 'The email should be a string.',
}),
password: t.String({
error: 'The password should be a string.',
}),
}),
},
);
But I see some problems with that approach:
- It’s clearly way more coupled with Elysia
- It’s harder to test, since I’ll need to use an elysia instance on the testing. That makes the controllers the hardest entities to test so far, all the other entities are completely agnostic. Also it’s harder to mock and spy on the dependencies of that controller (SignIn usecase in this scenario).
- That schema validation forces me to define my models in Elysia first, and if I want an agnostic schema, I need to extract them from the Elysia schema. This schema validation is nice and I’d like to use it, but I want Elysia to validate the schemas based on the models defined in domain layer, not my models to be based on the Elysia schemas!
Therefore I would appreciate some opinions on this topic. This is also my first application where I’m applying clean architecture concepts, so I’m not fully confident on my approaches.
1