Como criar uma API GraphQL com o Nest.js?
Neste artigo, você aprenderá a criar uma API GraphQL com o NestJS aproveitando sua arquitetura limpa e a segurança de tipos.
O NestJS é uma estrutura NodeJS que ajuda os usuários a criar aplicativos de back-end escalonáveis de nível empresarial, fornecendo segurança de tipo e um padrão arquitetônico rigoroso.
O GraphQL é uma linguagem de consulta para APIs (interfaces de programação de aplicativos) amplamente usada como alternativa ao REST devido à sua velocidade e estabilidade, que são alcançadas ao responder às consultas com os dados solicitados com precisão. Esse recurso do GraphQL resolve o problema de overfetching e underfetching apresentado pelo REST.
Contents
- 1 Configuração de seu ambiente de desenvolvimento
- 2 Criação de uma entidade
- 3 Criação de um tipo de objeto
- 4 Criação de um serviço
- 5 Criação de um resolvedor
- 6 Testar sua API usando o GraphQL Playground
- 7 Back4app e GraphQL
- 8 Conclusão
- 9 PERGUNTAS FREQUENTES
- 10 O que é GraphQL?
- 11 O que é Nest.JS?
- 12 Como criar uma API GraphQL com Nest.JS?
Configuração de seu ambiente de desenvolvimento
Se você não tiver a CLI do Nest.js instalada globalmente em seu sistema, execute o comando abaixo para instalá-la:
npm i -g @nestjs/cli
A CLI do Nest.js contém vários comandos que o ajudam a gerar código padrão para facilitar o processo de desenvolvimento.
Em seguida, crie o projeto e gere os arquivos iniciais necessários executando o comando abaixo:
nest new graphql-api
Em seguida, execute o comando abaixo para entrar no diretório do projeto:
cd graphql-api
Em seguida, instale as dependências necessárias executando o comando abaixo:
npm i @nestjs/graphql @nestjs/apollo graphql apollo-server-express
As dependências instaladas acima incluem:
nest/graphql
nestjs/apollo
graphql
apollo-server-express
Em seguida, instale o pacote TypeORM e o driver de banco de dados sqlite executando o comando abaixo:
npm install @nestjs/typeorm typeorm sqlite3
Você precisará dos pacotes instalados acima para se conectar, ler e gravar em um banco de dados.
Configuração do GraphQL no Nest.js
O Nest.js oferece duas maneiras de criar uma API GraphQL: as abordagens code-first e schema-first.
A abordagem code-first apresenta o uso de decoradores e classes TypeScript para gerar o esquema GraphQL correspondente.
A abordagem schema-first apresenta o uso de arquivos SDL (GraphQL Schema Definition Language), enquanto o Nest.js gera definições TypeScript usando classes ou interfaces baseadas no GraphQL Schema.
Este tutorial apresentará o uso da abordagem code-first para evitar a troca de contexto entre diferentes idiomas.
Para usar a abordagem de código primeiro, navegue até o arquivo de entrada do seu aplicativo, app.module.ts
, e importe GraphQLModule
de @nestjs/graphql
. Assim:
import { GraphQLModule } from '@nestjs/graphql';
Em seguida, em sua matriz de importações
, chame o método forRoot
do GraphQLModule
. Esse método recebe um objeto de configuração como argumento. As opções de configuração são passadas por meio do driver GraphQL subjacente (este tutorial apresenta o uso do driver Apollo). Defina a propriedade autoSchemaFile
no objeto de configuração como schema.gql
. Dessa forma:
//app.module.ts
GraphQLModule.forRoot({ autoSchemaFile: 'schema.gql' }),
A propriedade autoSchemaFile
é o caminho do arquivo em que o esquema gerado automaticamente será armazenado.
Conexão a um banco de dados
Para conectar seu aplicativo a um banco de dados, navegue até o arquivo app.module.ts
e importe TypeOrmModule
de @nestjs/typeorm
.
Assim:
import { TypeOrmModule } from '@nestjs/typeorm';
Em seguida, adicione o bloco de código abaixo à sua matriz de importações
:
TypeOrmModule.forRoot({
type: 'sqlite',
database: ':memory:',
entities: ['dist/**/*.entity{.ts,.js}'],
synchronize: true,
}),
O bloco de código acima cria uma conexão de banco de dados entre o seu aplicativo e um banco de dados Sqlite e compartilha a conexão com todos os módulos do seu aplicativo.
Geração de recursos
Em seguida, crie um módulo para organizar seu código executando o comando abaixo:
nest g module blog
O comando acima gera um módulo de blog para seu aplicativo.
Em seguida, execute o comando abaixo para criar um serviço:
nest g service blog
O bloco de código acima gera e registra um serviço no seu aplicativo. Esse serviço conterá e manipulará toda a lógica comercial do seu aplicativo.
Em seguida, execute o comando abaixo para criar um resolvedor:
nest g resolver
O bloco de código acima gera e registra um resolvedor no seu aplicativo. Um resolvedor especifica instruções para transformar as consultas e mutações do GraphQL em dados e retorna a forma dos dados especificados em um esquema de forma síncrona ou assíncrona.
Criação de uma entidade
Uma entidade é uma coleção de campos que especifica como os dados são armazenados em um banco de dados.
Para criar uma entidade, na pasta do módulo (blog), crie um arquivo de entidade seguindo a convenção .entity.ts
, por exemplo, blog.entity.ts
.
Em seu arquivo de entidade, importe a coluna
, a entidade
e a PrimaryGeneratedColumn
do typeorm
. Assim:
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
O decorador Column
adiciona os campos que ele anota como colunas em um banco de dados. O decorador Entity
marca a classe que ele anota como uma entidade. O decorador PrimaryGeneratedColumn
marca a propriedade que ele anota como o identificador exclusivo de sua tabela e a gera automaticamente.
Em seguida, crie e exporte uma classe, Blog
. Em seguida, anote a classe com o decorador Entity
para marcá-la como uma entidade. Assim:
@Entity()
export class Blog {}
Como este tutorial apresenta uma API de blog, adicione uma propriedade id, title, body, author e date à sua classe. Em seguida, anote cada uma das propriedades com o decorador Column
, exceto a propriedade id
. Anote a propriedade id
com o decorador PrimaryGeneratedColumn
.
Assim:
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Blog {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
body: string;
@Column()
author: string;
@Column()
date: string;
}
Criação de um tipo de objeto
Um tipo de objeto é uma definição de esquema GraphQL que representa o objeto com o qual o cliente precisa interagir. Por exemplo, se você estiver criando uma API de blog, precisará definir o esquema/entidade do blog com uma classe TypeScript e anotar cada campo com os decoradores apropriados.
Em seguida, em seu arquivo de entidade, importe o tipo Int
e os decoradores Field
e ObjectType
de @nestjs/graphql
. Assim:
import { Field, Int, ObjectType } from '@nestjs/graphql';
O decorador Field
marca uma propriedade de classe específica como um campo GraphQL. Somente as propriedades anotadas com esse decorador serão definidas no esquema. Ele aceita uma função de tipo de retorno opcional e um objeto de configuração como argumentos.
O tipo Int
é necessário para eliminar a possível ambiguidade entre os sistemas de tipos TypeScript e GraphQL. Ele é necessário apenas para propriedades com valores numéricos, pois eles podem ser inteiros ou flutuantes.
O decorador ObjectType
marca uma classe como um tipo GraphQL.
Em seguida, anote sua classe Blog com o decorador ObjectType
para marcá-la como um tipo GraphQL. Assim:
@ObjectType()
export class Blog {}
Por fim, especifique as propriedades necessárias do seu tipo dentro da classe e anote cada uma delas com o decorador Field
. Por exemplo:
//blog.entity.ts
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
@ObjectType()
export class Blog {
@PrimaryGeneratedColumn()
@Field((type) => Int)
id: number;
@Column()
@Field()
title: string;
@Column()
@Field()
body: string;
@Column()
@Field()
author: string;
@Column()
@Field()
date: string;
}
Seu Object Type finalizado deve se parecer com o bloco de código acima.
Observe que o id
com um tipo de número
no bloco de código acima foi explicitamente especificado como um número inteiro para evitar ambiguidade entre os sistemas de tipos do TypeScript e do GraphQL.
Por fim, injete a entidade no aplicativo para criar uma camada de acesso entre o aplicativo e o banco de dados.
Para isso, navegue até o arquivo blog.module.ts
, importe TypeOrmModule
de @nestjs/typeorm
e importe sua entidade Blog.
Em seguida, adicione o bloco de código abaixo ao decorador do módulo:
imports: [TypeOrmModule.forFeature([Blog])],
O bloco de código acima cria um repositório que atuará como uma camada de acesso entre seu aplicativo e o banco de dados.
Criação de um serviço
Navegue até o arquivo de serviço gerado anteriormente, blog.service.ts
, e importe InjectRepository
de @nestjs/typeorm
e seu tipo de objeto.
Assim:
import { InjectRepository } from '@nestjs/typeorm';
import { Blog } from './blog.entity';
Em seguida, adicione o bloco de código abaixo à sua classe BlogService
para injetar seu repositório:
constructor(
@InjectRepository(Blog)
private blogRepository: Repository<Blog>,
) {}
Em seguida, adicione o bloco de código abaixo à sua classe de serviço para implementar a lógica de recuperação de todos os blogs no banco de dados:
async getAll(): Promise<Blog[]> {
return await this.blogRepository.find();
}
Em seguida, você precisará implementar a lógica para adicionar um novo blog ao seu banco de dados, mas, primeiro, será necessário criar um Input Type.
Criação de um tipo de entrada
Para criar um tipo de entrada para suas mutações que aceitam objetos complexos, crie uma pasta dtos
na pasta do
seu blog
. Em seguida, na pasta dtos
, crie um novo arquivo, create-blog.input.ts
.
Em seu arquivo create-blog.input.ts
, importe os decoradores Field
e InputType
. Assim:
import { Field, InputType } from '@nestjs/graphql';
O decorador InputType
marca uma classe como um tipo de entrada GraphQL.
Em seguida, crie e exporte uma classe, BlogInput
. Em seguida, anote a classe com o decorador InputType
. Assim:
@InputType()
export class BlogInput {}
Por fim, adicione todas as propriedades necessárias do blog e anote-as com o decorador Field
.
Assim:
//create-blog.input.ts
import { Field, InputType } from '@nestjs/graphql';
@InputType()
export class BlogInput {
@Field()
id: number;
@Field()
title: string;
@Field()
body: string;
@Field()
author: string;
@Field()
date: string;
}
Seu tipo de entrada finalizado deve se parecer com o bloco de código acima.
Em seguida, importe o tipo de entrada para o arquivo de serviço e adicione o bloco de código abaixo à classe de serviço para implementar a lógica de adição de um blog ao banco de dados:
async createBlog(blogInput: BlogInput): Promise<Blog> {
const newBlog = this.blogRepository.create(blogInput);
return this.blogRepository.save(newBlog);
}
O tipo de entrada é aplicado da mesma forma que um objeto regular de transferência de dados do Nest.js, como um mecanismo de validação para os dados recebidos. Como os dtos, você também pode executar validação adicional nos dados usando o pacote class-validator
.
Criação de um resolvedor
Navegue até o arquivo Resolver gerado anteriormente, blog.resolver.ts
, e importe a entidade, o tipo de entrada e o serviço. Assim:
import { Blog } from './blog.entity';
import { BlogService } from './blog.service';
import { BlogInput } from './dto/create-blog.input';
Em seguida, adicione o bloco de código abaixo à sua classe Resolver para injetar seu serviço no resolvedor:
constructor(private blogService: BlogService) {}
Em seguida, importe os decoradores Args
, Mutation
e Query
de @nestjs/graphql
.
Assim:
import { Args, Mutation, Query } from '@nestjs/graphql';
O decorador Args
extrai o objeto arguments da plataforma subjacente e preenche o parâmetro decorado com o valor de todos os argumentos ou de um único argumento especificado.
O decorador Mutation
especifica uma rota como uma mutação.
O decorador Query
especifica uma rota como uma consulta.
Em seguida, passe a função abaixo para o decorador Resolver
para especificar o tipo de objeto:
(of) => Blog
Em seguida, adicione o bloco de código abaixo à sua classe Resolver para resolver o método getAll
.
@Query((type) => [Blog])
async getAllBlogs() {
return this.blogService.getAll();
}
Por fim, adicione o bloco de código abaixo à sua classe Resolver para resolver o método createBlog
.
@Mutation((returns) => Blog)
createBlog(@Args('blogInput') blogInput: BlogInput): Promise<Blog> {
return this.blogService.createBlog(blogInput);
}
Observação: não se esqueça de especificar a função do tipo de retorno para cada decorador.
Sua classe Resolver finalizada deve se parecer com o bloco de código abaixo:
@Resolver((of) => Blog)
export class BlogResolver {
constructor(private blogService: BlogService) {}
@Query((type) => [Blog])
async getAllBlogs() {
return this.blogService.getAll();
}
@Mutation((returns) => Blog)
createBlog(@Args('blogInput') blogInput: BlogInput): Promise<Blog> {
return this.blogService.createBlog(blogInput);
}
}
Testar sua API usando o GraphQL Playground
Para testar seu aplicativo usando o playground GraphQL, disponível por padrão, execute o comando abaixo e navegue até http://localhost:3000/graphql.
npm start
Em seguida, você verá um playground onde poderá testar suas consultas e mutações, conforme mostrado na imagem abaixo.
Para recuperar todos os blogs do banco de dados, execute a consulta abaixo:
query getAll{
getAllBlogs {
id,
title,
body,
author,
date
}
}
Um exemplo é mostrado na imagem abaixo:
Para adicionar um blog ao seu banco de dados, execute a mutação abaixo:
mutation createBlog {
createBlog (blogInput: {
id: 1,
title: "GraphQL is great",
body: "GraphQL APIs are faster than REST APIs",
author: "David Ekete",
date: "01-02-03"
}) {
id,
title,
body,
author,
date,
}
}
Um exemplo é mostrado na imagem abaixo:
Back4app e GraphQL
Devido às muitas vantagens que o GraphQL tem sobre o REST, como o controle de busca de dados, a plataforma Back4app fornece uma API GraphQL integrada aos seus aplicativos de análise em execução na plataforma.
Essa integração permite que você verifique a integridade do backend do seu servidor, execute operações de criação, leitura, atualização e exclusão (CRUD) no seu banco de dados e muito mais, escrevendo consultas e mutações GraphQL simples.
Por exemplo, para verificar a integridade do seu servidor de back-end usando a API GraphQL, execute a consulta abaixo:
query Health {
health
}
A consulta acima retornará:
{
"data": {
"health": true
}
}
Para começar a usar o recurso GraphQL, navegue até o painel do Parse, selecione e clique no seu aplicativo. Na interface do usuário do aplicativo, selecione e clique em Core, depois selecione e clique em API console e escolha o console GraphQL.
Seguir as instruções acima abrirá um console GraphQL no qual você poderá executar suas consultas e mutações semelhantes ao playground GraphQL que você usou no desenvolvimento. Você pode saber mais sobre o recurso GraphQL do Back4app na documentação do Back4app.
Conclusão
Este artigo abordou como você pode criar uma API GraphQL no Nest.js e testar a API com o playground do GraphQL. As APIs GraphQL têm várias vantagens sobre as APIs REST.
No entanto, eles não são ideais para todos os aplicativos. Não deixe de considerar os prós e os contras do GraphQL e do REST antes de escolher o que seria adequado para seu aplicativo.
Independentemente de sua escolha, GraphQL ou REST, você ainda precisará implantar seu aplicativo. O Back4app é um BaaS de baixo código baseado em tecnologias de código aberto que simplifica o processo de criação de back-end, eliminando tarefas repetitivas usando modelos reutilizáveis e gerenciando a maior parte de sua infraestrutura de back-end.
Alguns dos recursos do Back4app incluem um banco de dados em tempo real, funções de nuvem, APIs e SDKs nativos, um sistema completo de gerenciamento de usuários e muito mais.
Essa plataforma também apresenta um nível gratuito que permite que você explore a plataforma sem pagar uma taxa.
Boa construção!
PERGUNTAS FREQUENTES
O que é GraphQL?
GraphQL é uma linguagem de consulta e manipulação de dados de código aberto para APIs, criada pelo Facebook em 2012.
O que é Nest.JS?
Nest.JS é uma estrutura Node.js de código aberto para criar aplicativos eficientes e escaláveis do lado do servidor.
Como criar uma API GraphQL com Nest.JS?
– Configurar GraphQL em Nest.js
– Conectar a um banco de dados
– Gerar recursos
– Criar uma entidade
– Criar um tipo de objeto
– Criar um serviço