Construindo APIs GraphQL com Node
Publicados: 2022-12-20GraphQL é a nova palavra da moda no desenvolvimento de APIs. Embora as APIs RESTful continuem sendo a maneira mais popular de expor dados de aplicativos, elas vêm com muitas limitações que o GraphQL pretende resolver.
GraphQL é uma linguagem de consulta criada pelo Facebook, que foi transformada em um projeto de código aberto em 2015. 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 criar um aplicativo Todo na estrutura da Web Express.js para Node.
O que é GraphQL?
Da documentação oficial: “GraphQL é uma linguagem de consulta para APIs e um tempo de execução para atender a essas consultas com seus dados existentes. O GraphQL fornece uma descrição completa e compreensível dos dados em sua API, dá aos clientes o poder de solicitar exatamente o que precisam e nada mais, facilita a evolução das APIs ao longo do tempo e permite poderosas ferramentas de desenvolvedor.”
GraphQL é um tempo de execução do lado do servidor para executar consultas usando o sistema de tipo que você definiu para seus dados. Além disso, o GraphQL não está vinculado a nenhum banco de dados ou mecanismo de armazenamento específico. Em vez disso, ele é respaldado por 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, comece definindo tipos de esquema e criando campos usando esses tipos. Em seguida, você fornece um resolvedor de função para ser executado em cada campo e digita sempre que os dados são solicitados pelo lado do cliente.
Terminologia do GraphQL
O sistema de tipo GraphQL é usado para descrever quais dados podem ser consultados e quais dados você pode manipular. É o núcleo do GraphQL. Vamos discutir diferentes maneiras de descrever e manipular dados no GraphQ.
tipos
Os tipos de objeto GraphQL são modelos de dados contendo campos fortemente tipados. Deve haver um mapeamento de 1 para 1 entre seus modelos e tipos de GraphQL. Abaixo está um exemplo de GraphQL Type:
type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }
Consultas
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 GraphQL forem solicitações GET , as mutações serão solicitações POST , PUT , PATCH e DELETE que manipulam a API 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 tipos -input para as mutações, como UserInput , TodoInput . É sempre uma prática recomendada sempre definir tipos de entrada para criar e atualizar seus recursos.
Você pode definir os tipos de entrada como o abaixo:
input UserInput { firstname: String! lastname: String email: String! username: String! }
resolvedores
Os resolvedores dizem ao GraphQL o que fazer quando cada consulta ou mutação é solicitada. É uma função básica que faz o trabalho duro de atingir a camada do banco de dados para fazer as operações CRUD (criar, ler, atualizar, excluir), atingir um terminal de API RESTful interno ou chamar um microsserviço para atender à 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 } }; }
Esquema
O esquema do GraphQL é o que o GraphQL expõe ao mundo. Portanto, os tipos, consultas e mutações serão incluídos dentro do esquema a ser exposto 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 o RootMutation que criamos anteriormente para serem expostos ao mundo.
Como o GraphQL funciona com Nodejs e Expressjs
O 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 a JavaScript e também há outras implementações do GraphQL para simplificar a escrita e a codificação no GraphQL.
O GraphQL Apollo fornece uma implementação para Node.js e Express.js e facilita a introdução ao GraphQL.
Você aprenderá como criar e desenvolver seu primeiro aplicativo GraphQL na estrutura de back-end Nodes.js e Express.js usando o GraphQL Apollo na próxima seção.
Configurando GraphQL com Express.js
Construir um servidor GraphQL API com Express.js é simples de começar. Nesta seção, exploraremos como construir um servidor GraphQL.
Inicializar projeto com Express
Primeiro, você precisa instalar e configurar um novo projeto Express.js.
Crie uma pasta para 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, vamos estruturar nosso projeto conforme a imagem abaixo. Ele conterá diferentes módulos para os recursos do projeto, como usuários, todos, etc.
Inicializar 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 Esquemas e Tipos
Em seguida, vamos criar um arquivo index.js dentro da pasta modules e adicionar o seguinte trecho 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;
Passo a passo do código
Vamos trabalhar com o trecho de código e dividi-lo:
Passo 1
Primeiro, importamos as bibliotecas necessárias e criamos tipos de consulta e mutação padrão. A consulta e a mutação definem apenas a versão da API GraphQL por enquanto. No entanto, estenderemos a consulta e a mutação para incluir outros esquemas à medida que prosseguirmos.
Passo 2:
Em seguida, criamos um novo tipo escalar para o tempo e nosso primeiro resolvedor para a consulta e mutação criada acima. Além disso, também geramos um esquema usando a função makeExecutableEchema .
O esquema gerado inclui todos os outros esquemas que importamos e também incluirá mais quando os criarmos e importarmos.
O trecho de código acima mostra que importamos esquemas diferentes para a função makeExecutableEchema. Essa abordagem nos ajuda a estruturar o aplicativo para a complexidade. Em seguida, vamos criar os esquemas Todo e Usuário que importamos.
Criando esquema de tarefas
O esquema Todo mostra operações CRUD simples que os usuários do aplicativo podem executar. Abaixo está o esquema que implementa a operação 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 };
Passo a passo do código
Vamos trabalhar com o trecho de código e dividi-lo:
Passo 1:
Primeiro, criamos um esquema para o 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, que é usado para recuperar os dados corretos quando uma determinada consulta ou mutação é chamada.
Com a função resolvedor instalada, podemos criar métodos individuais para a lógica de negócios e a manipulação do banco de dados, conforme mostrado no exemplo create-todo.js .
Crie um arquivo create-user.js na pasta <code>./mutations</code> e adicione a lógica de negócios 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 trecho de código acima é uma maneira simplificada de criar um novo Todo em nosso banco de dados usando o Sequelize ORM. Você pode aprender mais sobre Sequelize e como configurá-lo com Node.js.
Você pode seguir a mesma etapa para criar muitos esquemas dependendo do seu aplicativo ou pode clonar o projeto completo do GitHub.
Em seguida, vamos configurar o servidor com Express.js e executar o aplicativo Todo recém-criado com GraphQL e Node.js
Configurando e executando o servidor
Por fim, configuraremos nosso servidor usando a biblioteca apollo-server-express que instalamos anteriormente e a configuramos.
O apollo-server-express é um wrapper simples do Apollo Server para Express.js. É recomendado porque foi desenvolvido para caber no desenvolvimento do Express.js.
Usando os exemplos que discutimos acima, vamos configurar o servidor Express.js para funcionar com o recém-instalado apollo-server-express .
Crie um arquivo server.js no diretório raiz e cole o 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`) );
No código acima, você criou com sucesso seu primeiro servidor CRUD GraphQL para Todos e Usuários. Você pode iniciar seu servidor de desenvolvimento e acessar o playground usando http://localhost:3000/graphql. Se tudo der certo, você deverá ser apresentado à tela abaixo:
Resumo
GraphQL é uma tecnologia moderna suportada pelo Facebook que simplifica o tedioso trabalho envolvido na criação de APIs em larga escala com padrões de arquitetura RESTful.
Este guia elucidou o GraphQL e demonstrou como desenvolver sua primeira API GraphQL com Express.js.
Deixe-nos saber o que você constrói usando GraphQL.