Olá! Seja bem-vinda e bem-vindo a este curso. Desta vez, vamos falar sobre GraphQL. Meu nome é Vinícius Neves, sou o desenvolvedor de boina, mas ainda barbudo, que você aprecia aqui na Alura.
Audiodescrição: Vinícius é um homem branco, com barba e cabelo castanho. Ele está usando uma boina e veste uma camisa casual. Está em um ambiente de estúdio com uma decoração moderna ao fundo.
A ideia deste curso é implementar uma aplicação de ponta a ponta, um back-end GraphQL. Vamos começar entendendo o mais importante: a motivação por trás da existência do GraphQL.
Vamos explorar de onde o GraphQL veio, qual problema ele resolve e quais são suas limitações. Após essa introdução, vamos colocar a mão na massa e construir uma aplicação. Nesta aplicação, realizaremos diversas atividades ao longo das aulas: criar usuários, fazer login, criar canais, fazer upload de vídeos, comentar em vídeos e até mesmo lidar com comentários em tempo real. Quando alguém cria um comentário, como mostrado na tela, receberemos uma notificação.
É importante que estejamos com o Node atualizado, pois não abordaremos a base do Node aqui. Nosso foco será no GraphQL, especificamente utilizando o framework NestJS. Se estamos prontos para essa jornada, vamos começar a codificar. Este curso aborda muitos conceitos interessantes e cobre de ponta a ponta o que enfrentamos no dia a dia como pessoas desenvolvedoras: criação de usuários, autenticação com token, criação e atualização de dados, entre outros.
Esperamos que todos estejam tão animados quanto nós. Nos vemos no próximo vídeo, onde aprenderemos mais sobre GraphQL.
Para entrar na discussão sobre Rust versus GraphQL, precisamos entender um contexto histórico. Vamos começar do início, abordando o HTTP. Como funciona esse protocolo? Essencialmente, temos um cliente que faz uma requisição e recebe uma resposta. Esse é o funcionamento básico do HTTP: alguém solicita algo e o servidor responde.
Um exemplo disso é o navegador, que atua como cliente, utilizando a internet para visualizar um site, como o servidor da Alura. Quando digitamos www.alura.com.br, algo acontece que transforma esse endereço compreensível para humanos em números, realizando todo o roteamento necessário, conforme a web funciona nos bastidores. O ponto central aqui é a solicitação e a resposta.
Historicamente, o HTTP foi inventado no CERN. O primeiro site, inclusive, ainda está ativo. Até a versão 0.9, o HTTP não aceitava cabeçalhos. Esses cabeçalhos foram introduzidos na versão 1.0, em 1996. Antes, o tráfego era apenas de HTML. Com os cabeçalhos, foi possível adicionar informações extras nas requisições, tanto na ida quanto na volta, conferindo "superpoderes" ao HTTP.
Com isso, surgiram novas formas de programação distribuída. Por exemplo, o XML e o RPC permitiam chamadas de código nos bastidores, enviando mensagens de um lado para o outro. Não era mais necessário trafegar apenas HTML; podíamos enviar XML também. Foi nesse contexto que surgiu o SOAP (Simple Object Access Protocol), que, apesar do nome, não era simples.
No SOAP, instanciávamos uma classe, e o código era executado em outra máquina. Nos bastidores, ocorria a serialização, envio pela rede, processamento, deserialização, e o ciclo se repetia. Embora amigável a nível de código, o SOAP apresentava problemas, como conexões intermitentes e complexidades adicionais.
O importante é que, com os cabeçalhos, surgiram novas formas de utilizar o protocolo, além do HTML, incluindo o XML. Isso nos leva ao REST (Representational State Transfer), que introduz algumas restrições e regras. Quando afirmamos que uma API não é RESTful, podemos gerar discussões, pois as pessoas tendem a defender suas implementações.
RESTful refere-se a uma API que segue os princípios REST. Para ser considerada RESTful, uma API deve aderir a todas essas regras; caso contrário, é apenas JSON sobre HTTP, o que não está errado, mas não é RESTful. Vamos discutir esses princípios.
Primeiro, temos o modelo cliente-servidor, onde o cliente faz um pedido, o servidor processa e devolve. Além disso, o REST é stateless (sem estado), o que significa que cada requisição deve conter todas as informações necessárias para seu funcionamento, sem manter estado entre requisições.
Outro princípio é a possibilidade de cache, permitindo adicionar uma camada de cache. O REST também deve ser em camadas, compreendendo todas as camadas relacionadas à API. Um conceito mais intangível é o Code On Demand, que ocorre quando carregamos HTML, CSS e scripts JavaScript do servidor, exemplificando o Code On Demand.
Estamos solicitando o código e vamos executá-lo sob demanda. Como o REST não foi originalmente pensado como uma API, mas sim para a web, podemos ter essa necessidade de código sob demanda. Um ponto crítico do HTTP, que muitas APIs não possuem, mas que para ser RESTful deveria ter, é a interface uniforme. Basicamente, precisamos conseguir fazer um controle de hipermídia de forma que cada requisição nos forneça informações sobre o que pode acontecer com aquele recurso ou sobre a navegação em si. Isso se relaciona com o conceito de HATEOAS (Hypermedia as the Engine of Application State).
Vamos entender isso na prática. Observemos uma requisição feita no Postman. Solicitamos o produto de id1. Além de trazer o id, o nome, o preço e a descrição desse produto, há uma propriedade _links, que contém um link para ele mesmo e outra propriedade que é produtos relacionados. A ideia de hipermídia é justamente essa, de conseguirmos navegar pelos recursos.
No final, queremos sair do POX (Plain Old XML) para alcançar a glória do REST. Vamos deixar de usar XML, começar a adicionar recursos, observar os verbos HTTP de acordo com o tipo de operação que queremos realizar, adicionar hipermídia e, assim, atingir a glória do REST.
Vamos agora refletir sobre um exemplo prático. Trouxemos uma tela do YouTube do canal da Alura. Podemos pensar em como estruturaríamos endpoints REST. Poderíamos ter, por exemplo, /channels para listar todos os canais, /channels/{id} para obter os dados de um canal específico, /channels/{id}/playlists para trazer todas as playlists daquele canal específico, /playlists/{id} para obter uma playlist específica, e /playlists/{id}/videos para obter os vídeos daquela playlist. Percebemos a quantidade de requisições necessárias para montar essa tela. É aqui que o REST pode se tornar complexo, com um excesso de round trips. Quantas vezes precisamos acessar o servidor para obter os dados necessários para montar essa tela?
O GraphQL, criado em 2012, busca resolver esse problema. Ele visa resolver o excesso de round trips e facilitar a construção da interface. Além disso, o GraphQL se preocupa com o overfetching e underfetching. Isso significa que não queremos obter dados em excesso nem em falta. Se temos uma lista e queremos listar apenas os canais, não queremos trazer todos os vídeos de todos os canais, pois não sabemos para onde a pessoa irá navegar. Queremos trafegar apenas os dados necessários, sob medida.
Voltando ao exemplo do YouTube, gostaríamos de poder especificar que, para esse cenário, queremos apenas a thumbnail, o título, o número de visualizações, o nome do canal e a data de publicação. Nada além disso. Se a pessoa clicar, então pedimos mais informações. A ideia do GraphQL é ser algo sob medida.
Se fizermos uma requisição GET tradicional em uma API HTTP, como por exemplo para pessoa/1, o que retorna é o nome Maria, sobrenome da Silva, e-mail maria.silva@gmail.com, e o estado civil. Por padrão, é isso que uma API REST entregaria. No GraphQL, pedimos explicitamente quais informações queremos. Se estamos fazendo uma query para obter dados de uma pessoa, especificamos os campos desejados. Podemos, por exemplo, solicitar apenas o nome e o sobrenome, sem precisar do e-mail ou estado civil. Assim, entregamos exatamente os dados necessários.
No nosso cenário, podemos solicitar dados de um canal cujo nome de usuário é Alura e obter informações específicas do canal, como o nome, a quantidade de inscritos, as playlists disponíveis, o nome das playlists, e dois vídeos com seus títulos e quantidade de visualizações. É algo bem sob medida.
Concluindo, conseguimos entender qual problema estamos tentando resolver com uma API GraphQL. Queremos evitar o excesso de round trips e também cuidar do overfetching e underfetching. Vamos ser bem granulares e específicos para cada cenário e consumo. Essa é a flexibilidade que o GraphQL oferece.
Agora que entendemos o caso de uso específico, vamos explorar os conceitos necessários para desenvolver uma API GraphQL. Nos vemos na próxima aula.
Vamos agora entender o que é um servidor GraphQL. Neste curso, vamos utilizar especificamente o servidor chamado Apollo e o framework Nest para desenvolver um servidor desse tipo. Essa é a técnica que vamos adotar, embora não seja a única. Deixaremos o conteúdo em texto para que possamos entender também as diferenças.
Como funciona essencialmente um servidor GraphQL? Ele é uma API baseada em esquema (schema-based), ou seja, todo o núcleo, o conceito principal, é justamente o esquema. Se pensarmos em uma árvore montando isso, teremos o esquema principal, que é um tipo, um tipo raiz (root type). Também temos os tipos específicos de operações que podemos realizar. Se quisermos buscar dados, faremos uma query. Se quisermos enviar dados, faremos uma mutation. E se quisermos nos inscrever em algo que acontece em tempo real e manter essa conexão aberta, faremos uma subscription. Esses são os três pilares do GraphQL.
Além disso, temos os tipos de objeto (object types), que são os modelos em si. No vídeo anterior, falamos sobre canais e vídeos na tela do YouTube, onde tínhamos vídeos, playlists e canais. Aqui, por exemplo, temos usuários e postagens, que são nossos modelos. Eles serão nossos tipos de objeto. Temos também os tipos escalares (scalar types), que são de fato os tipos das propriedades. Um usuário, por exemplo, terá um id, um name e um e-mail. Estamos falando das propriedades do nosso modelo. Portanto, o tipo raiz é o esquema em si e as operações que podemos realizar. O tipo de objeto são nossos modelos, e o tipo escalar são os tipos de propriedade que nossos modelos podem ter.
Essencialmente, é assim que funciona. Temos dois possíveis enfoques: podemos ter o code first, ou seja, criamos o código e usamos alguma ferramenta para gerar o esquema derivado do código. Ou fazemos o contrário, adotando o schema first e derivando o código a partir do esquema.
No code first, definimos os modelos, os tipos de objeto, diretamente no código e temos ferramentas que geram automaticamente os tipos para nós. Como escolhemos entre um ou outro? Podemos optar por algo baseado em esquema. Imagine que temos um front-end que depende disso; então, fazemos todo o esquema primeiro, compartilhamos e, em cima do esquema, desenvolvemos o servidor. Esse pode ser um cenário plausível. Na prática, o que vemos muito é a abordagem code first, ou seja, utilizamos o TypeScript e o Nest, escrevemos o código em TypeScript e deixamos as ferramentas de automação gerarem o esquema para nós.
Agora, vamos começar a entrar nos resolvers, ou seja, como vamos desenvolver isso? Enquanto no lado da API REST costumamos ter controllers, no lado do GraphQL temos resolvers. Como isso funciona? O resolver é um intermediário entre o que a pessoa usuária está pedindo, consumindo nossa API, e o que precisamos fazer para devolver uma resposta. Um resolver é basicamente um conjunto de funções. Podemos colocá-lo no nível do controller.
No contexto de uma API REST, utilizamos controllers no back-end. No entanto, no GraphQL, não temos controllers, mas sim resolvers. Além disso, no GraphQL, não consideramos o status code. A resposta será sempre 200, mas o corpo da mensagem conterá os dados necessários para entender a operação realizada. Portanto, não utilizamos o status code para verificar se a operação foi bem-sucedida ou não; analisamos o conteúdo da resposta. Isso ocorre porque abstraímos essa informação para o cliente que consome a API. Na prática, trabalhamos mais orientados aos dados e ao estado do que ao controle granular do que está acontecendo.
Já entendemos o que é um resolver. Agora, vamos falar sobre o object type. Lembramos que discutimos sobre root, object type e scalar type. Quando temos um modelo, uma entidade, utilizamos a anotação do NestJS para definir um object type. Por exemplo, ao criar o object type de uma categoria, definimos um id, um displayName e um icon. O displayName e o icon são do tipo string. O id também é uma string, mas possui um escalar específico.
Para ilustrar isso, vamos ver como definimos um object type no código:
@ObjectType()
export class Category {
@Field(() => ID)
id: string;
@Field()
displayName: string;
@Field()
icon: string;
}
Se temos um object type categoria, criamos um resolver para essa categoria. Utilizamos uma anotação para indicar o que estamos resolvendo. Assim, temos um resolver de categoria, que é uma classe com um nome específico. Esse resolver possui uma query que retorna um array de categorias, ou seja, uma lista de categorias. Essa operação é uma promise que provavelmente acessará um serviço que, por sua vez, acessará o banco de dados, retornando os dados no final.
Aqui está como podemos implementar um resolver para a categoria:
@Resolver(() => Category)
export class CategoryResolver {
@Query(() => [Category])
async categories(): Promise<Category[]> {
return [
{
id: 'camisetas',
displayName: 'Camisetas',
icon: 'https://raw.content.com/icon.png',
},
];
}
}
É importante evitar duplicações ou acoplamentos desnecessários no código. Por exemplo, em um cenário com categorias e produtos, ao invés de incluir tudo em um único local, podemos ter um resolve field específico para um campo. Quando temos nosso object type, ao invés de um escalar, como um id, podemos apontar para outro objeto e usar um resolve field para resolver esses campos específicos.
Vamos ver como isso se aplica a um resolver de produto:
@Resolver('Product')
export class ProductResolver {
@Query(() => [Product])
async getProducts(): Promise<Product[]> {
return [
{
name: 'Tênis Esportivo',
price: 199.99,
seller: 'Loja XYZ',
image: 'image-url',
category: { id: '1', displayName: 'Calçados' },
},
];
}
@ResolveField(() => String)
async categoryName(@Parent() product: Product): Promise<string> {
return product.category.displayName;
}
}
Outra característica comum do GraphQL é o playground, que oferece uma documentação integrada. Não precisamos fazer muito para ter esse playground funcionando, permitindo que façamos queries e mutations sem a necessidade de ferramentas específicas como o Postman.
Por exemplo, podemos executar a seguinte query no playground:
# Write your query or mutation here
query {
categories {
displayName
}
}
E a resposta que obteríamos seria algo assim:
{
"data": {
"categories": [
{
"displayName": "Camisetas"
},
{
"displayName": "Bolsas"
},
{
"displayName": "Calçados"
},
{
"displayName": "Calças"
}
]
}
}
Com isso, estamos prontos para começar a codificar. Na sequência, vamos colocar a mão no NestJS e construir o back-end de GraphQL. Vamos em frente!
O curso Graphql: criando APIs baseada em esquemas possui 247 minutos de vídeos, em um total de 51 atividades. Gostou? Conheça nossos outros cursos de Node.JS em Programação, ou leia nossos artigos de Programação.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
2 anos de Alura
Matricule-se no plano PLUS 24 e garanta:
Jornada de estudos progressiva que te guia desde os fundamentos até a atuação prática. Você acompanha sua evolução, entende os próximos passos e se aprofunda nos conteúdos com quem é referência no mercado.
Mobile, Programação, Front-end, DevOps, UX & Design, Marketing Digital, Data Science, Inovação & Gestão, Inteligência Artificial
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você participa de eventos exclusivos, pode tirar dúvidas em estudos colaborativos e ainda conta com mentorias em grupo com especialistas de diversas áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
2 anos de Alura
Todos os benefícios do PLUS 24 e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Para estudantes ultra comprometidos atingirem seu objetivo mais rápido.
2 anos de Alura
Todos os benefícios do PRO 24 e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.
Conecte-se ao mercado com mentoria individual personalizada, vagas exclusivas e networking estratégico que impulsionam sua carreira tech para o próximo nível.