Este projeto contém um exemplo de arquitetura e organização de código para desenvolvimento em Node.Js
- Criar uma pasta com o nome do projeto
- Executar o comando
yarn init -y
- Instalar o node express
yarn add express
e seus tiposyarn add @types/express -D
- Instalar o typescript
yarn add typescript -D
- Executar o comando
yarn tsc --init
para criar o arquivotsconfig.json
- No arquivo
tsconfig.json
colar a seguinte configuração:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"rootDir": "./",
"baseUrl": "./src",
"outDir": "./dist",
"paths": {
"@modules/*": ["modules/*"],
"@config/*": ["config/*"],
"@shared/*": ["shared/*"],
"@errors/*": ["errors/*"],
"@utils/*": ["utils/*"]
},
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
}
}
- Criar a seguinte estrutura de pastas:
. ├── ... ├── src │ ├── @types │ ├── config │ ├── modules │ └── shared │ │ └── container │ │ │ └── providers │ │ ├── errors │ │ └── infra #Camadas externa como framework de banco, envio de e-mail, etc │ │ │ └── http │ │ │ │ ├── middlewares │ │ │ │ └── routes └── ...
A pasta modules
corresponde aos contextos do projeto, por exemplo o contexto users
utilizado para criação de usuários e autenticação:
. │ ├── modules │ │ └── users │ │ | ├── dtos │ │ | ├── entities │ │ | ├── repositories │ │ │ └── useCases | │ │ │ ├── authenticateUser | │ │ │ └── createUser └── ...
- Dentro da pasta
infra/http/routes
criar o arquivoindex.ts
que será responsável por
import { Router } from "express";
import { authenticateRoutes } from "./authenticate.routes";
const router = Router();
router.use(authenticateRoutes);
export { router };
- Dentro de
infra/http
criar o arquivoapp.ts
eserver.ts
app.ts
import express from "express";
import { router } from "./routes";
const app = express();
app.use(express.json());
app.use(router);
export { app };
server.ts
import { app } from "./app";
app.listen(3333, () => console.log("Server is running!"));
- Instalar a biblioteca
yarn add express-async-errors
- Na pasta
errors
criar o arquivoAppError.ts
export class AppError {
public readonly message: string;
public readonly statusCode: number;
constructor(message: string, statusCode = 400) {
this.message = message;
this.statusCode = statusCode;
}
}
- No arquivo
server.ts
adicionar o middleware de erro:
import "express-async-errors";
...
app.use(
(
error: Error,
_request: Request,
response: Response,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_next: NextFunction
) => {
if (error instanceof AppError) {
return response.status(error.statusCode).json({
message: error.message,
});
}
return response.status(500).json({
status: "error",
message: `Internal server error - ${error.message}`,
});
}
);
- Instalar a biblioteca
tsyringe
conforme documentação - Dentro da pasta
shared\container
criar um arquivoindex.ts
para registrar os repositórios conforme exemplo:
import { container } from "tsyringe";
import { IProfilesRepository } from "@modules/profiles/repositories/IProfilesRepository";
import { ProfilesRepository } from "@modules/profiles/repositories/ProfilesRepository";
import { IUsersRepository } from "@modules/users/repositories/IUsersRepository";
import { UsersRepository } from "@modules/users/repositories/UsersRepository";
container.registerSingleton<IUsersRepository>("UsersRepository", UsersRepository);
container.registerSingleton<IProfilesRepository>("ProfilesRepository", ProfilesRepository);
- Cada
useCase
deverá receber a anotação@injectable()
acima da declaração da classe assim como cada repositório utilizado no construtor deve receber@inject("name_repository")
, conforme exemplo:
...
@injectable()
class AuthenticateUserUseCase {
constructor(
@inject("UsersRepository")
private usersRepository: IUsersRepository
) {}
...
}
- Na
controller
se obtém a instância dauseCase
utilizando o métodoresolve
da seguinte maneira:
import { Request, Response } from "express";
import { container } from "tsyringe";
import { AuthenticateUserUseCase } from "./AuthenticateUserUseCase";
class AuthenticateUserController {
async handle(request: Request, response: Response): Promise<Response> {
const { password, email } = request.body;
const authenticateUserUseCase = container.resolve(AuthenticateUserUseCase);
const token = await authenticateUserUseCase.execute({
password,
email,
});
return response.json(token);
}
}
export { AuthenticateUserController };
- Instalar a biblioteca
yarn add ts-node-dev tsconfig-paths -D
- No arquivo
package.json
adicionar o elemento script abaixo:
"scripts": {
"dev": "ts-node-dev -r tsconfig-paths/register --inspect=0.0.0.0:9229 --transpile-only --ignore-watch node_modules --respawn --poll src/shared/infra/http/server.ts"
},