Clean Architecture Example
This repository tries to apply concepts from Clean Architecture in NestJS.
- Nest is the framework used to tie everything together.
- Docker is the runtime for for local development.
- MongoDB is the database provider for the environment.
# Create an environment file
$ cp .env.template .env
# Start the applications (database and app)
$ docker compose up -d
# Inspect logs
$ docker logs -f zen-banks-api
# Cleanup
$ docker compose down -v
- Add logging
- Add authentication
- Add unit tests
- Add e2e tests
This layer contains application entities, which represent business rules in their most natural and atomic form. They don't know anything about the external world, not even about the use cases where they are applied. These models don't do any external communication or work, but they signal whatever might be done to the use case layer. This layer also contains errors, aka domain errors.
Together with the domain, these are the core of our application. This layer orchestrations everything that happens in the application and is not allowed to reference the external world.
In this layer we have the actual use case handlers, which are orchestrators. We also have use case specific models and abstractions which are essential to prevent this layer from knowing anything external. In order for anything from the external world to be used in the Use Case, they need to implement the contracts existing in abstractions which will be swapped via Dependnecy Injection in runtime.
This layer provides two central units of work to our use cases. They are the repositories, which provide strucutred and semi-strucutred data acess to the use cases and services which provide any other form of abstraction to the use cases. These can only be exposed in the use cases through the implementation of an abstraction from the Application Layer.
This is where the framework lives. Entrypoints and any raw validators exist within this layer. Some of its artifacts are Controllers, Resolvers, Validators, Guards, Interceptors and Models. It's the layers that exposes your application to the outside world or trigger whatever it is that our service does.
These are IO drivers, they are the very first layer of defence between our system and the outside world. A provider can be an http client, an external service client or a database model mapping for data access. They stand in front of your system and the world and will be adapted in the adapter layer in order to be used within the use cases.
Central to the service itself, these provide any sort of configuration that's needed. It's no man's land, everything is allowed here.
Core: (Can only depend on the artifacts within core)
Domain -> {Domain} `domain is the most internal, depends only on itself`
Application -> {Application|Domain|Abstractions} `Business orchestrator`
Infra:
Adapters(ACL) -> {Adapters|Application|Domain|Abstractions} `ensures external providers respect domain contracts`
Presentation -> {Presentation|Application|Abstractions} `exposes application to the world, inbound, entrypoints`
Providers -> {ExternalProviders|SDKs|Clients|etc.} `protect the system from the outbound world`
Config -> {Config|Libs|etc.} `any manner of configuration that's needed`