Drive server WIP is the new API to Drive based on NestJS and following Clean Architecture and DDD(Domain Driven Design).
-
Yarn
npm i -g yarn
- Create a
.npmrc
file from the.npmrc.template
example provided in the repo. - Replace
TOKEN
with your own Github Personal Access Token withread:packages
permission ONLY - Use
yarn
to install project dependencies.
Run yarn start
to start server in production mode.
Run yarn start:dev
to start with nodemon and development environment.
With docker-compose:
docker-compose up
You can run unit tests with:
yarn run test
Running e2e test requires creating a database first (check .env.test file), and having a mariadb instance running.
yarn run test:e2e
This project is based on NestJS and implements DDD (Domain Driven Design). Our implementation has these layers:
- Use cases
- Persistence
- Domain
- Controllers
The project has these main folders
- Modules
- Externals
- Config
- Middlewares
- Lib
In this folder we have all "use cases" or "context" where the business logic and the controllers (to respect Nest architecture) are located:
- Module: files with
*.module.ts
- Use Cases: files with
*.usecase.ts
- Controllers: files with
*.controller.ts
- Domain: files with
*.domain.ts
- Repository: files with
*.repository.ts
As an example, a 'file' module would be src/modules/file
:
- Controllers:
file.controller.ts
Endpoints for exposing the business logic of the file module. - Use Cases:
file.usecase.ts
Contains all the use-cases that are related to the file domain: moving a file, removing a file, etc. - Domain:
file.domain.ts
Class File, all attributes and business logic are here, but we do not include anything about persistence or use cases. - Repository:
file.repository.ts
File that contains the interface that defines the signature of the methods to persist data and all the concrete implementations of this persistence (MariaDB, Redis..) - Module:
file.module.ts
Nest.js module
Based on Nest.js Controllers. Contains endpoints for exposing the business logic of the module.
Domain is an agnostic "entity" with the properties and the business logic, including global functionality to this domain. The domain does not persist the information , just changes the entity according to the situation.
Example of the File domain
# file.domain.ts
export class File implements FileAttributes {
fileId: number;
deleted: boolean;
deletedAt: boolean;
bucket: string;
constructor({...}){
...
}
moveToTrash() {
this.deleted = true;
this.deletedAt = new Date();
}
moveTo(bucket) {
if(this.bucket === bucket) {
throw Error('you cannot move file to this directory')
}
this.bucket = bucket;
}
}
The use case is a function that includes a real functional use case from the business model. To identify use cases we can use: "As User, I want ... for ... Example: "As Web User, I want to move files to trash for delete them later"
How to code a use case?
- Use a repository if there is a need to get any information from the entity in the database, the repositories should always return the entity of a domain.
- Update any properties of a domain or call functions with a business-logic. Ex: File.moveToTrash()
- Persist changes using a repository.
Example of use case:
# file.usecase.ts
export class FileUsecase {
constructor(private fileRepository: FileRepository) {}
async moveToTrash(fileId) {
const file = await this.fileRepository.findOne({ fileId });
if(!file) {
throw new Error('file not found');
}
file.moveToTrash();
await this.fileRepository.update(file);
return file;
}
async moveTo(fileId, destination) {
const file = await this.fileRepository.findOne({ fileId });
if(!file) {
throw new Error('file not found');
}
file.moveTo(destination);
await this.fileRepository.update(file);
return file;
}
}
The repository is part of the persistence layer.
A repository commonly has a model and a CRUD to interact with the entities of any concrete persistence implementation. The repository always returns an entity domain or a collection of them, so a repository should have adapters to parse from the model to the entity domain and viceversa.
Information about the repository pattern could be found here.
This folder contains third-party dependencies and external services whose usage could be necessary but it is not business-related.
This structure is based on modules
structure of Nest.js.
A module can be found here if:
- Is an external API gateway.
- Is a bunch of logic that provides some 'service', as a cryptography service, a notifications service and any other logic that could be commonly found on generic folders like
utils
,helpers
, etc. But grouped by a context. For instance:encryptText()
-> CryptoServicesendAnalytics()
-> AnalyticsServiceparseStringToDate()
-> StringService
This folder contains config files for the app.
This folder includes middlewares of any kind. You can find documentation about middlewares in Nest.js.
In this folder include only libraries to server HTTP and Nest.js
We use Swagger, which can be found up and running at /api
endpoint via HTTP. You can find documentation of how to use it with Nest.js here.
This project is based on GNU License. You can show it in the License file.