GraphQL - Guia rápido
GraphQL é uma tecnologia do lado do servidor de código aberto que foi desenvolvida pelo Facebook para otimizar chamadas de API RESTful. É um mecanismo de execução e uma linguagem de consulta de dados. Neste capítulo, discutimos sobre as vantagens de usar GraphQL.
Por que GraphQL
As APIs RESTful seguem uma abordagem orientada a recursos clara e bem estruturada. No entanto, quando os dados ficam mais complexos, as rotas ficam mais longas. Às vezes, não é possível buscar dados com uma única solicitação. É aqui que o GraphQL se torna útil. GraphQL estrutura os dados na forma de um gráfico com sua poderosa sintaxe de consulta para percorrer, recuperar e modificar dados.
A seguir estão as vantagens de usar a linguagem de consulta GraphQL -
Peça o que você quer - e obtenha
Envie uma consulta GraphQL para sua API e obtenha exatamente o que você precisa. As consultas GraphQL sempre retornam resultados previsíveis. Os aplicativos que usam GraphQL são rápidos e estáveis. Ao contrário dos serviços Restful, esses aplicativos podem restringir os dados que devem ser buscados no servidor.
O exemplo a seguir ajudará você a entender isso melhor -
Vamos considerar um objeto de negócio Student com os atributos id, firstName, lastName e collegeName . Suponha que um aplicativo móvel precise buscar apenas o firstName e id . Se projetarmos um endpoint REST como / api / v1 / students , ele vai acabar buscando dados para todos os campos de um objeto de aluno . Isso significa que os dados são recuperados pelo serviço RESTful. Este problema pode ser resolvido usando GraphQL.
Considere a consulta GraphQL fornecida abaixo -
{
students {
id
firstName
}
}
Isso retornará valores apenas para os campos id e firstname. A consulta não buscará valores para outros atributos do objeto de aluno. A resposta da consulta ilustrada acima é mostrada abaixo -
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim"
},
{
"id": "S1002",
"firstName": "Kannan"
}
]
}
}
Obtenha muitos recursos em uma única solicitação
As consultas GraphQL ajudam a recuperar facilmente objetos de negócios associados, enquanto as APIs REST típicas requerem o carregamento de vários URLs. As APIs GraphQL buscam todos os dados de que seu aplicativo precisa em uma única solicitação. Os aplicativos que usam GraphQL podem ser rápidos, mesmo em conexões de rede móvel lentas.
Vamos considerar mais um objeto de negócio, a faculdade que possui os atributos: nome e localização. O objeto de negócios Aluno tem um relacionamento de associação com o objeto Faculdade. Se fôssemos usar uma API REST para buscar os detalhes dos alunos e da faculdade, acabaríamos fazendo duas solicitações ao servidor como / api / v1 / students e / api / v1 / colleges . Isso levará à sub-busca de dados com cada solicitação. Portanto, os aplicativos móveis são forçados a fazer várias chamadas para o servidor para obter os dados desejados.
No entanto, o aplicativo móvel pode buscar detalhes para objetos Student e College em uma única solicitação usando GraphQL.
A seguir está uma consulta GraphQL para buscar dados -
{
students{
id
firstName
lastName
college{
name
location
}
}
}
A saída da consulta acima contém exatamente os campos que solicitamos, conforme mostrado abaixo -
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"lastName": "Mohammad",
"college": {
"name": "CUSAT",
"location": "Kerala"
}
},
{
"id": "S1002",
"firstName": "Kannan",
"lastName": "Sudhakaran",
"college": {
"name": "AMU",
"location": "Uttar Pradesh"
}
},
{
"id": "S1003",
"firstName": "Kiran",
"lastName": "Panigrahi",
"college": {
"name": "AMU",
"location": "Uttar Pradesh"
}
}
]
}
}
Descreva o que é possível com um sistema de tipos
GraphQL é fortemente tipado e as consultas são baseadas em campos e seus tipos de dados associados. Se houver incompatibilidade de tipo em uma consulta GraphQL, os aplicativos de servidor retornarão mensagens de erro claras e úteis. Isso ajuda na depuração suave e na detecção fácil de bugs pelos aplicativos clientes. GraphQL também fornece bibliotecas do lado do cliente que podem ajudar a reduzir a conversão e análise explícita de dados.
Um exemplo dos tipos de dados Student e College é fornecido abaixo -
type Query {
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
type College {
id:ID!
name:String
location:String
rating:Float
students:[Student]
}
Mova-se mais rápido com poderosas ferramentas de desenvolvedor
GraphQL fornece ferramentas ricas de desenvolvedor para documentação e teste de consultas. GraphiQL é uma excelente ferramenta que gera documentação da consulta e seu esquema. Ele também fornece um editor de consulta para testar APIs GraphQL e capacidade de preenchimento de código inteligente ao construir consultas.
Neste capítulo, aprenderemos sobre a configuração ambiental do GraphQL. Para executar os exemplos neste tutorial, você precisará do seguinte -
Um computador executando Linux, macOS ou Windows.
Um navegador da web, de preferência a versão mais recente do Google Chrome.
Uma versão recente do Node.js instalada. Recomenda-se a versão mais recente do LTS.
Código do Visual Studio com extensão GraphQL para VSCode instalado ou qualquer editor de código de sua escolha.
Como construir um servidor GraphQL com Nodejs
Faremos uma abordagem detalhada em etapas para construir o servidor GraphQL com Nodejs, conforme mostrado abaixo -
Etapa 1 - Verificar as versões do nó e Npm
Depois de instalar o NodeJs, verifique a versão do nó e do npm usando os seguintes comandos no terminal -
C:\Users\Admin>node -v
v8.11.3
C:\Users\Admin>npm -v
5.6.0
Etapa 2 - Criar uma pasta de projeto e abrir em VSCode
A pasta raiz do projeto pode ser nomeada como test-app.
Abra a pasta usando o editor de código do Visual Studio, seguindo as instruções abaixo -
C:\Users\Admin>mkdir test-app
C:\Users\Admin>cd test-app
C:\Users\Admin\test-app>code.
Etapa 3 - Criar package.json e instalar as dependências
Crie um arquivo package.json que conterá todas as dependências do aplicativo de servidor GraphQL.
{
"name": "hello-world-server",
"private": true,
"scripts": {
"start": "nodemon --ignore data/ server.js"
},
"dependencies": {
"apollo-server-express": "^1.4.0",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"graphql": "^0.13.2",
"graphql-tools": "^3.1.1"
},
"devDependencies": {
"nodemon": "1.17.1"
}
}
Instale as dependências usando o comando conforme fornecido abaixo -
C:\Users\Admin\test-app>npm install
Etapa 4 - Criar Banco de Dados de Arquivo Simples na Pasta de Dados
Nesta etapa, usamos arquivos simples para armazenar e recuperar dados. Crie uma pasta de dados e adicione dois arquivosstudents.json e colleges.json.
A seguir está o colleges.json arquivo -
[
{
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating":5.0
},
{
"id": "col-102",
"name": "CUSAT",
"location": "Kerala",
"rating":4.5
}
]
A seguir está o students.json arquivo -
[
{
"id": "S1001",
"firstName":"Mohtashim",
"lastName":"Mohammad",
"email": "[email protected]",
"password": "pass123",
"collegeId": "col-102"
},
{
"id": "S1002",
"email": "[email protected]",
"firstName":"Kannan",
"lastName":"Sudhakaran",
"password": "pass123",
"collegeId": "col-101"
},
{
"id": "S1003",
"email": "[email protected]",
"firstName":"Kiran",
"lastName":"Panigrahi",
"password": "pass123",
"collegeId": "col-101"
}
]
Etapa 5 - Criar uma camada de acesso a dados
Precisamos criar um armazenamento de dados que carregue o conteúdo da pasta de dados. Neste caso, precisamos de variáveis de coleção, alunos e faculdades . Sempre que o aplicativo precisa de dados, ele faz uso dessas variáveis de coleção.
Crie o arquivo db.js na pasta do projeto da seguinte forma -
const { DataStore } = require('notarealdb');
const store = new DataStore('./data');
module.exports = {
students:store.collection('students'),
colleges:store.collection('colleges')
};
Etapa 6 - Criar arquivo de esquema, schema.graphql
Crie um arquivo de esquema na pasta do projeto atual e adicione o seguinte conteúdo -
type Query {
test: String
}
Etapa 7 - Criar Arquivo Resolver, resolvers.js
Crie um arquivo de resolução na pasta do projeto atual e adicione o seguinte conteúdo -
const Query = {
test: () => 'Test Success, GraphQL server is up & running !!'
}
module.exports = {Query}
Etapa 8 - Criar Server.js e configurar GraphQL
Crie um arquivo de servidor e configure GraphQL da seguinte maneira -
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const db = require('./db');
const port = process.env.PORT || 9000;
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json());
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
app.listen(
port, () => console.info(
`Server started on port ${port}`
)
);
Etapa 9 - Executar o aplicativo e testar com GraphiQL
Verifique a estrutura da pasta do projeto test-app da seguinte forma -
test-app /
-->package.json
-->db.js
-->data
students.json
colleges.json
-->resolvers.js
-->schema.graphql
-->server.js
Execute o comando npm start conforme fornecido abaixo -
C:\Users\Admin\test-app>npm start
O servidor está rodando na porta 9000, então podemos testar o aplicativo usando a ferramenta GraphiQL. Abra o navegador e digite o URL http: // localhost: 9000 / graphiql. Digite a seguinte consulta no editor -
{
Test
}
A resposta do servidor é fornecida abaixo -
{
"data": {
"test": "Test Success, GraphQL server is running !!"
}
}
GraphQL é uma especificação que descreve o comportamento de um servidor GraphQL. É um conjunto de diretrizes sobre como as solicitações e respostas devem ser tratadas como protocolos suportados, formato dos dados que podem ser aceitos pelo servidor, formato da resposta retornada pelo servidor, etc. A solicitação feita por um cliente ao GraphQL servidor é chamado de Consulta. Outro conceito importante do GraphQL são seus agnósticos de camada de transporte. Ele pode ser usado com qualquer protocolo de rede disponível como TCP, websocket ou qualquer outro protocolo de camada de transporte. Também é neutro para bancos de dados, portanto, você pode usá-lo com bancos de dados relacionais ou NoSQL.
O GraphQL Server pode ser implantado usando qualquer um dos três métodos listados abaixo -
- Servidor GraphQL com banco de dados conectado
- Servidor GraphQL que integra sistemas existentes
- Abordagem híbrida
GraphQL Server com banco de dados conectado
Esta arquitetura possui um GraphQL Server com um banco de dados integrado e muitas vezes pode ser usada com novos projetos. Ao receber uma Consulta, o servidor lê a carga útil da solicitação e busca os dados do banco de dados. Isso é chamado de resolução da consulta. A resposta retornada ao cliente segue o formato especificado na especificação oficial do GraphQL.
No diagrama acima, o servidor GraphQL e o banco de dados estão integrados em um único nó. O cliente (desktop / móvel) se comunica com o servidor GraphQL por HTTP. O servidor processa a solicitação, busca dados do banco de dados e os retorna para o cliente.
GraphQL Server Integrando Sistemas Existentes
Essa abordagem é útil para empresas que possuem infraestrutura legada e APIs diferentes. GraphQL pode ser usado para unificar microsserviços, infraestrutura legada e APIs de terceiros no sistema existente.
No diagrama acima, uma API GraphQL atua como uma interface entre o cliente e os sistemas existentes. Os aplicativos cliente se comunicam com o servidor GraphQL que, por sua vez, resolve a consulta.
Abordagem Híbrida
Finalmente, podemos combinar as duas abordagens acima e construir um servidor GraphQL. Nesta arquitetura, o servidor GraphQL resolverá qualquer solicitação recebida. Ele recuperará dados do banco de dados conectado ou das APIs integradas. Isso é representado na figura abaixo -
Este capítulo discute diferentes componentes GraphQL e a maneira como eles se comunicam entre si. Todos os componentes do aplicativo podem ser distinguidos conforme abaixo -
- Componentes do lado do servidor
- Componentes do lado do cliente
Componentes do lado do servidor
O servidor GraphQL forma o componente principal do lado do servidor e permite analisar as consultas provenientes de aplicativos clientes GraphQL. O Apollo Server é a implementação mais comumente usada da especificação GraphQL. Outros componentes de programação de servidor incluem o seguinte -
Sr. Não. | Fundamentos e descrição do servidor |
---|---|
1 | Schema Um esquema GraphQL está no centro de qualquer implementação de servidor GraphQL e descreve a funcionalidade disponível para os clientes que se conectam a ele. |
2 | Query Uma consulta GraphQL é a solicitação do aplicativo cliente para recuperar dados do banco de dados ou APIs legadas. |
3 | Resolver Os resolvedores fornecem as instruções para transformar uma operação GraphQL em dados. Eles resolvem a consulta aos dados definindo funções de resolução. |
Componentes do lado do cliente
Abaixo estão os componentes do lado do cliente -
Sr. Não. | Ferramenta e descrição |
---|---|
1 | GraphiQL Interface baseada em navegador para editar e testar consultas GraphQL e mutações. |
2 | ApolloClient Melhor ferramenta para construir aplicativos cliente GraphQL. Integra-se bem com todo o front-end javascript. |
O diagrama abaixo mostra um Client-Server architecture. O servidor da web é construído na estrutura NodeJs e Express. Uma solicitação é feita para o Apollo GraphQL Server pelo aplicativo ReactJS (criado com a biblioteca Apollo Client) ou pelo aplicativo de navegador GraphiQL. A consulta será analisada e validada em relação a um esquema definido no servidor. Se o esquema de solicitação passar na validação, as funções de resolução associadas serão executadas. O resolvedor conterá código para buscar dados de uma API ou banco de dados.
Neste capítulo, criaremos uma API simples que retorna uma mensagem de saudação, HelloWorld, e a acessamos usando GraphiQL.
Exemplo
Este exemplo é baseado no servidor NodeJS, Express e Apollo. Vamos aprender a colocar todos os conceitos juntos nas seguintes etapas -
Etapa 1 - Configurando o Express
ExpressJS é uma estrutura de aplicativo da web que ajuda a construir sites e aplicativos da web. Neste exemplo, construiremos uma API GraphQL sobre a estrutura Express.
O próximo passo é criar uma pasta hello-world-servere navegue até a mesma pasta do terminal. Adicione package.json e dê um nome ao pacote. Como este pacote é usado apenas internamente, podemos declará-lo privado.
{
"name":"hello-world-server",
"private":true
}
Instale as dependências do servidor Express conforme mostrado abaixo -
C:\Users\Admin\hello-world-server>npm install express body-parser cors
body-parser é um pacote de middleware que ajuda o Express a lidar com solicitações HTTP Post com eficiência. cors é outro pacote de middleware que lida com o compartilhamento de recursos de origem cruzada.
Criar uma server.js arquivo dentro da pasta do projeto e digite o seguinte nele -
const bodyParser = require('body-parser')
const cors = require('cors')
const express = require('express')
const port = process.env.PORT|| 9000
const app = express()
//register middleware
app.use(bodyParser.json() , cors())
app.listen(port, () => console.log(`server is up and running at ${port}`)
Para verificar se o servidor Express está instalado e funcionando, execute o seguinte código na janela do terminal -
C:\Users\Admin\hello-world-server>node server.js
A seguinte saída é exibida no console do servidor. Isso mostra que o servidor expresso está sendo executado na porta 9000.
server is up and running at 9000
Se você abrir o navegador e digitar http://localhost:9000, você obterá a seguinte tela -
Para parar o servidor, pressione Ctrl + C.
Etapa 2 - Instalar GraphQL e Apollo Server
Agora que o Express está configurado, a próxima etapa é fazer o download das seguintes dependências GraphQL -
- graphql
- graphql-tools
- apollo-server-express@1
Devemos usar o servidor Apollo v1.0, pois é uma versão estável. Digite os seguintes comandos para instalar essas dependências -
C:\Users\Admin\hello-world-server>npm install graphql graphql-tools apollo-server-express@1
Podemos verificar se essas dependências foram instaladas com sucesso verificando o package.json arquivo que criamos anteriormente.
{
"name": "hello-world-server",
"private": true,
"dependencies": {
"apollo-server-express": "^1.4.0",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"graphql": "^0.13.2",
"graphql-tools": "^3.1.1"
}
}
Etapa 3 - Definir o esquema
Um esquema GraphQL define que tipo de objeto pode ser obtido de um serviço e quais campos ele possui. O esquema pode ser definido usandoGraphQL Schema Definition Language. Agora, adicione o seguinte snippet de código noserver.js arquivo -
// Adding Type Definitions
const typeDefinition = `
type Query {
greeting: String
}
Aqui, a consulta contém um atributo de saudação que retorna um valor de string .
Etapa 4 - Criar um resolvedor
A primeira etapa na criação de um resolvedor é adicionar algum código para processar a solicitação do campo de saudação. Isso é especificado em umresolver. A estrutura da função de resolução deve corresponder ao esquema. Adicione o seguinte snippet de código noserver.js Arquivo.
// Adding resolver
const resolverObject = {
Query : {
greeting: () => 'Hello GraphQL From TutorialsPoint !!'
}
}
A segunda etapa é vincular o esquema e o resolvedor usando makeExecutableSchema. Esta função é pré-definida no módulo graphql-tools. Adicione o seguinte snippet de código no server.js Arquivo.
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})
Etapa 5 - Definir rotas para buscar dados do aplicativo ReactJS / GraphiQL
Adicione o seguinte snippet de código no server.js arquivo -
const {graphqlExpress, graphiqlExpress} = require('apollo-server-express')
//create routes for graphql and graphiql
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
A função graphqlExpress ajuda a registrar a rotahttp://localhost:9000/graphql. O aplicativo ReactJS pode usar este terminal para consultar dados. Da mesma forma, a função graphqliExpress ajuda a registrar a rotahttp://localhost:9000/graphiql. Isso será usado pelo cliente do navegador GraphiQL para testar a API.
O código server.js completo é fornecido abaixo -
const bodyParser = require('body-parser')
const cors = require('cors')
const express = require('express')
const port = process.env.PORT||9000
const app = express()
app.use(bodyParser.json() , cors())
const typeDefinition = `
type Query {
greeting: String
}`
const resolverObject = {
Query : {
greeting: () => 'Hello GraphQL From TutorialsPoint !!'
}
}
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})
const {graphqlExpress,graphiqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
app.listen(port, () => console.log(`server is up and running ${port}`))
Etapa 6 - Iniciar o aplicativo
Executar server.js usando Node.js da seguinte maneira -
C:\Users\Admin\hello-world-server>node server.js
Etapa 7 - Teste a API GraphQL
Abra o navegador e digite http://localhost:9000/graphiql. Na guia de consulta do GraphiQL, digite o seguinte -
{
greeting
}
A resposta do servidor é fornecida abaixo -
{
"data": {
"greeting": "Hello GraphQL From TutorialsPoint !!"
}
}
A imagem a seguir ilustra a resposta -
Note - Certifique-se de que o Apollo Server versão 1.0 seja usado.
GraphQL é uma linguagem fortemente tipada. Tipo System define vários tipos de dados que podem ser usados em um aplicativo GraphQL. O sistema de tipos ajuda a definir o esquema, que é um contrato entre cliente e servidor. Os tipos de dados GraphQL comumente usados são os seguintes -
Sr. Não. | Tipos e descrição |
---|---|
1 | Scalar Armazena um único valor |
2 | Object Mostra que tipo de objeto pode ser obtido |
3 | Query Tipo de ponto de entrada para outros tipos específicos |
4 | Mutation Ponto de entrada para manipulação de dados |
5 | Enum Útil em uma situação em que você precisa que o usuário escolha em uma lista de opções prescrita |
Tipo Escalar
Os tipos escalares são tipos de dados primitivos que podem armazenar apenas um único valor. Os tipos escalares padrão que o GraphQL oferece são -
Int - Inteiro assinado de 32 bits
Float - Valor de ponto flutuante de precisão dupla sinalizado
String - UTF - sequência de 8 caracteres
Boolean - Verdadeiro ou falso
ID - Um identificador exclusivo, geralmente usado como um identificador exclusivo para buscar um objeto ou como a chave para um cache.
A sintaxe para definir um tipo escalar é a seguinte -
field: data_type
O trecho fornecido abaixo define um campo denominado saudação que retorna o valor String.
greeting: String
Tipo de objeto
O tipo de objeto é o tipo mais comum usado em um esquema e representa um grupo de campos. Cada campo dentro de um tipo de objeto é mapeado para outro tipo, permitindo, assim, tipos aninhados. Em outras palavras, um tipo de objeto é composto de vários tipos escalares ou tipos de objeto.
A sintaxe para definir um tipo de objeto é fornecida abaixo -
type object_type_name
{
field1: data_type
field2:data_type
....
fieldn:data_type
}
Você pode considerar o seguinte snippet de código -
--Define an object type--
type Student {
stud_id:ID
firstname: String
age: Int
score:Float
}
--Defining a GraphQL schema--
type Query
{
stud_details:[Student]
}
O exemplo fornecido acima define um tipo de dados de objeto Student. O campo stud_details no esquema raiz da Consulta retornará uma lista de objetos de Aluno.
Tipo de consulta
Uma consulta GraphQL é usada para buscar dados. É como solicitar um recurso em APIs baseadas em REST. Para mantê-lo simples, o tipo Consulta é a solicitação enviada de um aplicativo cliente para o servidor GraphQL. GraphQL usa oSchema Definition Language (SDL)para definir uma consulta. O tipo de consulta é um dos muitos tipos de nível raiz no GraphQL.
A sintaxe para definir uma consulta é fornecida a seguir -
type Query {
field1: data_type
field2:data_type
field2(param1:data_type,param2:data_type,...paramN:data_type):data_type
}
Um exemplo de definição de uma consulta -
type Query {
greeting: String
}
Tipo de Mutação
Mutações são operações enviadas ao servidor para create, update ou deletedados. Eles são análogos aos verbos PUT, POST, PATCH e DELETE para chamar APIs baseadas em REST.
Mutation é um dos tipos de dados de nível raiz no GraphQL. O tipo Query define os pontos de entrada para operações de busca de dados, enquanto o tipo Mutation especifica os pontos de entrada para operações de manipulação de dados.
A sintaxe para definir um tipo de mutação é fornecida abaixo -
type Mutation {
field1: data_type
field2(param1:data_type,param2:data_type,...paramN:data_type):data_type
}
Por exemplo, podemos definir um tipo de mutação para adicionar um novo aluno conforme abaixo -
type Mutation {
addStudent(firstName: String, lastName: String): Student
}
Tipo Enum
Um Enum é semelhante a um tipo escalar. Enums são úteis em uma situação em que o valor de um campo deve ser de uma lista de opções prescrita.
A sintaxe para definir um tipo Enum é -
type enum_name{
value1
value2
}
O snippet a seguir ilustra como um tipo de enum pode ser definido -
type Days_of_Week{
SUNDAY
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
}
Tipo de lista
As listas podem ser usadas para representar uma matriz de valores de tipo específico. As listas são definidas com um modificador de tipo [] que envolve tipos de objetos, escalares e enums.
A seguinte sintaxe pode ser usada para definir um tipo de lista -
field:[data_type]
O exemplo a seguir define um tipo de lista todos -
type Query {
todos: [String]
}
Tipo Não Anulável
Por padrão, cada um dos tipos escalares principais pode ser definido como nulo. Em outras palavras, esses tipos podem retornar um valor do tipo especificado ou não podem ter nenhum valor. Para substituir esse padrão e especificar que um campo deve ser definido, um ponto de exclamação (!) Pode ser anexado a um tipo. Isso garante a presença de valor nos resultados retornados pela consulta.
A seguinte sintaxe pode ser usada para definir um campo não anulável -
field:data_type!
No exemplo abaixo, stud_id é declarado como um campo obrigatório.
type Student {
stud_id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
Um esquema GraphQL está no centro de qualquer implementação de servidor GraphQL. Ele descreve a funcionalidade disponível para os aplicativos cliente que se conectam a ele. Podemos usar qualquer linguagem de programação para criar um esquema GraphQL e construir uma interface em torno dele.
O tempo de execução GraphQL define um esquema genérico baseado em gráfico para publicar os recursos do serviço de dados que ele representa. Os aplicativos cliente podem consultar o esquema dentro de seus recursos. Essa abordagem separa os clientes dos servidores e permite que ambos evoluam e escalem independentemente.
Neste capítulo, usamos o servidor Apollo para executar consultas GraphQL. omakeExecutableSchema A função em graphql-tools ajuda você a vincular esquema e resolvedores.
Sintaxe da função makeExecutableSchema
o makeExecutableSchemafunção recebe um único argumento {} do tipo Object. A sintaxe para usar esta função é fornecida abaixo -
import { makeExecutableSchema } from 'graphql-tools';
const jsSchema = makeExecutableSchema({
typeDefs,
resolvers, // optional
logger, // optional
allowUndefinedInResolve = false, // optional
resolverValidationOptions = {}, // optional
directiveResolvers = null, // optional
schemaDirectives = null, // optional
parseOptions = {}, // optional
inheritResolversFromInterfaces = false // optional
});
Sr. Não. | Parâmetro e Descrição |
---|---|
1 | typeDefs Este é um argumento obrigatório. Ele representa uma consulta GraphQL como uma string UTF-8. |
2 | Resolvers Este é um argumento opcional (objeto vazio por padrão). Isso tem funções que tratam da consulta. |
3 | logger Este é um argumento opcional e pode ser usado para imprimir erros no console do servidor. |
4 | parseOptions Este é um argumento opcional e permite a personalização da análise ao especificar typeDefs como uma string. |
5 | allowUndefinedInResolve Isso é verdade por padrão. Quando definido como falso, faz com que suas funções de resolução gerem erros se retornarem indefinido. |
6 | resolverValidationOptions Este é um argumento opcional e aceita um objeto com propriedades booleanas. |
7 | inheritResolversFromInterfaces Este é um argumento opcional e aceita um argumento booleano para verificar a herança do objeto resolvedor. |
Ilustração
Vamos criar um aplicativo simples para entender esse esquema. Isso criará um esquema para consultar a lista de alunos do servidor. Os dados do aluno serão armazenados em um arquivo simples e usaremos um módulo de nó chamadonotarealdb para falsificar um banco de dados e ler do arquivo simples.
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta chamada schema-app. Mude seu diretório para schema-app no terminal. Em seguida, siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente para concluir o download e o processo de instalação.
Etapa 2 - Criar um esquema
Adicionar schema.graphql arquivo na pasta do projeto, schema-app e adicione o seguinte código -
type Query {
greeting:String
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
password:String
collegeId:String
}
A raiz do esquema será o tipo Consulta. A consulta tem dois campos - saudação e Alunos que retorna String e uma lista de alunos, respectivamente. O aluno é declarado como um tipo de objeto, pois contém vários campos. O campo ID é declarado como não anulável.
Etapa 3 - Criar resolvedor
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const db = require('./db')
const Query = {
greeting:() => {
return "hello from TutorialsPoint !!!"
},
students:() => db.students.list()
}
module.exports = {Query}
Aqui, saudação e alunos são os resolvedores que tratam da consulta. students resolver functionretorna uma lista de alunos da camada de acesso a dados. Para acessar as funções do resolvedor fora do módulo, o objeto Query deve ser exportado usandomodule.exports.
Etapa 4 - Executar o aplicativo
Crie um arquivo server.js e consulte a etapa 8 no capítulo Configuração de ambiente. A próxima etapa é executar o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo. Abra o navegador e digite o URL,http://localhost:9000/graphiql.
Digite a seguinte consulta no editor -
{
greeting
students {
id
firstName
lastName
}
}
A consulta exibirá a saída conforme mostrado abaixo -
Note- Podemos substituir o students.json por uma chamada de API RESTful para recuperar os dados dos alunos ou mesmo um banco de dados real como MySQL ou MongoDB. GraphQL se torna um envoltório fino em torno de sua camada de aplicativo original para melhorar o desempenho.
Resolver é uma coleção de funções que geram resposta para uma consulta GraphQL. Em termos simples, um resolvedor atua como um manipulador de consultas GraphQL. Cada função de resolução em um esquema GraphQL aceita quatro argumentos posicionais conforme fornecido abaixo -
fieldName:(root, args, context, info) => { result }
Um exemplo de funções do resolvedor é mostrado abaixo -
//resolver function with no parameters and returning string
greeting:() => {
return "hello from TutorialsPoint !!!"
}
//resolver function with no parameters and returning list
students:() => db.students.list()
//resolver function with arguments and returning object
studentById:(root,args,context,info) => {
return db.students.get(args.id);
}
A seguir estão os argumentos posicionais e suas descrições -
Sr. Não. | Argumentos e Descrição |
---|---|
1 | root O objeto que contém o resultado retornado do resolvedor no campo pai. |
2 | args Um objeto com os argumentos passados para o campo da consulta. |
3 | context Este é um objeto compartilhado por todos os resolvedores em uma consulta específica. |
4 | info Ele contém informações sobre o estado de execução da consulta, incluindo o nome do campo e o caminho da raiz para o campo. |
Formato do resultado do resolvedor
Os resolvedores em GraphQL podem retornar diferentes tipos de valores, conforme fornecido abaixo -
Sr. Não. | Argumentos e Descrição |
---|---|
1 | null or undefined isso indica que o objeto não foi encontrado |
2 | array isso só é válido se o esquema indicar que o resultado de um campo deve ser uma lista |
3 | promise resolvedores costumam fazer ações assíncronas como buscar em um banco de dados ou API de back-end, para que possam retornar promessas |
4 | scalar or object um resolvedor também pode retornar outros valores |
Ilustração
Vamos criar um aplicativo simples para entender o resolvedor. Isso criará um esquema para consultar um aluno por id do servidor. Os dados do aluno serão armazenados em um arquivo simples e usaremos um módulo de nó chamadonotarealdb para falsificar um banco de dados e ler um arquivo simples.
A seguir está um processo passo a passo para criar um aplicativo simples -
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta chamada resolver-app. Mude seu diretório pararesolver-appdo terminal. Posteriormente, siga as etapas 3 a 5 no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicione o arquivo schema.graphql na pasta do projeto resolver-app e adicione o seguinte código -
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
password:String
collegeId:String
}
O arquivo de esquema mostra que o usuário pode consultar saudação, alunos e studentById . Para recuperar alunos com id específico, usamosdata type ID!que mostra um campo identificador exclusivo não anulável. O campo students retorna uma matriz de alunos e greeting retorna um valor de string simples.
Etapa 3 - Criar resolvedor
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const db = require('./db')
const Query = {
//resolver function for greeting
greeting:() => {
return "hello from TutorialsPoint !!!"
},
//resolver function for students returns list
students:() => db.students.list(),
//resolver function for studentbyId
studentById:(root,args,context,info) => {
//args will contain parameter passed in query
return db.students.get(args.id);
}
}
module.exports = {Query}
Aqui, studentById assume três parâmetros. Conforme discutido neste capítulo, o studentId pode ser recuperado de args; root conterá o próprio objeto Query. Para retornar um aluno específico, precisamos chamar o método get com o parâmetro id na coleção de alunos.
Aqui , saudando, alunos, studentById são os resolvedores que tratam da consulta.students resolver functionretorna uma lista de alunos da camada de acesso a dados. Para acessar as funções do resolvedor fora do módulo, o objeto Query deve ser exportado usando module.exports.
Etapa 4 - Executar o aplicativo
Crie um arquivo server.js. Consulte a etapa 8 no capítulo Configuração de ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o url, http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
studentById(id:"S1001") {
id
firstName
lastName
}
}
O resultado da consulta acima é mostrado abaixo -
{
"data": {
"studentById": {
"id": "S1001",
"firstName": "Mohtashim",
"lastName": "Mohammad"
}
}
}
Uma operação GraphQL pode ser uma operação de leitura ou gravação. Uma consulta GraphQL é usada para ler ou buscar valores, enquanto uma mutação é usada para escrever ou postar valores. Em ambos os casos, a operação é uma string simples que um servidor GraphQL pode analisar e responder com dados em um formato específico. O formato de resposta popular geralmente usado para aplicativos móveis e da web é JSON.
A sintaxe para definir uma consulta é a seguinte -
//syntax 1
query query_name{ someField }
//syntax 2
{ someField }
A seguir está um exemplo de uma consulta -
//query with name myQuery
query myQuery{
greeting
}
// query without any name
{
greeting
}
É claro a partir do exemplo acima que a palavra-chave da consulta é opcional.
As consultas GraphQL ajudam a reduzir a busca excessiva de dados. Ao contrário de uma API Restful, GraphQL permite que um usuário restrinja campos que devem ser buscados no servidor. Isso significa consultas menores e menos tráfego na rede; o que, por sua vez, reduz o tempo de resposta.
Ilustração 1 - Consultar o modelo do aluno com um campo personalizado
Neste exemplo, temos um conjunto de alunos armazenados em um arquivo json. Cada modelo de aluno possui campos como firstName, lastName e id, mas nenhum fullName. Aqui, discutiremos como fazer uma consulta para recuperar fullName de todos os alunos. Para isso, precisamos criar o campo fullName em ambos os resolvedores de esquema.
Vamos ver como fazer esta ilustração usando as etapas abaixo -
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta chamada query-app. Mude seu diretório paraquery-appdo terminal. Posteriormente, siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicionar schema.graphql arquivo na pasta do projeto query-app e adicione o seguinte código -
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}
Observe que não há campo fullName nostudents.jsonArquivo. No entanto, precisamos buscar o nome completo do aluno por meio de uma consulta. O fullName , neste caso, será um campo personalizado que não está disponível com a fonte de dados.
Etapa 3 - Criar resolvedor
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const db = require('./db')
const Query = {
//resolver function for greeting
greeting:() => {
return "hello from TutorialsPoint !!!"
},
//resolver function for students returns list
students:() => db.students.list(),
//resolver function for studentbyId
studentById:(root,args,context,info) => {
//args will contain parameter passed in query
return db.students.get(args.id);
}
}
//for each single student object returned,resolver is invoked
const Student = {
fullName:(root,args,context,info) => {
return root.firstName+":"+root.lastName
}
}
module.exports = {Query,Student}
Etapa 4 - Executar o aplicativo
Criar uma server.jsArquivo. Consulte a etapa 8 no capítulo Configuração de ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
students{
id
fullName
}
}
A resposta para a consulta é fornecida abaixo -
{
"data": {
"students": [
{
"id": "S1001",
"fullName": "Mohtashim:Mohammad"
},
{
"id": "S1002",
"fullName": "Kannan:Sudhakaran"
},
{
"id": "S1003",
"fullName": "Kiran:Panigrahi"
}
]
}
}
Criar uma server.js e adicione o seguinte código -
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const db = require('./db');
const port = 9000;
const app = express();
//loading type definitions from schema file
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
//loading resolvers
const resolvers = require('./resolvers')
//binding schema and resolver
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
//enabling cross domain calls and form post
app.use(cors(), bodyParser.json());
//enabling routes
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//registering port
app.listen(port, () => console.info(`Server started on port ${port}`));
Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
students{
id
fullName
}
}
A resposta para a consulta é fornecida abaixo -
{
"data": {
"students": [
{
"id": "S1001",
"fullName": "Mohtashim:Mohammad"
},
{
"id": "S1002",
"fullName": "Kannan:Sudhakaran"
},
{
"id": "S1003",
"fullName": "Kiran:Panigrahi"
}
]
}
}
Ilustração 2 - Consulta aninhada
Vamos criar uma consulta aninhada para buscar os detalhes do aluno e os detalhes da faculdade. Vamos trabalhar com a mesma pasta de projeto.
Etapa 1 - Editar o Esquema
O arquivo de esquema já contém o campo do aluno . Vamos adicionar uma faculdade de campo e definir seu tipo.
type College {
id:ID!
name:String
location:String
rating:Float
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
Etapa 2 - Modificar o resolver.js
Precisamos adicionar uma função de resolução de faculdade conforme abaixo. A função de resolução de faculdade será executada para cada objeto de aluno retornado. O parâmetro raiz do resolvedor neste caso conterá aluno .
const Student = {
fullName:(root,args,context,info) => {
return root.firstName+":"+root.lastName
},
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student}
O resolvedor retorna a faculdade de cada aluno chamando o método get de coleta de faculdade e passando o collegeId . Temos relação de associação entre Student e College por meio do collegeId .
Etapa 3 - Teste o aplicativo
Abra a janela do terminal e navegue até a pasta do projeto. Digite o comando -npm start. Abra o navegador e digite o URLhttp://localhost:9000/graphiql.
Insira a seguinte consulta na janela GraphiQL -
{
students{
id
firstName
college {
id
name
location
rating
}
}
}
A resposta para a consulta é a seguinte -
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"college": {
"id": "col-102",
"name": "CUSAT",
"location": "Kerala",
"rating": 4.5
}
},
{
"id": "S1002",
"firstName": "Kannan",
"college": {
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating": 5
}
},
{
"id": "S1003",
"firstName": "Kiran",
"college": {
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating": 5
}
}
]
}
}
O que é uma variável de consulta?
Se uma consulta tiver alguns valores dinâmicos a serem transmitidos, represente esses valores dinâmicos usando variáveis. Portanto, a consulta pode ser reutilizada pelos aplicativos cliente.
Ilustração
Vamos criar um aplicativo simples para entender a variável de consulta.
Etapa 1 - Editar Arquivo de Esquema
Adicione um campo sayHello que recebe um parâmetro de string e retorna uma string. Os valores de nome serão dinâmicos no aplicativo cliente.
type Query {
sayHello(name:String!):String
}
Etapa 2 - Editar o arquivo resolver.js
Adicione um resolvedor sayHello que usa o parâmetro abaixo -
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
Etapa 3 - Declare a variável de consulta no GraphiQL
Uma variável é declarada com $ seguido do nome da variável. Por exemplo: $ myname_Variable.
Uma vez que $ myname_Variable é declarado, ele deve ser usado com uma sintaxe de consulta nomeada. A consulta, myQuery pega o valor da string e o passa para dizer Olá, conforme mostrado abaixo -
query myQuery($myname_Variable:String!) { sayHello(name:$myname_Variable)
}
Defina o valor de $ myname_Variable como um objeto JSON na seção Variáveis de consulta do cliente GraphiQL.
{
"myname_Variable": "Mohtashim"
}
A saída do código acima é a seguinte -
{
"data": {
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
Como usar a variável de consulta com Enum
Vamos ver como usar uma variável de consulta quando o parâmetro de campo é enum type.
Etapa 1 - Editar o arquivo schema.graphql
enum ColorType {
RED
BLUE
GREEN
}
type Query {
setFavouriteColor(color:ColorType):String
}
A função setFavouriteColor leva enum como entrada e retorna um valor de string.
Etapa 2 - Editar o arquivo resolvers.js
A função de resolução setFavouriteColor obtém raiz e args . O valor enum passado para a função em tempo de execução pode ser acessado por meio do parâmetro args.
setFavouriteColor:(root,args) => {
return "Your Fav Color is :"+args.color;
}
Etapa 3 - Declare uma variável de consulta no GraphiQL
A consulta é nomeada query_to_setColorque recebe uma variável de nome color_variable de ColorType. Essa variável é passada para o método setFavouriteColor.
query query_to_setColor($color_variable:ColorType) {
setFavouriteColor(color:$color_variable)
}
Na seção de variável de consulta do GraphiQL, digite o seguinte código -
{
"color_variable":"RED"
}
A resposta é mostrada abaixo -
{
"data": {
"setFavouriteColor": "Your Fav Color is: RED"
}
}
Neste capítulo, aprenderemos as consultas de mutação em GraphQL.
As consultas de mutação modificam os dados no armazenamento de dados e retornam um valor. Ele pode ser usado para inserir, atualizar ou excluir dados. As mutações são definidas como parte do esquema.
A sintaxe de uma consulta de mutação é fornecida abaixo -
mutation{
someEditOperation(dataField:"valueOfField"):returnType
}
Ilustração
Vamos entender como adicionar um novo registro de aluno ao armazenamento de dados usando uma consulta de mutação.
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta de projeto com o nome mutation-app. Mude seu diretório para mutation-app no terminal. Siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um arquivo schema.graphql
Adicionar schema.graphql arquivo na pasta do projeto mutation-app e adicione o seguinte código -
type Query {
greeting:String
}
type Mutation {
createStudent(collegeId:ID,firstName:String,lastName:String):String
}
Observe que a função createStudent retorna um tipo String. Este é um identificador único (ID) gerado após a criação de um aluno.
Etapa 3 - Criar um arquivo resolver.js
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const db = require('./db')
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName})
}
}
const Query = {
greeting:() => "hello"
}
module.exports = {Query,Mutation}
A função de mutação aponta para a coleção dos alunos no armazenamento de dados. Para adicionar um novo aluno , invoque o método de criação na coleção de alunos. O objeto args conterá os parâmetros que são passados na consulta. O método de criação da coleção de alunos retornará o id de um objeto de aluno recém-criado.
Etapa 4 - Executar o aplicativo
Criar uma server.jsArquivo. Consulte a etapa 8 no capítulo Configuração do ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo.
O próximo passo é abrir o navegador e digitar o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
//college Id should be matched with data from colleges.json for easy retrieval
mutation {
createStudent(collegeId:"col-2",firstName:"Tim",lastName:"George")
}
A consulta acima criará um objeto aluno no arquivo student.json. A consulta retornará um identificador exclusivo. A resposta da consulta é mostrada abaixo -
{
"data": {
"createStudent": "SkQtxYBUm"
}
}
Para verificar se o objeto aluno foi criado, podemos usar a consulta studentById. Você também pode abrir o arquivo students.json da pasta de dados para verificar a id.
Para usar a consulta studentById, edite o schema.graphql como dado abaixo -
type Query {
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
collegeId:String
}
Edite o resolver.js arquivo conforme fornecido abaixo -
const db = require('./db')
const Query = {
studentById:(root,args,context,info) => {
return db.students.get(args.id);
}
}
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName})
}
}
module.exports = {Query,Mutation}
A seguir está a consulta para obter o aluno por id exclusivo retornado da consulta de mutação -
{
studentById(id:"SkQtxYBUm") {
id
firstName
lastName
}
}
A resposta do servidor é a seguinte -
{
"data": {
"studentById": {
"id": "SkQtxYBUm",
"firstName": "Tim",
"lastName":"George"
}
}
}
Retornando um objeto em mutação
É uma prática recomendada retornar um objeto em mutação. Por exemplo, o aplicativo cliente deseja obter detalhes de alunos e faculdades. Nesse caso, em vez de fazer duas solicitações diferentes, podemos criar uma consulta que retorna um objeto contendo alunos e seus detalhes de faculdade.
Etapa 1 - Editar Arquivo de Esquema
Adicione um novo método chamado addStudent que retorna o objeto em tipo de mutação de schema.graphql.
Vamos aprender como acessar os detalhes da faculdade por meio dos dados do aluno. Adicione o tipo de faculdade no arquivo de esquema.
type Mutation {
addStudent_returns_object(collegeId:ID,firstName:String,lastName:String):Student
createStudent(collegeId:ID,firstName:String,lastName:String):String
}
type College {
id:ID!
name:String
location:String
rating:Float
}
type Student {
id:ID!
firstName:String
lastName:String
college:College
}
Etapa 2 - Atualizar o arquivo resolvers.js
Atualizar um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({
collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName
})
},
// new resolver function
addStudent_returns_object:(root,args,context,info) => {
const id = db.students.create({
collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName
})
return db.students.get(id)
}
}
//for each single student object returned,resolver is invoked
const Student = {
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student,Mutation}
Etapa 3 - Inicie o servidor e digite a consulta de solicitação no GraphiQL
Em seguida, devemos iniciar o servidor e solicitar a consulta em GraphiQL com o seguinte código -
mutation {
addStudent_returns_object(collegeId:"col-101",firstName:"Susan",lastName:"George") {
id
firstName
college{
id
name
}
}
}
A consulta acima adiciona um novo aluno e recupera o objeto aluno junto com o objeto faculdade. Isso economiza viagens de ida e volta para o servidor.
A resposta é a seguinte -
{
"data": {
"addStudent_returns_object": {
"id": "rklUl08IX",
"firstName": "Susan",
"college": {
"id": "col-101",
"name": "AMU"
}
}
}
}
Ao adicionar ou modificar dados, é importante validar a entrada do usuário. Por exemplo, podemos precisar garantir que o valor de um campo não seja sempre nulo. Podemos usar! (non-nullable) digite o marcador no GraphQL para realizar essa validação.
A sintaxe para usar o ! o marcador de tipo é conforme abaixo -
type TypeName {
field1:String!,
field2:String!,
field3:Int!
}
A sintaxe acima garante que todos os campos não sejam nulos.
Se quisermos implementar regras adicionais, como verificar o comprimento de uma string ou se um número está dentro de um determinado intervalo, podemos definir validadores personalizados. A lógica de validação personalizada fará parte da função de resolução. Vamos entender isso com a ajuda de um exemplo.
Ilustração - Implementando validadores personalizados
Vamos criar um formulário de inscrição com validação básica. O formulário terá campos de e-mail, nome e senha.
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta chamada validation-app. Altere o diretório para validation-app no terminal. Siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicionar schema.graphql arquivo na pasta do projeto validation-app e adicione o seguinte código -
type Query {
greeting:String
}
type Mutation {
signUp(input:SignUpInput):String
}
input SignUpInput {
email:String!,
password:String!,
firstName:String!
}
Note- Podemos usar o tipo de entrada SignUpInput para reduzir o número de parâmetros na função de inscrição. Portanto, a função signUp leva apenas um parâmetro do tipo SignUpInput.
Etapa 3 - Criar resolvedores
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const Query = {
greeting:() => "Hello"
}
const Mutation ={
signUp:(root,args,context,info) => {
const {email,firstName,password} = args.input;
const emailExpression = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const isValidEmail = emailExpression.test(String(email).toLowerCase())
if(!isValidEmail)
throw new Error("email not in proper format")
if(firstName.length > 15)
throw new Error("firstName should be less than 15 characters")
if(password.length < 8 )
throw new Error("password should be minimum 8 characters")
return "success";
}
}
module.exports = {Query,Mutation}
A função de resolução, signUp, aceita os parâmetros email, password e firstName. Eles serão passados pela variável de entrada para que possam ser acessados por meio de args.input.
Etapa 4 - Executar o aplicativo
Crie um arquivo server.js. Consulte a etapa 8 no capítulo Configuração de ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usaremos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
mutation doSignUp($input:SignUpInput) { signUp(input:$input)
}
Como a entrada para a função de inscrição é um tipo complexo, precisamos usar variáveis de consulta no graphiql. Para isso, precisamos primeiro dar um nome à consulta e chamá-la doSignUp, a $ input é uma variável de consulta.
A seguinte variável de consulta deve ser inserida na guia de variáveis de consulta do Graphiql -
{
"input":{
"email": "abc@abc",
"firstName": "kannan",
"password": "pass@1234"
}
}
A matriz de erros contém os detalhes dos erros de validação, conforme mostrado abaixo -
{
"data": {
"signUp": null
},
"errors": [
{
"message": "email not in proper format",
"locations": [
{
"line": 2,
"column": 4
}
],
"path": [
"signUp"
]
}
]
}
Temos que inserir uma entrada adequada para cada campo conforme fornecido abaixo -
{
"input":{
"email": "[email protected]",
"firstName": "kannan",
"password": "pass@1234"
}
}
A resposta é a seguinte -
{
"data": {
"signUp": "success"
}
}
Aqui, na consulta abaixo, não estamos atribuindo nenhuma senha.
{
"input":{
"email": "[email protected]",
"firstName": "kannan"
}
}
Se um campo obrigatório não for fornecido, o servidor qraphql exibirá o seguinte erro -
{
"errors": [
{
"message": "Variable \"$input\" got invalid value {\"email\":\"[email protected]\",\"firstName\":\"kannan\"}; Field value.password of required type String! was not provided.",
"locations": [
{
"line": 1,
"column": 19
}
]
}
]
}
Os aplicativos da Web enviam e recuperam dados de forma assíncrona (em segundo plano). O AJAX permite que os sites carreguem conteúdo na tela sem atualizar a página. jQuery fornece vários métodos para funcionalidade AJAX, tornando mais fácil usar AJAX. Neste capítulo, aprenderemos como podemos integrar GraphQL com jQuery.
Considere um aplicativo que usa arquitetura cliente-servidor. Podemos construir uma página da web front end que solicite dados de um servidor GraphQL. A página da Web fará chamadas AJAX usando jQuery para o servidor GraphQL.
Para integrar GraphQL com JQuery, vamos inspecionar os cabeçalhos de solicitação GraphiQL e entender os parâmetros de solicitação.
Comece o hello-worldapp (consulte o capítulo 6 para a ilustração relevante). Digite a consulta graphql {saudação} na janela GraphiQL. Clique com o botão direito e inspecione ou pressione (ctrl + shift + I) no cromo para ir para a guia de rede conforme mostrado abaixo -
Do simples hello-world exemplo, podemos entender que http method usado é POST. Agora, no navegador, role para baixo até a seção do cabeçalho para visualizar a carga útil da solicitação .
Depois de clicar em view code, você verá o seguinte na seção de solicitação de carga útil do chrome.
{"query":"{\n greeting\n}","variables":null,"operationName":null}
Observe também o URL da solicitação, http://localhost:9000/graphql que deve ser chamado do aplicativo cliente.
Ilustração
Vamos entender como integrar GraphQL com JQuery usando um processo passo a passo.
Configurando o Servidor
Aprenderemos a configurar o servidor usando as seguintes etapas -
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta chamada jquery-server-app. Mude seu diretório para jquery-server-app a partir do terminal. Siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicione o arquivo schema.graphql na pasta do projeto jquery-server-app e adicione o seguinte código -
type Query
{
greeting: String
sayHello(name:String!):String
}
O arquivo definiu duas consultas greeting e sayHello. A consulta sayHello aceita um parâmetro de string e retorna outra string. O parâmetro para a função sayHello () não é nulo.
Etapa 3 - Criar resolvedores
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const Query =
{
greeting: () => 'Hello GraphQL From TutorialsPoint !!' ,
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}
Aqui, greeting e sayHellosão dois resolvedores. No resolvedor sayHello, o valor passado para o parâmetro name pode ser acessado por meio de args. Para acessar as funções do resolvedor fora do módulo, o objeto Query deve ser exportado usandomodule.exports.
Etapa 4 - Executar o aplicativo
Crie um arquivo server.js. Consulte a etapa 8 no capítulo Configuração do ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
greeting,
sayHello(name:"Mohtashim")
}
A resposta do servidor é a seguinte -
{
"data": {
"greeting": "Hello GraphQL From TutorialsPoint !!",
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
Configurando o Cliente
Uma vez que já configuramos o servidor, agora aprenderemos como configurar o cliente.
Etapa 1 - Crie uma nova pasta jquery-client-app fora da pasta do projeto atual
Primeiro, vamos criar uma pasta chamada jquery-client-app fora da pasta do projeto.
Etapa 2 - Criar uma página HTML index.html para integração jQuery
Vamos criar um aplicativo cliente em jquery e chamar ambos os métodos. A seguir está o código para index.html Arquivo. o index.html página envia solicitações ao servidor quando os botões - Greet e SayHellosão clicados. Faremos uma solicitação assíncrona usando a função $ .ajax ().
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() { $("#btnSayhello").click(function() {
const name = $("#txtName").val(); console.log(name); $("#SayhelloDiv").html('loading....');
$.ajax({url: "http://localhost:9000/graphql", contentType: "application/json",type:'POST', data: JSON.stringify({ query:`{ sayHello(name:"${name}")}`
}),
success: function(result) {
console.log(JSON.stringify(result))
$("#SayhelloDiv").html("<h1>"+result.data.sayHello +"</h1>"); } }); }); $("#btnGreet").click(function() {
$("#greetingDiv").html('loading....'); //https://kannan-first-graphql-app.herokuapp.com/graphql $.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",
type:'POST',
data: JSON.stringify({
query:`{greeting}`
}),
success: function(result) {
$("#greetingDiv").html("<h1>"+result.data.greeting+"</h1>");
}
});
});
});
</script>
</head>
<body>
<h1>Jquery Client </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"> </div>
</section>
<br/> <br/> <br/>
<hr/>
<section>
Enter a name:<input id = "txtName" type = "text" value = "kannan"/>
<button id = "btnSayhello">SayHello</button>
<div id = "SayhelloDiv"> </div>
</section>
</body>
</html>
Abra este arquivo no navegador e clique no botão para ver a resposta. O resultado será como fornecido abaixo -
React é uma biblioteca Javascript para construir interfaces de usuário. Este capítulo explica como integrar o GraphQL a um aplicativo React.
Ilustração
A maneira mais rápida de configurar um projeto react é usando a ferramenta Create React App . Nas seções subsequentes, aprenderemos como configurar o Servidor e o Cliente.
Configurando o Servidor
Para configurar o servidor, siga as etapas abaixo -
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta react-server-app. Mude seu diretório para react-server-app do terminal. Siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicionar schema.graphql arquivo na pasta do projeto react-server-app e adicione o seguinte código -
type Query
{
greeting: String
sayHello(name:String!):String
}
O arquivo definiu duas consultas - saudação e dizer Olá. A consulta sayHello aceita um parâmetro de string e retorna outra string. O parâmetro para a função sayHello () não é nulo.
Etapa 3 - Criar resolvedores
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const Query =
{
greeting: () => 'Hello GraphQL From TutorialsPoint !!' ,
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}
Aqui, cumprimentar e dizer olá são dois resolvedores. No resolvedor sayHello, o valor passado para o parâmetro name pode ser acessado por meio de args. Para acessar as funções do resolvedor fora do módulo, o objeto Query deve ser exportado usando module.exports.
Etapa 4 - Executar o aplicativo
Crie um arquivo server.js. Consulte a etapa 8 no capítulo Configuração de ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
greeting,
sayHello(name:"Mohtashim")
}
A resposta do servidor é fornecida abaixo -
{
"data": {
"greeting": "Hello GraphQL From TutorialsPoint !!",
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
Configurando o Cliente
Abra um novo terminal para o cliente. O terminal do servidor deve ser mantido em execução antes de executar o aplicativo cliente. O aplicativo React será executado na porta número 3000 e o aplicativo do servidor na porta número 9000.
Etapa 1 - Criar um projeto React hello-world-client
No terminal do cliente, digite o seguinte comando -
npx create-react-app hello-world-client
Isso instalará tudo o que é necessário para um aplicativo típico de reação. onpx utilidade e create-react-appferramenta cria um projeto com o nome hello-world-client. Assim que a instalação for concluída, abra o projeto no VSCode.
Etapa 2 - Iniciar o cliente hello-world
Altere o caminho da pasta atual no terminal para hello-world-client. Digite npm start para iniciar o projeto. Isso executará um servidor de desenvolvimento na porta 3000, abrirá automaticamente o navegador e carregará a página de índice.
Isso é mostrado na imagem abaixo -
Etapa 3 - modificar o componente do aplicativo
No App.js dentro da pasta src, adicione duas funções, uma para carregar saudação e outra para carregar mensagens de dizer Olá.
A seguir está a função loadGreeting que envia a consulta GraphQL para saudação.
async function loadGreeting() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:'{greeting}'})
})
const rsponseBody = await response.json();
return rsponseBody.data.greeting;
console.log("end of function")
}
A seguir está o loadSayhello função que envia a consulta GraphQL para sayHello -
async function loadSayhello(name) {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
})
}
O completo App.js arquivo é mostrado abaixo -
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
async function loadGreeting() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:'{greeting}'})
})
const rsponseBody = await response.json();
return rsponseBody.data.greeting;
console.log("end of function")
}
async function loadSayhello(name) {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
})
const rsponseBody = await response.json();
return rsponseBody.data.sayHello;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {greetingMessage:'',sayHelloMessage:'',userName:''}
this.updateName = this.updateName.bind(this);
this.showSayHelloMessage = this.showSayHelloMessage.bind(this);
this.showGreeting = this.showGreeting.bind(this);
}
showGreeting() {
loadGreeting().then(g => this.setState({greetingMessage:g+" :-)"}))
}
showSayHelloMessage() {
const name = this.state.userName;
console.log(name)
loadSayhello(name).then(m => this.setState({sayHelloMessage:m}))
}
updateName(event) {
this.setState({userName:event.target.value})
}
render() {
return (
<div className = "App">
<header className = "App-header">
<img src = {logo} className = "App-logo" alt = "logo" />
<h1 className = "App-title">Welcome to React</h1>
</header>
<br/><br/>
<section>
<button id = "btnGreet" onClick = {this.showGreeting}>Greet</button>
<br/> <br/>
<div id = "greetingDiv">
<h1>{this.state.greetingMessage}</h1>
</div>
</section>
<hr/>
<section>
Enter a name:<input id = "txtName" type = "text" onChange = {this.updateName}
value = {this.state.userName}/>
<button id = "btnSayhello" onClick = {this.showSayHelloMessage}>SayHello</button>
<br/>
user name is:{this.state.userName} <br/>
<div id = "SayhelloDiv">
<h1>{this.state.sayHelloMessage}</h1>
</div>
</section>
</div>
);
}
}
export default App;
Quando os dois aplicativos estiverem em execução, clique no botão saudar. Em seguida, insira um nome na caixa de texto e clique no botão dizer Olá. O resultado será como fornecido abaixo -
Usamos o Apollo Server para construir a especificação do graphql no lado do servidor. É rápido e fácil construir um servidor GraphQL pronto para produção. Agora vamos entender o lado do cliente.
O Cliente Apollo é a melhor maneira de usar o GraphQL para construir aplicativos cliente. O cliente foi projetado para ajudar o desenvolvedor a construir rapidamente uma IU que busca dados com GraphQL e pode ser usada com qualquer front-end JavaScript.
O cliente Apollo oferece suporte às seguintes plataformas -
Sr. Não. | Plataforma e estrutura |
---|---|
1 | Javascript React, Angular, Vue, Meteor, Ember |
2 | WebComponents Polímero, lit-apollo |
3 | Native Mobile Android nativo com Java, iOS nativo com Swift |
O cache é um dos principais recursos do Apollo Client. apollo-boost é um pacote de conveniência que traz um monte de outras dependências.
Ilustração
Vamos ver como usar o Apollo Client para construir aplicativos cliente usando as seguintes etapas -
Configurando o servidor
Temos que seguir as etapas abaixo para configurar um servidor -
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta apollo-server-app. Mude seu diretório para apollo-server-app do terminal. Em seguida, siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicionar schema.graphql arquivo na pasta do projeto apollo-server-app e adicione o seguinte código -
type Query
{
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
college:College
}
type College {
id:ID!
name:String
location:String
rating:Float
}
Step 3 − Add Resolvers
Create a file resolvers.js in the project folder and add the following code −
const db = require('./db')
const Query = {
//resolver function for students returns list
students:() => db.students.list(),
}
const Student = {
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student}
Step 4 − Run the Application
Create a server.js file. Refer step 8 in the Environment Setup Chapter. Execute the command npm start in the terminal. The server will be up and running on 9000 port. Here, we will use GraphiQL as a client to test the application.
Open browser and type the URL http://localhost:9000/graphiql. Type the following query in the editor.
{
students{
id
firstName
college{
name
}
}
}
The response for the query is as given below −
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"college": {
"name": "CUSAT"
}
},
{
"id": "S1002",
"firstName": "Kannan",
"college": {
"name": "AMU"
}
},
{
"id": "S1003",
"firstName": "Kiran",
"college": {
"name": "AMU"
}
}
]
}
}
Setting up the Client
Open a new terminal for client. The server terminal should be kept running before executing the client application. React application will be running on port number 3000 and server application on port number 9000.
Step 1 − Create a React Application
In the client terminal, type the following command −
npx create-react-app hello-world-client
This will install everything needed for a typical react application. The npx utility and create-react-app tool create a project with name hello-world-client. Once the installation is completed, open the project in VSCode.
Step 2 − Start hello-world-client
Change the current folder path in the terminal to hello-world-client. Type npm start to launch the project. This will run a development server at port 3000 and will automatically open the browser and load the index page.
This is shown in the screenshot given below −
Step 3 − Install Apollo Client Libraries
To install an Apollo Client, open a new terminal and be in current project folder path. Type the following command −
npm install apollo-boost graphql
This will download the graphql libraries for client side and also the Apollo Boost package. We can cross check this by typing npm view in apollo-boost dependencies. This will have many dependencies as shown below −
{
'apollo-cache': '^1.1.15',
'apollo-cache-inmemory': '^1.2.8',
'apollo-client': '^2.4.0',
'apollo-link': '^1.0.6',
'apollo-link-error': '^1.0.3',
'apollo-link-http': '^1.3.1',
'apollo-link-state': '^0.4.0',
'graphql-tag': '^2.4.2'
}
We can clearly see that Apollo-Client library is installed.
Step 4 − Modify the App Component in index.js File
With Apollo Client, we can directly call server without the use of fetch API. Also, the queries and mutations should not be embedded in a string made with back tick notation. This is because, the gql function directly parses the queries. This means, a programmer can directly write queries in the same way when writing queries in GraphiQL tool. gql is a tag function which will parse the template string written in back tick notation to graphql query object. The Apollo Client query method returns a promise.
Following code snippet shows how to import Apollo Client −
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const endPointUrl = 'http://localhost:9000/graphql'
const client = new ApolloClient({
link: new HttpLink({uri:endPointUrl}),
cache:new InMemoryCache()
});
In the previous chapter, we discussed how to use fetch API for HTTP requests. The following code shows how to use gql function. The loadStudentsAsync function uses graphql client to query the server.
async function loadStudentsAsync() {
const query = gql`
{
students{
id
firstName
lastName
college{
name
}
}
}`
const {data} = await client.query({query}) ;
return data.students;
}
You only need to keep the index.js in src folder and index.html in public folder; all other files that are auto generated can be removed.
The directory structure is given below −
hello-world-client /
-->node_modules
-->public
index.html
-->src
index.js
-->package.json
Following is the index.js in react application −
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
// apollo client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const endPointUrl = 'http://localhost:9000/graphql'
const client = new ApolloClient({
link: new HttpLink({uri:endPointUrl}),
cache:new InMemoryCache()
});
async function loadStudentsAsync() {
const query = gql`
{
students{
id
firstName
lastName
college{
name
}
}
}
`
const {data} = await client.query({query}) ;
return data.students;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
students:[]
}
this.studentTemplate = [];
}
async loadStudents() {
const studentData = await loadStudentsAsync();
this.setState({
students: studentData
})
console.log("loadStudents")
}
render() {
return(
<div>
<input type = "button" value = "loadStudents" onClick = {this.loadStudents.bind(this)}/>
<div>
<br/>
<hr/>
<table border = "3">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>college Name</td>
</tr>
</thead>
<tbody>
{
this.state.students.map(s => {
return (
<tr key = {s.id}>
<td>
{s.firstName}
</td>
<td>
{s.lastName}
</td>
<td>
{s.college.name}
</td>
</tr>
)
})
}
</tbody>
</table>
</div>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
The react application will load students from GraphQL server, once we click on loadStudents button as shown below −
Authentication is the process or action of verifying the identity of a user or a process. It is important that an application authenticates a user to ensure that the data is not available to an anonymous user. In this section, we will learn how to authenticate a GraphQL client.
Express JWT
In this example, we will use jQuery to create a client application. To authenticate requests, we will use express-jwt module on the server-side.
The express-jwt module is a middleware that lets you authenticate HTTP requests using JWT tokens. JSON Web Token (JWT) is a long string that identifies the logged in user.
Once the user logs in successfully, the server generates a JWT token. This token distinctly identifies a log. In other words, the token is a representation of user's identity. So next time, when the client comes to the server, it has to present this token to get the required resources. The client can be either a mobile application or a web application.
Illustration
We will follow a step-wise procedure to understand this illustration.
Setting up the Server
Following are the steps for setting up the server −
Step 1 − Download and Install Required Dependencies for the Project
Create a folder auth-server-app. Change your directory to auth-server-app from the terminal. Follow steps 3 to 5 explained in the Environment Setup chapter.
Step 2 − Create a Schema
schema.graphql auth-server-apptype Query
{
greetingWithAuth:String
}
Step 3 − Add Resolvers
Create a file resolvers.js in the project folder and add the following code −
The resolver will verify if an authenticated user object is available in the context object of GraphQL. It will raise an exception if an authenticated user is not available.
const db = require('./db')
const Query = {
greetingWithAuth:(root,args,context,info) => {
//check if the context.user is null
if (!context.user) {
throw new Error('Unauthorized');
}
return "Hello from TutorialsPoint, welcome back : "+context.user.firstName;
}
}
module.exports = {Query}
Step 4 − Create Server.js File
The authentication middleware authenticates callers using a JSON Web Token. The URL for authentication is http://localhost:9000/login.
This is a post operation. The user has to submit his email and password which will be validated from the backend. If a valid token is generated using jwt.sign method, the client will have to send this in header for subsequent requests.
If the token is valid, req.user will be set with the JSON object decoded to be used by later middleware for authorization and access control.
O código a seguir usa dois módulos - jsonwebtoken e express-jwt para autenticar solicitações -
Quando o usuário clica no greetbotão, uma solicitação para a rota / graphql é emitida. Se o usuário não estiver autenticado, ele será solicitado a se autenticar.
O usuário é apresentado a um formulário que aceita ID de e-mail e senha. Em nosso exemplo, a rota / login é responsável por autenticar o usuário.
A rota / login verifica se uma correspondência é encontrada no banco de dados para as credenciais fornecidas pelo usuário.
Se as credenciais forem inválidas, uma exceção HTTP 401 será retornada ao usuário.
Se as credenciais forem válidas, um token será gerado pelo servidor. Este token é enviado como parte da resposta ao usuário. Isso é feito pela função jwt.sign.
const expressJwt = require('express-jwt');
const jwt = require('jsonwebtoken');
//private key
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
app.post('/login', (req, res) => {
const {email, password} = req.body;
//check database
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
//generate a token based on private key, token doesn't have an expiry
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
Para cada solicitação, a função app.use () será chamada. Isso, por sua vez, invocará o middleware expressJWT. Este middleware irá decodificar o JSON Web Token. O ID do usuário armazenado no token será recuperado e armazenado como um usuário de propriedade no objeto de solicitação.
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
Para disponibilizar a propriedade do usuário dentro do contexto GraphQL, esta propriedade é atribuída ao context objeto como mostrado abaixo -
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
Crio server.js no caminho da pasta atual. O arquivo server.js completo é o seguinte -
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const expressJwt = require('express-jwt'); //auth
const jwt = require('jsonwebtoken'); //auth
const db = require('./db');
var port = process.env.PORT || 9000
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json(), expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//authenticate students
app.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
app.listen(port, () => console.info(`Server started on port ${port}`));
Etapa 5 - Executar o aplicativo
Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usamos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
greetingWithAuth
}
Na resposta abaixo, ocorreu um erro porque não somos um usuário autenticado.
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
Na próxima seção, vamos criar um aplicativo cliente para autenticação.
Configurando o cliente JQuery
No aplicativo cliente, um botão de saudação é fornecido para invocar o esquema greetingWithAuth. Se você clicar no botão sem fazer login, será exibida a mensagem de erro abaixo -
Depois de fazer o login com um usuário disponível no banco de dados, a seguinte tela aparecerá -
Acessar greeting, precisamos primeiro acessar o URL http://localhost:9000/login rota como abaixo.
A resposta conterá o token gerado a partir do servidor.
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus') .html("authenticated successfully") .css({"color":"green",'font-weight':'bold'}); $("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
Após um login bem-sucedido, podemos acessar o esquema greetingWithAuth conforme mostrado abaixo. Deve haver um cabeçalho de autorização para todas as solicitações subsequentes com token de portador.
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
A seguir está o código para index.html -
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() { let loginToken = ""; $("#btnGreet").click(function() {
$.ajax({url: "http://localhost:9000/graphql", contentType: "application/json", headers: {"Authorization": 'bearer '+loginToken}, type:'POST', data: JSON.stringify({ query:`{greetingWithAuth}` }), success: function(result) { $("#greetingDiv").html("<h1>"+result.data.greetingWithAuth+"</h1>")
},
error:function(jQxhr,error) {
if(jQxhr.status == 401) {
$("#greetingDiv").html('please authenticate first!!') .css({"color":"red",'font-weight':'bold'}) return; } $("#greetingDiv").html('error').css("color","red");
}
});
});
$('#btnAuthenticate').click(function() { var email = $("#txtEmail").val();
var password = $("#txtPwd").val(); if(email && password) { $.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus') .html("authenticated successfully") .css({"color":"green",'font-weight':'bold'}); $("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
}else alert("email and pwd empty")
})
});
</script>
</head>
<body>
<h1> GraphQL Authentication </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"></div>
</section>
<br/> <br/> <br/>
<hr/>
<section id = "LoginSection">
<header>
<h2>*Login first to access greeting </h2>
</header>
<input type = "text" value = "[email protected]" placeholder = "enter email" id = "txtEmail"/>
<br/>
<input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
<br/>
<input type = "button" id = "btnAuthenticate" value = "Login"/>
<p id = "authStatus"></p>
</section>
</body>
</html>
Cache é o processo de armazenar dados em uma área de armazenamento temporário chamada cache. Quando você retorna a uma página que visitou recentemente, o navegador pode obter esses arquivos do cache em vez do servidor original. Isso economiza seu tempo e rede da carga de tráfego adicional.
Os aplicativos cliente que interagem com o GraphQL são responsáveis pelo armazenamento em cache dos dados em sua extremidade. Um padrão possível para isso é reservar um campo, como id, para ser um identificador globalmente exclusivo.
Cache InMemory
InMemoryCache é um armazenamento de dados normalizado comumente usado em aplicativos cliente GraphQL sem o uso de outra biblioteca como Redux.
O código de amostra para usar InMemoryCache com ApolloClient é fornecido abaixo -
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const cache = new InMemoryCache();
const client = new ApolloClient({
link: new HttpLink(),
cache
});
O construtor InMemoryCache usa um objeto de configuração opcional com propriedades para personalizar seu cache.
Sr. Não. | Parâmetro e Descrição |
---|---|
1 | addTypename Um booleano para determinar se deve ser adicionado __typename ao documento (padrão: true) |
2 | dataIdFromObject Uma função que pega um objeto de dados e retorna um identificador único para ser usado ao normalizar os dados na loja |
3 | fragmentMatcher Por padrão, o InMemoryCache usa um matcher de fragmento heurístico |
4 | cacheRedirects Um mapa de funções para redirecionar uma consulta para outra entrada no cache antes que uma solicitação ocorra. |
Ilustração
Criaremos um aplicativo de página única no ReactJS com duas guias - uma para a guia inicial e outra para alunos. A guia de alunos carregará dados de uma API do servidor GraphQL. O aplicativo consultará os dados dos alunos quando o usuário navegar da guia inicial para a guia dos alunos. Os dados resultantes serão armazenados em cache pelo aplicativo.
Também consultaremos o tempo do servidor usando getTimecampo para verificar se a página está em cache. Se os dados forem retornados do cache, a página exibirá a hora da primeira solicitação enviada ao servidor. Se os dados forem resultado de uma nova solicitação feita ao servidor, ele sempre mostrará a hora mais recente do servidor.
Configurando o Servidor
A seguir estão as etapas para configurar o servidor -
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta cache-server-app. Mude seu diretório para cache-server-app do terminal. Siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicionar schema.graphql arquivo na pasta do projeto cache-server-app e adicione o seguinte código -
type Query {
students:[Student]
getTime:String
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}
Etapa 3 - Adicionar resolvedores
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const db = require('./db')
const Query = {
students:() => db.students.list(),
getTime:() => {
const today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
return `${h}:${m}:${s}`;
}
}
module.exports = {Query}
Etapa 4 - Executar o aplicativo
Crie um arquivo server.js. Consulte a etapa 8 no capítulo Configuração de ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usaremos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
getTime
students {
id
firstName
}
}
O exemplo de resposta mostra os nomes dos alunos e o horário do servidor.
{
"data": {
"getTime": "22:18:42",
"students": [
{
"id": "S1001",
"firstName": "Mohtashim"
},
{
"id": "S1002",
"firstName": "Kannan"
},
{
"id": "S1003",
"firstName": "Kiran"
}
]
}
}
Configurando o ReactJS Client
Abra um novo terminal para o cliente. O terminal do servidor deve ser mantido em execução antes de executar o aplicativo cliente. O aplicativo React será executado na porta número 3000 e o aplicativo do servidor na porta número 9000.
Etapa 1 - Criar um aplicativo React
No terminal do cliente, digite o seguinte comando -
npx create-react-app hello-world-client
Isso instalará tudo o que é necessário para um aplicativo típico de reação. onpx utility e create-react-appferramentas criam um projeto com o nome hello-world-client. Assim que a instalação for concluída, abra o projeto no VSCode.
Instale os módulos do roteador para reagir usando o seguinte comando - npm install react-router-dom.
Etapa 2 - Iniciar o cliente hello-world
Altere o caminho da pasta atual no terminal para hello-world-client. Digite npm start para iniciar o projeto. Isso executará um servidor de desenvolvimento na porta 3000, abrirá automaticamente o navegador e carregará a página de índice.
Isso é mostrado na imagem abaixo -
Etapa 3 - Instale as bibliotecas cliente Apollo
Para instalar um cliente Apollo, abra um novo terminal e esteja no caminho da pasta do projeto atual. Digite o seguinte comando -
npm install apollo-boost graphql
Isso baixará as bibliotecas graphql para o lado do cliente e também o pacote Apollo Boost. Podemos verificar isso digitando npm view apollo-boost dependencies. Isso terá muitas dependências, conforme mostrado abaixo -
{
'apollo-cache': '^1.1.15',
'apollo-cache-inmemory': '^1.2.8',
'apollo-client': '^2.4.0',
'apollo-link': '^1.0.6',
'apollo-link-error': '^1.0.3',
'apollo-link-http': '^1.3.1',
'apollo-link-state': '^0.4.0',
'graphql-tag': '^2.4.2'
}
Podemos ver claramente que a biblioteca cliente-apollo está instalada.
Etapa 4 - Modificar o componente do aplicativo no arquivo index.js
Para uma aplicação simples de reação, você só precisa manter o index.js dentro src pasta e index.htmlem pasta pública; todos os outros arquivos gerados automaticamente podem ser removidos.
A estrutura do diretório é fornecida abaixo -
hello-world-client /
-->node_modules
-->public
index.html
-->src
index.js
students.js
-->package.json
Adicione um arquivo student.js adicional que conterá o componente Students. Os detalhes do aluno são obtidos por meio do Componente do aluno. No componente de aplicativo, estamos usando um HashRouter.
A seguir está o index.js na aplicação de reação -
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {HashRouter, Route, Link} from 'react-router-dom'
//components
import Students from './students'
class App extends Component {
render() {
return(
<div><h1>Home !!</h1>
<h2>Welcome to React Application !! </h2>
</div>
)
}
}
function getTime() {
var d = new Date();
return d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()
}
const routes = <HashRouter>
<div>
<h4>Time from react app:{getTime()}</h4>
<header>
<h1> <Link to="/">Home</Link>
<Link to = "/students">Students</Link> </h1>
</header>
<Route exact path = "/students" component = {Students}></Route>
<Route exact path = "/" component = {App}></Route>
</div>
</HashRouter>
ReactDOM.render(routes, document.querySelector("#root"))
Etapa 5 - Editar alunos do componente em Students.js
No Componente de Alunos, usaremos as duas abordagens a seguir para carregar dados -
Fetch API (loadStudents_noCache) - Isso irá disparar uma nova solicitação toda vez que clicar na guia do aluno.
Apollo Client (loadWithApolloclient) - Isso irá buscar dados do cache.
Adicionar uma função loadWithApolloclientquais consultas para alunos e tempo do servidor. Esta função habilitará o cache. Aqui, usamos uma função gql para analisar a consulta.
async loadWithApolloclient() {
const query = gql`{
getTime
students {
id
firstName
}
}`;
const {data} = await client.query({query})
return data;
}
o Fetch APIé uma interface simples para buscar recursos. Fetch torna mais fácil fazer solicitações da web e lidar com respostas do que com o XMLHttpRequest mais antigo. O método a seguir mostra o carregamento de dados diretamente usando fetch api -
async loadStudents_noCache() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{
getTime
students {
id
firstName
}
}`})
})
const rsponseBody = await response.json();
return rsponseBody.data;
}
No construtor de StudentsComponent, chame o loadWithApolloClientmétodo. O completo Student.js o arquivo está abaixo -
import React, {Component} from 'react';
import { Link} from 'react-router-dom'
//Apollo Client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const client = new ApolloClient({
link: new HttpLink({uri:`http://localhost:9000/graphql`}),
cache:new InMemoryCache()
})
class Students extends Component {
constructor(props) {
super(props);
this.state = {
students:[{id:1,firstName:'test'}],
serverTime:''
}
this.loadWithApolloclient().then(data => {
this.setState({
students:data.students,
serverTime:data.getTime
})
})
}
async loadStudents_noCache() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{
getTime
students {
id
firstName
}
}`})
})
const rsponseBody = await response.json();
return rsponseBody.data;
}
async loadWithApolloclient() {
console.log("inside apollo client function")
const query = gql`{
getTime
students {
id
firstName
}
}`;
const {data} = await client.query({query})
return data;
}
render() {
return(
<div>
<h3>Time from GraphQL server :{this.state.serverTime}</h3>
<p>Following Students Found </p>
<div>
<ul>
{
this.state.students.map(s => {
return(
<li key = {s.id}>
{s.firstName}
</li>
)
})
}
</ul>
</div>
</div>
)
}
}
export default Students
Etapa 6 - Executar o aplicativo React com npm start
Você pode testar o aplicativo Rea, alternando da guia inicial para a guia alunos. Uma vez que a guia de alunos é carregada com dados do servidor. Ele armazenará os dados em cache. Você pode testá-lo alternando da guia casa para a guia de alunos várias vezes. A saída será como mostrado abaixo -
Se você carregou a página dos alunos primeiro digitando o URL, http://localhost:3000/#/students, você pode ver que o tempo de carregamento para o app react e GraphQL seria aproximadamente o mesmo. Depois disso, se você alternar para a visualização inicial e retornar ao servidor GraphQL, a hora não mudará. Isso mostra que os dados estão armazenados em cache.
Etapa 7 - Alterar a chamada loadWithApolloclient para loadStudents_noCache
Se você alterar o método de carregamento para loadStudents_noCacheno construtor de StudentComponent, a saída não armazenará os dados em cache. Isso mostra a diferença entre armazenamento em cache e não armazenamento em cache.
this.loadStudents_noCache().then(data => {
this.setState({
students:data.students,
serverTime:data.getTime
})
})
A partir da saída acima, é claro que se você alternar entre as guias, o tempo do servidor graphql será sempre o mais recente, o que significa que os dados não são armazenados em cache.