GraphQL é a nova palavra-chave no desenvolvimento de API. Enquanto as APIs RESTful continuam sendo a forma mais popular de expor dados de aplicativos, elas vêm com muitas limitações que o GraphQL planeja resolver.
GraphQL é uma linguagem de consulta criada pelo Facebook, transformada em um projeto de código aberto em 2015. Ele oferece uma sintaxe intuitiva e flexível para descrever e acessar dados em uma API.
Este guia irá explorar como construir um projeto GraphQL Node.js. Usaremos o GraphQL para construir um aplicativo Todo no framework web do Express.js para Node.
O que é GraphQL?
A partir da documentação oficial: “GraphQL é uma linguagem de consulta para APIs e um tempo de execução para preencher essas consultas com seus dados existentes. GraphQL fornece uma descrição completa e compreensível dos dados em sua API, dá aos clientes o poder de pedir exatamente o que eles precisam e nada mais, facilita a evolução das APIs ao longo do tempo e permite poderosas ferramentas de desenvolvimento”
GraphQL é um tempo de execução do lado do servidor para executar consultas usando o tipo de sistema que você definiu para seus dados. Além disso, o GraphQL não está ligado a nenhum banco de dados ou mecanismo de armazenamento específico. Ao invés disso, ele é apoiado pelo seu código e armazenamento de dados existentes. Você pode obter uma comparação detalhada dessas tecnologias com o guia GraphQL vs RESTful API.
Para criar um serviço GraphQL, você começa definindo tipos de schemas e criando campos usando esses tipos. Em seguida, você fornece um resolvedor de função a ser executado em cada campo e digita sempre que os dados são solicitados pelo lado do cliente.
Terminologia do GraphQL
O sistema do tipo GraphQL é usado para descrever quais dados podem ser consultados e quais dados você pode manipular. É o núcleo do GraphQL. Discutiremos diferentes maneiras de descrever e manipular os dados no GraphQ.
Tipos de objetos
Os tipos de objetos GraphQL são modelos de dados contendo campos fortemente digitados. Deve haver um mapeamento de 1 para 1 entre seus modelos e os tipos de GraphQL. Abaixo está um exemplo de tipos de GraphQL:
type User {
id: ID! # The "!" means required
firstname: String
lastname: String
email: String
username: String
todos: [Todo] # Todo is another GraphQL type
}
Query
GraphQL Query define todas as consultas que um cliente pode executar na API GraphQL. Você deve definir um RootQuery
que conterá todas as consultas existentes por convenção.
Abaixo, definimos e mapeamos as consultas para a API RESTful correspondente:
type RootQuery {
user(id: ID): User # Corresponds to GET /api/users/:id
users: [User] # Corresponds to GET /api/users
todo(id: ID!): Todo # Corresponds to GET /api/todos/:id
todos: [Todo] # Corresponds to GET /api/todos
}
Mutações
Se as consultas do GraphQL são pedidos GET
, as mutações são POST
, PUT
, PATCH
, e DELETE
pedidos que manipulam a API do GraphQL.
Colocaremos todas as mutações em um único RootMutation
para demonstrar:
type RootMutation {
createUser(input: UserInput!): User # Corresponds to POST /api/users
updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users
removeUser(id: ID!): User # Corresponds to DELETE /api/users
createTodo(input: TodoInput!): Todo
updateTodo(id: ID!, input: TodoInput!): Todo
removeTodo(id: ID!): Todo
}
Você notou o uso de -input
tipos para as mutações como UserInput
, TodoInput
. É sempre a melhor prática definir sempre os tipos de entrada para criar e atualizar seus recursos.
Um tipo de entrada pode ser definido como:
input UserInput {
firstname: String!
lastname: String
email: String!
username: String!
}
Resolvers
Os resolvers dizem ao GraphQL o que fazer quando cada consulta ou mutação é solicitada. É uma função básica que faz o trabalho duro de acertar a camada do banco de dados para fazer as operações CRUD (criar, ler, atualizar, excluir), acertar um endpoint interno RESTful API, ou chamar um microsserviço para atender a solicitação do cliente.
Você pode criar um novo arquivo resolvers.js e adicionar o seguinte código:
import sequelize from '../models';
export default function resolvers () {
const models = sequelize.models;
return {
// Resolvers for Queries
RootQuery: {
user (root, { id }, context) {
return models.User.findById(id, context);
},
users (root, args, context) {
return models.User.findAll({}, context);
}
},
User: {
todos (user) {
return user.getTodos();
}
},
}
// Resolvers for Mutations
RootMutation: {
createUser (root, { input }, context) {
return models.User.create(input, context);
},
updateUser (root, { id, input }, context) {
return models.User.update(input, { ...context, where: { id } });
},
removeUser (root, { id }, context) {
return models.User.destroy(input, { ...context, where: { id } });
},
// ... Resolvers for Todos go here
}
}
Schema
Um Schema GraphQL é o que expõe o GraphQL ao mundo. Portanto, tipos, consultas e mutações estão contidos em schemas e expostos ao mundo.
Abaixo está como expor tipos, consultas e mutações para o mundo:
schema {
query: RootQuery
mutation: RootMutation
}
No script acima, incluímos o RootQuery
e RootMutation
que criamos anteriormente para ser exposto ao mundo.
Como o GraphQL funciona com o Node.js e Express.js?
GraphQL fornece uma implementação para todas as principais linguagens de programação, e o Node.js não está isento. No site oficial do GraphQL, há uma seção para suporte ao JavaScript, e também, há outras implementações do GraphQL para tornar simples a escrita e a codificação.
GraphQL Apollo fornece uma implementação para Node.js e Express.js e facilita começar a usar o GraphQL.
Você aprenderá como criar e desenvolver seu primeiro aplicativo GraphQL no Node.js e Express.js backend framework usando o GraphQL Apollo na próxima seção.
Configurando o GraphQL com o Express.js
A construção de um servidor GraphQL API com o Express.js é simples para começar. Nesta seção, vamos explorar como construir um servidor GraphQL.
Inicialize o projeto com o Express.js
Primeiro, você precisa instalar e configurar um novo projeto Express.js. Crie uma pasta para o seu projeto e instale o Express.js usando este comando:
cd <project-name> && npm init -y
npm install express
O comando acima cria um novo arquivo package.json e instala a biblioteca Express.js em seu projeto.
A seguir, estruturaremos nosso projeto como mostrado na imagem abaixo. Ele conterá diferentes módulos para as funcionalidades do projeto, tais como usuários, todos, etc.
Inicialize o GraphQL
Vamos começar instalando as dependências do GraphQL Express.js. Execute o seguinte comando para instalar:
npm install apollo-server-express graphql @graphql-tools/schema --save
Criando schemas e Types
A seguir, vamos criar um arquivo index.js na pasta de módulos e adicionar o seguinte snippet de código:
const { gql } = require('apollo-server-express');
const users = require('./users');
const todos = require('./todos');
const { GraphQLScalarType } = require('graphql');
const { makeExecutableSchema } = require('@graphql-tools/schema');
const typeDefs = gql`
scalar Time
type Query {
getVersion: String!
}
type Mutation {
version: String!
}
`;
const timeScalar = new GraphQLScalarType({
name: 'Time',
description: 'Time custom scalar type',
serialize: (value) => value,
});
const resolvers = {
Time: timeScalar,
Query: {
getVersion: () => `v1`,
},
};
const schema = makeExecutableSchema({
typeDefs: [typeDefs, users.typeDefs, todos.typeDefs],
resolvers: [resolvers, users.resolvers, todos.resolvers],
});
module.exports = schema;
Análise do código
Vamos rever o snippet de código passo a passo:
Passo 1
Primeiro, importamos as bibliotecas necessárias e criamos os tipos de consulta e mutação padrão. A consulta e a mutação definiram apenas a versão da API GraphQL por enquanto. Entretanto, estendamos a consulta e a mutação para incluir outros schemas conforme prosseguimos.
Passo 2:
Criamos um novo tipo de escalar por tempo e nosso primeiro resolvedor para a consulta e mutação criada acima. Além disso, também geramos um schema usando a função makeExecutableSchema
.
O schema gerado incluirá todos os outros schemas que você importou e ainda mais após criá-los e importá-los.
O snippet de código acima mostra que importamos diferentes schemas para a função makeExecutableSchema. Esta abordagem nos ajuda na estruturação do aplicativo por complexidade. Em seguida, criaremos os schemas Todo e Usuário que importamos.
Criando o schema Todo
O Schema Todo mostra operações simples de CRUD que os usuários do aplicativo podem realizar. Abaixo está o schema que implementa a operação de Todo CRUD.
const { gql } = require('apollo-server-express');
const createTodo = require('./mutations/create-todo');
const updateTodo = require('./mutations/update-todo');
const removeTodo = require('./mutations/delete-todo');
const todo = require('./queries/todo');
const todos = require('./queries/todos');
const typeDefs = gql`
type Todo {
id: ID!
title: String
description: String
user: User
}
input CreateTodoInput {
title: String!
description: String
isCompleted: Boolean
}
input UpdateTodoInput {
title: String
description: String
isCompleted: Boolean
} extend type Query {
todo(id: ID): Todo!
todos: [Todo!]
}
extend type Mutation {
createTodo(input: CreateTodoInput!): Todo
updateTodo(id: ID!, input: UpdateTodoInput!): Todo
removeTodo(id: ID!): Todo
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
// Resolvers for Queries
Query: {
todo,
todos,
},
// Resolvers for Mutations
Mutation: {
createTodo,
updateTodo,
removeTodo,
},
};
module.exports = { typeDefs, resolvers };
Análise do código
Vamos rever o snippet de código passo a passo:
Passo 1:
Primeiro, criamos um Schema Todo usando GraphQL type
, input
, e extend
. A palavra-chave extend
é usada para herdar e adicionar novas consultas e mutações à consulta raiz existente e à mutação que criamos acima.
Passo 2:
Em seguida, criamos um resolvedor, usado para recuperar os dados corretos quando uma determinada consulta ou mutação é chamada.
Com a função resolver implementada, podemos criar métodos individuais para a lógica de negócios e manipulação do banco de dados, como mostrado no exemplo do create-todo.js.
Crie um arquivo create-user.js na pasta ./mutations/
e adicione a lógica do negócio para criar um novo Todo em seu banco de dados.
const models = require('../../../models');
module.exports = async (root, { input }, context) => {
return models.todos.push({ ...input });
};
O snippet de código acima é uma forma simplificada de criar um novo Todo em nosso banco de dados usando o ORM Sequelize. Você pode aprender mais sobre o Sequelize e como configurá-lo com o Node.js.
Você pode seguir o mesmo passo para criar muitos schemas dependendo do seu aplicativo ou você pode clonar o projeto completo do GitHub.
Em seguida, configuraremos o servidor com o Express.js e executar o aplicativo Todo recém-criada com GraphQL e Node.js.
Configurando e executando o servidor
Finalmente, configuraremos nosso servidor usando a biblioteca apollo-server-express
que instalamos anteriormente.
O apollo-server-express
é um pacote simples do Apollo Server para Express.js, é recomendado porque foi desenvolvido para se encaixar no desenvolvimento do Express.js.
Usando os exemplos que discutimos acima, vamos configurar o servidor Express.js para trabalhar com o recém-instalado apollo-server-express
.
Crie um arquivo server.js no diretório raiz e cole no seguinte código:
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const schema = require('./modules');
const app = express();
async function startServer() {
const server = new ApolloServer({ schema });
await server.start();
server.applyMiddleware({ app });
}
startServer();
app.listen({ port: 3000 }, () =>
console.log(`Server ready at http://localhost:3000`)
);
O código acima criou com sucesso o primeiro servidor GraphQL CRUD para Todos e Usuários. Você pode iniciar o servidor de desenvolvimento e acessar o playground via http://localhost:3000/graphql. Se tudo der certo, você verá a seguinte tela:
Resumo
GraphQL é uma tecnologia moderna suportada pelo Facebook que simplifica o tedioso trabalho envolvido na criação de APIs de larga escala com padrões arquitetônicos RESTful.
Este guia se aprofundou no GraphQL e mostrou como criar sua primeira API GraphQL usando Express.js.
Deixe-nos saber o que você constrói com GraphQL nos comentários abaixo.
Deixe um comentário