Um sistema back-end que estimula o reconhecimento entre companheiros de equipe através de elogios. Incrível, não ?! 😃
- Serviços e regras da Api
- Como construir esta aplicação em 21 passos?
- Árvore de diretórios
- Alguns comandos pela Cli typeorm
- Um pouco sobre termos utilizados
- Licença
-
Cadastro de usuário:
-[x] Não é permitido cadastrar mais de um usuário com o mesmo e-mail;
-[x] Não é permitido cadastrar um usuário sem e-mail;
-
Cadastro de Hashtag:
-[x] Não é permitido cadastrar mais de uma TAG com o mesmo nome;
-[x] Não é permitido cadastrar uma TAG sem nome;
-[x] Somente usuários cadastrados como administradores podem cadastrar TAGS
-
Cadastro de elogios:
-[x] Não é permitido um usuário cadastrar um elogio para si;
-[x] Não é permitido cadastrar elogios para usuários inválidos;
-[x] Para cadastrar um elogio, o usuário precisa estar cadastrado na aplicação;
-
Listagem de usuários
-
Listagem de Hashtags
-
Listagem de elogios por usuário
1. Iniciar um projeto com o comando: yarn init -y
2. Adicionar o TypeScript nas dependências com o comando: yarn add typescript -D
3. Inicializar o TypeScript com o comando: yarn tsc --init
4. Configurar o arquivo ts.config, conforme abaixo:
{
"strict": false,
"strictPropertyInitialization": false,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
5. Adicionar o Express nas dependências com o comando: yarn add express
6. Adicionar a biblioteca de tipagens de express nas dependências de desenvolvimento: yarn add @types/express -D
O código TypeScript precisa ser convertido para JavaScript para que o Node consiga interpreta-lo, para isso podemos seguir o passo 6 ou 8.
7. Converter de TypeScript para JavaScript com o comando: yarn tsc
.
Este comando irá converter o arquivo de TypeScript para JavaScript, e a partir deste novo arquivo .JS
poderá ser interpretado pelo node com o comando do passo 7.
8. Inicializar o arquivo com "node caminhoDoArquivo", exemplo:
node src/server.js
9. Para automatizar o processo anterior, pode ser instalada a biblioteca 'ts-node-dev' através do comando: yarn add ts-node-dev
10. No arquivo package.json, adicione um script denominado "start": "ts-node-dev caminhoDoArquivo". No meu caso o script fica da seguinte forma:
{
"scripts": {
"start": "ts-node-dev src/server.ts",
}
}
11. No terminal, execute o comando yarn start
. Daí o servidor será iniciado e será reiniciado automaticamente após uma alteração nos arquivos .ts
12. Instalar o ORM desejado e as dependências necessária para conexão/manipulação do banco de dados. Para este projeto, foi o utilizado o typeorm. Comandos para instalação:
yarn add typeorm
- ORMyarn add reflect-metadata
- Biblioteca para utilização de decorators.yarn add sqlite3
- Driver do banco de dados
Também pode ser instalado em um único comando, da seguinte forma: yarn add typeorm reflect-metadata sqlite3
13. Criar na raiz do projeto, um arquivo de configuração do banco de dados, denominado "ormconfig.json", com objeto abaixo:
{
"type": "sqlite",
"database":"src/database/database.sqlite",
"migrations":["src/database/migrations/*.ts"],
"entities":["src/entities/*.ts"],
"cli":{
"migrationsDir":"src/database/migrations",
"entitiesDir": "src/entities"
}
- Este arquivo define as configurações de conexão com o banco de dados e instrução para a cli buscar as migrations e entidades a serem executadas, ou criar as migrations e entidades.
- Para utilização de outros drivers como postgres, mysql, mongo, etc., se faz necessário informar outros dados, como:
{
"host": "localhost",
"port": 3306,
"username": "test",
"password": "test",
"database": "test"
}
14. No diretório database, crie um arquivo index.ts para iniciar a conexão com o bando de dados,da seguinte forma:
import { createConnection } from 'typeorm';
const connection = createConnection();
connection
.then(() => {
console.log('Conexão com o banco de dados foi estabelecida com sucesso.');
})
.catch(err => {
console.log('Não foi possível conectar à base de dados:', err);
});
Após, importe o database no arquivo principal do servidor, no meu caso "server.ts"
:
import './database'
15. Criar no package.json o script para executar comandos pela Cli do typeorm:
{
"scripts": {
"start": "ts-node-dev src/server.ts",
"typeorm": "ts-node-dev ./node_modules/typeorm/cli.js"
}
}
16. Criar a tabela no banco de dados pela migration, exemplo abaixo criando a tabela "tags":
import { MigrationInterface, QueryRunner, Table } from 'typeorm';
export class CreateTags1624500232566 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'tags',
columns: [
{
name: 'id',
type: 'uuid',
isPrimary: true
},
{
name: 'name',
type: 'varchar'
},
{
name: 'created_at',
type: 'timestamp',
default: 'now()'
},
{
name: 'updated_at',
type: 'timestamp',
default: 'now()'
}
]
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('tags');
}
}
17. Criar uma entidade para modelar a tabela, exemplo: Entidade Tag, da tabela tags
import { Entity,PrimaryColumn,Column,CreateDateColumn,UpdateDateColumn
} from 'typeorm';
import { Expose } from 'class-transformer';
import { v4 as uuid } from 'uuid';
@Entity('tags')
export class Tag {
@PrimaryColumn()
readonly id: string;
@Column()
name: string;
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
@Expose({ name: 'nameCustom' })
nameCustom(): string {
return `#${this.name}`;
}
constructor() {
if (!this.id) {
this.id = uuid();
}
}
}
18. Criar um repositório para a Entidade, exemplo de um repositório para a entidade Tag:
import { EntityRepository, Repository } from "typeorm";
import { Tag } from "../entities/Tag";
@EntityRepository(Tag)
export class TagsRepositories extends Repository<Tag>{}
19. Criar um serviço para executar verificações e consultas no banco de dados, exemplo:
import { getCustomRepository } from 'typeorm';
import { TagsRepositories } from '../repositories/TagsRepositories';
export class CreateTagService {
async execute(name: string) {
const tagsRepositories = getCustomRepository(TagsRepositories);
if (!name) {
throw new Error('This name is invalid');
}
const tagAlreadyExists = await tagsRepositories.findOne({name});
if (tagAlreadyExists) {
throw new Error("There is already a tag with this name");
}
const tag = tagsRepositories.create({
name
});
await tagsRepositories.save(tag);
return tag;
}
}
Ao importar o repositório da entidade, temos acesso aos métodos do Repository do typeorm,como no exemplo acima tagsRepositories.create()
, tagsRepositories.findOne()
,tagsRepositories.create()
.Além de vários outros métodos que podem ser consultados em : typeorm.io/repository-api
20. Criar um controller para receber os dados da requisição e utilizar o serviço criado, conforme o exemplo abaixo do serviço de criação de tag:
import { Request, Response } from 'express';
import { CreateTagService } from '../services/CreateTagService';
export class CreateTagController {
async handle(request: Request, response: Response) {
const { name } = request.body;
const createTagService = new CreateTagService();
const tag = await createTagService.execute(name);
return response.json(tag);
}
}
Note que o controller apenas recebe os dados pelo request.body
, daí executa o método .execute()
do serviço criado no item 19.
21. Criar as rotas e delegar a ela o serviço adequado, exemplo:
router.post(
'/tags/create',
ensureAuthenticated,
ensureAdmin,
createTagController.handle
);
ensureAuthenticated
e ensureAdmin
são middlewares, para realizar a autenticação através do jwt e verificar se o usuário é administrador, respectivamente.
And Finish 🎉🎉
E é basicamente isso. Literalmente o básico, mas acredito que pode ser de ajuda para alguém !
Criação e versionamento de tabelas
Modelo de uma tabela do banco de dados
Veja uma explicação completa em: typeorm.io/#/entities
Classe responsável por se comunicar com o banco. Intermedia a conexão com o banco de dados e executa as querys, através da extensão da classe Repository do typeorm.
Veja uma explicação completa em: typeorm.io/#/custom-repository
Responsável por receber os dados da requisição e enviar para o service.
Responsável por executar todas as operações e verificações para a requisição.
Interceptador de requisições e realiza os tratamentos necessários, como por exemplo: Autenticação de usuário.
Veja uma explicação completa em: expressjs.com/pt-br/guide/using-middleware.html
- GET :
Requisição de dados.
- POST :
Inserção de dados.
src
├── /@types
└── /controllers
└── /database
| └── /migrations
| └── index
└── /entities
└── /middlewares
└── /repositories
└── /services
└── routes
└── server
- Criar migrations:
yarn typeorm migration:create -n nomeDaMigration
- Executar migrations:
yarn typeorm migration:run
*Desfazer a última migration:
yarn typeorm migration:revert
- Criar entidades:
yarn typeorm entity:create -n nomeDaEntidade
Outros comandos podem ser consultados no terminal da seguinte forma: yarn typeorm -help
Esse projeto está sob a licença MIT. Acesse opensource.org/licenses/MIT para mais detalhes.
Realizado com a RocketSeat !