In Part 1 of this article, we’ve created a small GraphQL server. We’ll now introduce Clean Architecture so the project will be easier to maintain.

Why Clean Architecture?

Clean Architecture is not the easiest architecture. If you’re looking for an architecture for a small project, it’s probably not the best choice.

But if your project starts to become bigger (when the number of resolvers or the data sources is increasing or when you start to struggle unit testing your business logic) then Clean Architecture is what you’re looking for.

Clean Architecture has very good aspects like:

Independent of Frameworks

This means it will work whatever the kind of project you’re working on (GraphQL server, REST server, front-end web app, mobile application, etc..)

Dependency Rules

This aspect means the outer layers depend on the inner ones, but never the opposite. Why? The inner layers represent the core of your business, so the code shouldn’t evolve often. The outer layers tend to have dependencies so the code could evolve as much as needed without impacting the business logic.

Layer Isolation

This allows you to change a component with a minimum of changes (ex: change your DB, pass from a REST API to GraphQL API, etc…)

For more information about Clean Architecture, you can read the original article from Uncle Bob: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

Implementation of Clean Architecture on a GraphQL server

Disclaimer:
There’s no strict implementation of Clean Architecture.
The following code is one implementation of it, don’t hesitate to have a critic look on it and implement it by yourself.

So, let’s rework a bit our previous GraphQL server example to implement Clean Architecture.

We have to split each resolver into 3 layers:

UseCase

The UseCase will manage the business logic. It should be isolated from the incoming request (it should work the same for a REST or GraphQL server). And isolated from the services (it should work wherever the data is coming: MySQL, Cassandra, SQLite, etc…).

You can see the UseCase receives an output callback instead of returning the value. This is to respect the Inversion Of Control principle.
You can see the output callback as a Presenter.

Controller

The Controller will map the incoming request into the domain model.
And it should also serialize the response (sometimes, this function is handled by a separate component — sometimes named Presenter).

The Controller calls the UseCase, then returns the output as a Promise.

Service

The service has access to external dependencies such as DB, HTTP API, file storage, etc…

It must provide an interface for the UseCase to access, modify, delete the data without having to depend on the data source implementation.

In this example, the data is stored in an in-memory array; but obviously, you can implement any DB access here.

Note:
In some clean architecture implementation, a Repository layer is placed between the UseCases and the Service. The Repository will manage where the data should be fetched (in-memory cache, DB, remote).
In this example, there’s only 1 datasource; so I chose to not use a Repository.
It’s up to you to decide if you need it or not.

Conclusion

Now, we’ve implemented a Clean Architecture GraphQL server.
Thanks to the layer isolation and dependency injection, it is very easy to add unit tests.

But, Clean Architecture is maybe a bit verbose, we created a lot of classes and we could think it’s maybe too much.
In the next and last step, we’ll see how Functional Programming can help us reduce verbosity.

Source code

--

--