Utilizamos cookies para ajudá-lo a navegar com eficiência e executar determinadas funções. Você encontrará informações detalhadas sobre todos os cookies em cada categoria de consentimento abaixo.
Os cookies categorizados como “Necessários” são armazenados no seu navegador, pois são essenciais para ativar as funcionalidades básicas do site.
Também utilizamos cookies de terceiros que nos ajudam a analisar como você usa este site, armazenam suas preferências e fornecem conteúdo e anúncios que são relevantes para você. Estes cookies só serão armazenados no seu navegador com o seu consentimento prévio.
Você pode optar por ativar ou desativar alguns ou todos esses cookies, mas a desativação de alguns deles pode afetar sua experiência de navegação.
Necessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.
Functional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.
Performance cookies are used to understand and analyse the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Advertisement cookies are used to provide visitors with customised advertisements based on the pages you visited previously and to analyse the effectiveness of the ad campaigns.
Neste artigo, vamos aprender a criar um CRUD básico com NestJS, GraphQL e MySQL.
Entretanto, antes de qualquer coisa, vamos entender o conceito de todos esses frameworks? Então, vamos lá!
Segundo a documentação, NestJS é:
Nest (NestJS) é mais um framework, voltado principalmente para construção de aplicações Node.js para
servidores Back-end. Dessa forma, uma das vantagens de se usar o NestJS é a alta escalabilidade do lado do servidor e a estrutura automática criada incialmente, seguindo os princípios do S.O.L.I.D.
[adrotate banner=”4″]
Como o NestJS utiliza TypeScript, é possível a criação de códigos fortemente tipados, mas também é possível utilizá-lo com JS puro.
A construção do código inicialmente combina elementos de OOP (Programação Orientada a Objetos), FP (Programação Funcional) e FRP (Programação Reativa Funcional). Além disso, o Nest faz uso de estruturas robustas de servidor HTTP como o Express (o padrão). Bem como, opcionalmente, pode ser configurado para usar o Fastify também!
O Nest fornece um nível de abstração acima dessas estruturas comuns do Node.js (Express/Fastify), mas
também expõe suas APIs diretamente ao desenvolvedor. Dessa forma, oferecendo aos desenvolvedores a liberdade de usar a infinidade de módulos de terceiros que estão disponíveis para a plataforma subjacente.
Segundo a documentação, GraphQL é:
GraphQL é uma linguagem de consulta para APIs de alto desempenho, relacionado ao tempo de consulta aos principais SGBDs. Dessa forma, o GraphQL fornece uma descrição completa e compreensível dos dados e requisições de sua API, oferecendo aos clientes o poder de solicitar exatamente o que eles precisam e nada mais!
Primeiramente, para iniciar nosso projeto CRUD, iremos realizar todas as instalações necessárias para a criação do projeto.
Extensões:
Para visualizar o projeto deste artigo, clique neste link.
npm i -g @nestjs/cli
nest new nest-api-withgraphql
Então, após executar o comando acima, a imagem abaixo descreve o que vocês devem visualizar de saída.
3. Na imagem 1, escolha o seu gerenciador de pacotes favorito! Neste caso, vamos escolher o YARN.
Dessa forma, após as instalações para o NestJS estiverem finalizadas, a imagem abaixo descreve o que você deve visualizar de saída.
cd .NOME_DO_PROJETO
para acessar a pasta criada com o projeto que definimos. Logo após entrarmos no projeto, vamos abri-lo no VSCode com o comando code .
. Perfeito, agora podemos fechar o terminal!Documentações de referência para projeto CRUD: https://docs.nestjs.com/techniques/database e https://typeorm.io/.
CTRL + J
yarn add @nestjs/typeorm typeorm mysql2
Observação: vou fazer a instalação do mysql, porque este é o SGBD que mais utilizei na minha trajetória como programador, mas você pode utilizar outros, como postgresql, mssql, etc. É só fazer a instalação da lib e adicionar os parâmetros de conexão conforme apresentado no código abaixo.
Dentro do diretório src
, vamos modificar o arquivo app.module.ts
.
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm'
/*
Arquivo para importação dos módulos utilizados no projeto e conexão com o banco de dados!
Sejam bem-vindos ao coração da nossa API!
*/
@Module({
imports: [
TypeOrmModule.forRoot({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "",
database: "graphql_database",
entities: [
"dist/**/*.entity{.ts,.js}"
],
synchronize: true
})
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
Caso queira saber mais sobre esses parâmetros, consulte a documentação neste link.
4. Ative os serviços de mysql e apache no XAMMP ou outro software da sua preferência!
Documentações de referência para projeto CRUD: https://docs.nestjs.com/graphql/quick-start, https://www.npmjs.com/package/graphql, https://www.npmjs.com/package/@nestjs/apollo, https://www.npmjs.com/package/apollo-server-express e https://www.npmjs.com/package/@nestjs/graphql.
yarn add @nestjs/graphql @nestjs/apollo graphql graphql-tools apollo-server-express
src
, vamos modificar o arquivo app.module.ts
novamente, com a nova funcionalidade do GraphQLModule:import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm'
//importações para utilização do graphql
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { join } from 'path';
@Module({
imports: [
TypeOrmModule.forRoot({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "",
database: "graphql_database",
entities: [
"dist/**/*.entity{.ts,.js}"
],
synchronize: true
}),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
Adicione GraphQLModule dentro do array de imports: []. Conforme o código supracitado! Assim, vamos utilizar o autoSchemaFile para fazer a geração do arquivo de schema.gql com as tipagens de forma automática e utilizar o servidor do Apollo para utilização do GraphQL.
nest g module user
Dessa forma, a imagem abaixo descreve o que você deve visualizar de saída.
O comando irá instanciar automaticamente o módulo de usuário e criar o arquivo. Assim, o mesmo acontecerá para os próximos passos.
nest g s user
nest g r user
src/user
com o seguinte nome user.entity.ts
Documentações de referência para projeto CRUD: https://docs.nestjs.com/graphql/resolvers e https://docs.nestjs.com/graphql/cli-plugin.
As entidades se assemelham bastante com a estrutura de migrations. Então, é nesse arquivo que definimos como vai ficar estruturado as colunas da tabela em nosso banco de dados!
(src/user/user.entity.ts)
, o seguinte trecho de código:// importações
import { Field, ID, ObjectType } from '@nestjs/graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@ObjectType() //Informa que é um objeto
@Entity() //Especifica ao código que essa classe se trata de uma entidade
export class User {
@PrimaryGeneratedColumn() // Especifica ao NestJS que a coluna id é uma coluna de chave primaria que é gerada automaticamente
@Field(() => ID) // Informa ao graphql o tipo da coluna
id: string; // tipagem da coluna
@Column()
name: string;
@Column()
email: string;
}
nest-cli.json
na raiz do nosso projeto.{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": [
{
"name": "@nestjs/graphql/plugin",
"options": {
"typeFileNameSuffix": [
".input.ts",
".args.ts",
".entity.ts",
".type.ts"
]
}
}
]
}
}
Documentação de referência para projeto CRUD: https://docs.nestjs.com/techniques/validation.
yarn add class-validator
yarn add class-transformer
src/user
, crie uma pasta e nomeie como dto
e adicione dois arquivos dentro desta pasta chamada createuser.input.ts
e update-user.input.ts
create-user.input.ts
, adicione o seguinte trecho de código:// importações
import { InputType } from "@nestjs/graphql";
import { IsEmail, IsNotEmpty, IsString } from "class-validator";
@InputType() //Define que essa classe é do tipo input, que são os valores que serão recebidos pelo endpoint
export class CreateUserInput {
@IsString()// Validação do tipo do input
@IsNotEmpty({ message: "Campo de name obrigatório" })//Validação para não aceitar o valor vazio para chave
name: string; //Tipagem da coluna
@IsEmail()// Validação do tipo do input
@IsNotEmpty({ message: "Campo de email obrigatório" })//Validação para não aceitar o valor vazio para chave
email: string; //Tipagem da coluna
}
Então, dentro do arquivo update-user.input.ts
, adicione o seguinte trecho de código:
// importações
import { InputType } from "@nestjs/graphql";
import { IsEmail, IsNotEmpty, IsOptional, IsString } from "class-validator";
@InputType() //Define que essa classe é do tipo input, que são os valores que serão recebidos pelo endpoint
export class UpdateUserInput {
@IsString()// Validação do tipo do input
@IsNotEmpty({ message: "Campo de name obrigatório" })//Validação para não aceitar o valor vazio para chave
@IsOptional()// Define o campo como opcional
name?: string; //Tipagem da coluna
@IsEmail()// Validação do tipo do input
@IsNotEmpty({ message: "Campo de email obrigatório" })//Validação para não aceitar o valor vazio para chave
@IsOptional()// Define o campo como opcional
email?: string; //Tipagem da coluna
}
6. Adicione, no arquivo src/main.ts
, o uso global das validações:
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe()) //Para utilizar as validações globalmente
await app.listen(3000);
}
bootstrap();
Documentação de referência para projeto CRUD: https://docs.nestjs.com/providers#services
Service é o arquivo responsável por conter todas nossas funções que faram comunicação direta com o banco. Além disso, ele se assemelha muito aos controllers em outros frameworks.
Portanto, vamos modificar o arquivo src/user/user.service.ts
com o seguinte trecho de código:
// importações
import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateUserInput } from './dto/create-user.input';
import { UpdateUserInput } from './dto/update-user.input';
import { User } from './user.entity'
@Injectable() // para fazer injeção de dependências no nestjs
export class UserService {
//injeta o repositório utilizando a entidade de usuário
constructor(
@InjectRepository(User)
private userRepository: Repository<User>
) { }
//método para listagem de usuários
async findAllUsers(): Promise<User[]> {
const users = await this.userRepository.find()
return users
}
//método para trazer um usuário por id
async findUserById(id: string): Promise<User> {
const user = await this.userRepository.findOneBy({ id })
if (!user) {
throw new NotFoundException("Usuário não encontrado")
}
return user
}
//método para criar um usuário
async createUser(data: CreateUserInput): Promise<User> {
const user = this.userRepository.create(data);
const userSaved = await this.userRepository.save(user)
if (!userSaved) {
throw new InternalServerErrorException('Falha na criação do usuário')
}
return userSaved
}
//método para alterar um usuário
async updateUser(id: string, data: UpdateUserInput): Promise<User> {
const user = await this.findUserById(id);
await this.userRepository.update(user, { ...data });
const userUpdated = this.userRepository.create({ ...user, ...data })
return userUpdated;
}
//método para exclusão de um usuário
async deleteUser(id: string): Promise<boolean> {
const user = await this.findUserById(id);
const deleted = await this.userRepository.delete(user);
if (deleted) {
return true;
}
return false;
}
}
Documentação de referência para projeto CRUD: https://docs.nestjs.com/graphql/resolvers#resolvers
Os Resolvers fornecem instruções para transformar uma operação do GraphQL (@Query @Mutation) em dados. Assim, aqui ficará definido o que uma função recebe e o que ela retorna!
src/user/user.resolver.ts
com o seguinte trecho de código:// importações
import { Args, Mutation, Resolver, Query } from '@nestjs/graphql';
import { CreateUserInput } from './dto/create-user.input';
import { UpdateUserInput } from './dto/update-user.input';
import { User } from './user.entity';
import { UserService } from './user.service';
@Resolver('User')
export class UserResolver {
//Ejetar nosso userService
constructor(private userService: UserService) { }
@Query(() => [User]) //informa ao graphql que esse método vai retornar um array de usuários e que não há modificação do banco com ela
async users(): Promise<User[]> {
const users = await this.userService.findAllUsers()
return users
}
@Query(() => User) //informa ao graphql que esse método vai retornar um usuário em especifico e que não há modificação do banco
async user(@Args('id') id: string): Promise<User> {
const user = await this.userService.findUserById(id)
return user
}
@Mutation(() => User) //informa ao graphql que esse método vai modificar o estado no nosso banco de dados
async createUser(@Args('data') data: CreateUserInput): Promise<User> {
const user = await this.userService.createUser(data)
return user
}
@Mutation(() => User) //informa ao graphql que esse método vai modificar o estado no nosso banco de dados
async updateUser(
@Args('id') id: string,
@Args('data') data: UpdateUserInput
): Promise<User> {
const user = this.userService.updateUser(id, data);
return user;
}
@Mutation(() => Boolean) //informa ao graphql que esse método vai modificar o estado no nosso banco de dados
async deleteUser(
@Args('id') id: string
): Promise<boolean> {
const deleted = await this.userService.deleteUser(id);
return deleted;
}
}
2. Vamos modificar o arquivo src/user/user.module.ts
com o seguinte trecho de código:
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserResolver } from './user.resolver';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
@Module({
imports: [
TypeOrmModule.forFeature([User])
],
providers: [UserService, UserResolver]
})
export class UserModule { }
yarn run start:dev
Com isso, a saída deve se apresentar como na imagem abaixo:
http://localhost:3000/graphql
Dessa forma, após colar o endereço supracitado no navegador, a seguinte página deve aparecer:
Esse é o playground do graphql. Ou seja, a ferramenta que auxilia em nossas requisições!
query{
users{
id
name
email
}
}
Assim, ao fazer a consulta na aba esquerda, a aba direita da ferramenta deve exibir o seguinte resultado:
Isso acontece porque não temos nenhum usuário registrado.
mutation {
createUser(
data: {
name: "Edith Silva"
email: "edith@email.com"
}
) {
id
name
email
}
}
Dessa forma, a resposta deve aparecer como na imagem abaixo:
Então, à essa altura, já conseguimos listar o usuário criado!
// Em uma nova aba do playground, adicione o body abaixo para fazer uma busca pelo id
query{
user(id: "1"){
id
name
email
}
}
// Em uma nova aba do playground, adicione o body abaixo para fazer uma Alteração
mutation {
updateUser(id: "1", data: { email: "manoel@gmail.com" }) {
id
name
email
}
}
//Em uma nova aba do playground, adicione o body abaixo para fazer uma exclusão
mutation {
deleteUser(id: "1")
}
Veja também:
Entenda gerenciador de pacotes
Assim encerramos nossa implementação de um CRUD básico de usuários, utilizando o NestJS, GraphQL e SGBD MySQL. O que foi ensinado nesse artigo é uma pequena fração de tudo que o CRUD essas demais tecnologias podem nos entregar!
Dessa forma, sugiro que a partir daqui, vocês explorem cada vez mais a própria documentação e qualquer dúvida, estou aberto para discussões através do Discord (Manoel Fernandes Neto#5644) ou Linkedin.
Autor: Manoel Fernandes Neto.
[adrotate banner=”5″]
Autor