Aguarde...

13 de julho de 2022

Como configurar um servidor de API GraphQL em Node.js

Como configurar um servidor de API GraphQL em Node.js

Introdução

Em Introdução ao GraphQL , você aprendeu que o GraphQL é uma linguagem de consulta de código aberto e tempo de execução para APIs criadas para resolver problemas que geralmente ocorrem com sistemas tradicionais de API REST.

Uma boa maneira de começar a entender como todas as partes do GraphQL se encaixam é criar um servidor de API do GraphQL. Embora o Apollo GraphQL seja uma implementação comercial popular do GraphQL, favorecida por muitas grandes empresas, não é um pré-requisito para criar seu próprio servidor GraphQL API.

Neste tutorial, você criará um servidor de API Express em Node.js que atende a um endpoint GraphQL. Você também criará um esquema GraphQL com base no sistema de tipos GraphQL, incluindo operações, como consultas e mutações, e funções de resolução para gerar respostas para quaisquer solicitações. Você também usará o ambiente de desenvolvimento integrado (IDE) do GraphiQL para explorar e depurar seu esquema e consultar a API do GraphQL de um cliente.

Pré-requisitos

Para seguir este tutorial, você precisará de:

  • Um ambiente Node.js local, que você pode configurar seguindo o tutorial Como instalar o Node.js e criar um ambiente de desenvolvimento local para seu sistema operacional e distribuição.
  • Uma compreensão dos conceitos fundamentais do GraphQL, que você pode encontrar no tutorial, Uma introdução ao GraphQL .
  • Familiaridade com HTTP .
  • Um conhecimento básico de HTML e JavaScript, que você pode obter da série, Como construir um site com HTML e Como codificar em JavaScript .

Configurando um servidor HTTP expresso

A primeira etapa é configurar um servidor Express, o que você pode fazer antes de escrever qualquer código GraphQL.

Em um novo projeto, você instalará expresscorscom o npm installcomando:

npm install express cors

Express será o framework para o seu servidor. É uma estrutura de aplicativo da Web para Node.js projetada para construir APIs. O pacote CORS , que é o middleware de Compartilhamento de Recursos C ross-O rigin , permitirá que você acesse facilmente este servidor a partir de um navegador.

Você também pode instalar o Nodemon como uma dependência de desenvolvimento:

npm install -D nodemon

Nodemon é uma ferramenta que ajuda a desenvolver aplicativos baseados em Node, reiniciando automaticamente o aplicativo quando são detectadas alterações de arquivo no diretório.

A instalação desses pacotes terá criado node_modulespackage.jsoncom duas dependências e uma dependência dev listada.

Usando nanoou seu editor de texto favorito, abra package.jsonpara edição, que ficará assim:pacote.json

{
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.3"
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  }
}

Há mais alguns campos que você adicionará neste momento. Para package.json, faça as seguintes alterações destacadas:pacote.json

{
  "main": "server.js",
  "scripts": {
    "dev": "nodemon server.js"
  },
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.3"
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  },
  "type": "module"
}

Você estará criando um arquivo para o servidor em server.js, então você mainaponta para server.js. Isso garantirá que npm starto servidor seja iniciado.

Para facilitar o desenvolvimento no servidor, você também cria um script chamado "dev"que executará o nodemon server.js.

Por fim, você adiciona um typepara modulegarantir que possa usar importinstruções em todo o código em vez de usar o CommonJS padrão require.

Salve e feche o arquivo quando terminar.

Em seguida, crie um arquivo chamado server.js. Nele, você criará um servidor Express simples, escutará na porta 4000e enviará uma solicitação dizendo Hello, GraphQL!. Para configurar isso, adicione as seguintes linhas ao seu novo arquivo:server.js

import express from 'express'
import cors from 'cors'

const app = express()
const port = 4000

app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.get('/', (request, response) => {
  response.send('Hello, GraphQL!')
})

app.listen(port, () => {
  console.log(`Running a server at http://localhost:${port}`)
})

Este bloco de código cria um servidor HTTP básico com Express. Ao invocar a expressfunção, você cria um aplicativo Express. Depois de definir algumas configurações essenciais para CORS e JSON, você definirá o que deve ser enviado com uma GETsolicitação para a raiz ( /) usando app.get('/'). Por fim, use app.listen()para definir a porta na qual o servidor de API deve estar escutando.

Salve e feche o arquivo quando terminar.

Agora você pode executar o comando para iniciar o servidor Node:

npm run dev

Se você visitar http://localhost:4000em um navegador ou executar um curl http://localhost:4000comando, verá o retorno Hello, GraphQL!, indicando que o servidor Express está em execução. Neste ponto, você pode começar a adicionar código para servir um endpoint GraphQL.

Configurando o middleware do servidor HTTP do GraphQL

Nesta seção, você começará a integrar o esquema GraphQL ao servidor Express básico. Você fará isso definindo um esquema, resolvedores e conectando-se a um armazenamento de dados.

Para começar a integrar o GraphQL ao servidor Express, você instalará três pacotes: graphqlexpress-graphql, e @graphql-tools/schema. Execute o seguinte comando:

npm install graphql@14 express-graphql @graphql-tools/schema
  • graphql: a implementação de referência JavaScript para GraphQL.
  • express-graphql: middleware de servidor HTTP para GraphQL.
  • @graphql-tools/schema: um conjunto de utilitários para desenvolvimento mais rápido do GraphQL.

Você pode importar esses pacotes no server.jsarquivo adicionando as linhas destacadas:server.js

import express from 'express'
import cors from 'cors'
import { graphqlHTTP } from 'express-graphql'
import { makeExecutableSchema } from '@graphql-tools/schema'

...

A próxima etapa é criar um esquema GraphQL executável.

Para evitar a sobrecarga de configurar um banco de dados, você pode usar um armazenamento na memória para os dados que o servidor GraphQL consultará. Você pode criar um dataobjeto com os valores que seu banco de dados teria. Adicione as linhas destacadas ao seu arquivo:server.js

import express from 'express'
import cors from 'cors'
import { graphqlHTTP } from 'express-graphql'
import { makeExecutableSchema } from '@graphql-tools/schema'

const data = {
  warriors: [
    { id: '001', name: 'Jaime' },
    { id: '002', name: 'Jorah' },
  ],
}

...

A estrutura de dados aqui representa uma tabela de banco de dados chamada warriorsque possui duas linhas, representadas pelas entradas Jaimee .Jorah

Observação: o uso de um armazenamento de dados real está fora do escopo deste tutorial. O acesso e manipulação de dados em um servidor GraphQL é realizado por meio dos redutores. Isso pode ser feito conectando-se manualmente ao banco de dados, por meio de um ORM como o Prisma . Os resolvedores assíncronos tornam isso possível por meio contextde um resolvedor. No restante deste tutorial, usaremos a datavariável para representar os valores do armazenamento de dados.

Com seus pacotes instalados e alguns dados no lugar, você agora criará um esquema, que define a API descrevendo os dados disponíveis para serem consultados.

Esquema GraphQL

Agora que você tem alguns dados básicos, pode começar a criar um esquema rudimentar para uma API para obter a quantidade mínima de código necessária para começar a usar um endpoint GraphQL. Esse esquema tem a intenção de replicar algo que possa ser usado para um jogo de RPG de fantasia, no qual existem personagens que possuem papéis como guerreiros, magos e curandeiros. Este exemplo deve ser aberto para que você possa adicionar o quanto quiser, como feitiços e armas.

Um esquema GraphQL depende de um sistema de tipos . Existem alguns tipos internos e você também pode criar seu próprio tipo. Para este exemplo, você criará um novo typechamado Warriore fornecerá dois campos: idname.

type Warrior {
  id: ID!
  name: String!
}

idtem um IDtipo e o nametem um Stringtipo. Ambos são escalares embutidos ou tipos primitivos. O ponto de exclamação ( !) significa que o campo não permite valor nulo e um valor será necessário para qualquer instância desse tipo.

A única informação adicional necessária para começar é um Querytipo base, que é o ponto de entrada para a consulta do GraphQL. Vamos definir warriorscomo uma matriz de Warriortipos.

type Query {
  warriors: [Warrior]
}

Com esses dois tipos, você tem um esquema válido que pode ser usado no middleware HTTP do GraphQL. Por fim, o esquema que você definir aqui será passado para a makeExecutableSchemafunção fornecida por graphql-toolsas typeDefs. As duas propriedades passadas para um objeto na makeExecutableSchemafunção serão as seguintes:

  • typeDefs: uma string de linguagem de esquema GraphQL.
  • resolvers: funções que são chamadas para executar um campo e produzir um valor.

Em server.js, após importar as dependências, crie uma typeDefsvariável e atribua o esquema do GraphQL como uma string, conforme mostrado aqui:server.js

...

const data = {
  warriors: [
    { id: '001', name: 'Jaime' },
    { id: '002', name: 'Jorah' },
  ],
}

const typeDefs = `
type Warrior {
  id: ID!
  name: String!
}

type Query {
  warriors: [Warrior]
}
`

...

Agora você tem seu conjunto de dados e seu esquema definidos, como datatypeDefs, respectivamente. Em seguida, você criará resolvedores para que a API saiba o que fazer com as solicitações recebidas.

Funções do Resolvedor GraphQL

Os resolvedores são uma coleção de funções que geram uma resposta para o servidor GraphQL. Cada função de resolver tem quatro parâmetros:

  • obj: O objeto pai, que não é necessário usar aqui, pois já é a raiz ou o objeto de nível superior.
  • args: quaisquer argumentos do GraphQL fornecidos ao campo.
  • context: Estado compartilhado entre todos os resolvedores, geralmente uma conexão de banco de dados.
  • info: Informações adicionais .

Nesse caso, você criará um resolvedor para o Querytipo raiz e retornará um valor para warriors.

Para começar com este servidor de exemplo, passe o armazenamento de dados na memória anterior nesta seção adicionando as linhas destacadas a server.js:server.js

...

const typeDefs = `
type Warrior {
  id: ID!
  name: String!
}

type Query {
  warriors: [Warrior]
}
`

const resolvers = {
  Query: {
    warriors: (obj, args, context, info) => context.warriors,
  },
}

...

O ponto de entrada no servidor GraphQL será por meio do Querytipo raiz nos resolvedores. Agora você adicionou uma função de resolução, chamada warriors, que retornará warriorsde contextcontexté onde seu ponto de entrada do banco de dados estará contido e, para essa implementação específica, será a datavariável que contém seu armazenamento de dados na memória.

Cada função de resolver individual tem quatro parâmetros: objargscontextinfo. O parâmetro mais útil e relevante para nosso esquema agora é context, que é um objeto compartilhado pelos resolvedores. É frequentemente usado como a conexão entre o servidor GraphQL e um banco de dados.

Finalmente, com o typeDefsresolverstudo configurado, você tem informações suficientes para criar um esquema executável. Adicione as linhas destacadas ao seu arquivo:server.js

...

const resolvers = {
  Query: {
    warriors: (obj, args, context, info) => context.warriors,
  },
}

const executableSchema = makeExecutableSchema({
  typeDefs,
  resolvers,
})

...

A função makeExecutableSchema cria um esquema completo que você pode passar para o endpoint do GraphQL.

Agora substitua o endpoint raiz padrão que está retornando no momento Hello, GraphQL!pelo seguinte /graphqlendpoint adicionando as linhas destacadas:server.js

...

const executableSchema = makeExecutableSchema({
  typeDefs,
  resolvers,
})

app.use(
  '/graphql',
  graphqlHTTP({
    schema: executableSchema,
    context: data,
    graphiql: true,
  })
)

...

A convenção é que um servidor GraphQL usará o /graphqlendpoint. Usar o graphqlHTTPmiddleware requer passar o esquema e um contexto, que neste caso, é seu armazenamento de dados simulado.

Agora você tem tudo o que é necessário para começar a servir o endpoint. Seu server.jscódigo deve ficar assim:server.js

import express from 'express'
import cors from 'cors'
import { graphqlHTTP } from 'express-graphql'
import { makeExecutableSchema } from '@graphql-tools/schema'

const app = express()
const port = 4000

// In-memory data store
const data = {
  warriors: [
    { id: '001', name: 'Jaime' },
    { id: '002', name: 'Jorah' },
  ],
}

// Schema
const typeDefs = `
type Warrior {
  id: ID!
  name: String!
}

type Query {
  warriors: [Warrior]
}
`

// Resolver for warriors
const resolvers = {
  Query: {
    warriors: (obj, args, context) => context.warriors,
  },
}

const executableSchema = makeExecutableSchema({
  typeDefs,
  resolvers,
})

app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

// Entrypoint
app.use(
  '/graphql',
  graphqlHTTP({
    schema: executableSchema,
    context: data,
    graphiql: true,
  })
)

app.listen(port, () => {
  console.log(`Running a server at http://localhost:${port}`)
})

Salve e feche o arquivo quando terminar.

Agora você deve poder acessar http://localhost:4000/graphqle explorar seu esquema usando o GraphiQL IDE .

Sua API GraphQL agora está completa com base no esquema e nos resolvedores que você criou nesta seção. Na próxima seção, você usará o GraphiQL IDE para ajudá-lo a depurar e entender seu esquema.

Usando o GraphiQL IDE

Como você aplicou a graphiqlopção quanto trueao middleware do GraphQL, você tem acesso ao ambiente de desenvolvimento integrado (IDE) do GraphiQL. Se você visitou o endpoint do GraphQL em uma janela do navegador, você se encontrará no GraphiQL.

GraphiQL é uma ferramenta no navegador para escrever, validar e testar consultas GraphQL. Agora você pode testar seu servidor GraphQL para garantir que ele esteja retornando os dados corretos.

Faça uma consulta para warriors, solicitando as propriedades idname. No seu navegador, adicione as seguintes linhas ao painel esquerdo do GraphiQL:

{
  warriors {
    id
    name
  }
}

Envie a consulta pressionando a seta Reproduzir no canto superior esquerdo e você verá o valor de retorno em JSON no lado direito:

{
  "data": {
    "warriors": [
      { "id": "001", "name": "Jaime" },
      { "id": "002", "name": "Jorah" }
    ]
  }
}

Se você remover um dos campos da consulta, verá o valor de retorno mudar de acordo. Por exemplo, se você deseja apenas recuperar o namecampo, pode escrever a consulta assim:

{
  warriors {
    name
  }
}

E agora sua resposta ficará assim:

{
  "data": {
    "warriors": [{ "name": "Jaime" }, { "name": "Jorah" }]
  }
}

A capacidade de consultar apenas os campos necessários é um dos aspectos poderosos do GraphQL e é o que o torna uma linguagem orientada para o cliente .

De volta ao GraphiQL, se você clicar em Documentos totalmente à direita, ele expandirá uma barra lateral chamada Documentation Explorer . Nessa barra lateral, você pode clicar na documentação para visualizar seu esquema com mais detalhes.

Agora sua API está completa e você explorou como usá-la no GraphiQL. A próxima etapa será fazer solicitações reais de um cliente para sua API GraphQL.

Consultando a API GraphQL de um cliente

Assim como nas APIs REST , um cliente pode se comunicar com uma API GraphQL fazendo solicitações HTTP pela rede. Como você pode usar APIs integradas do navegador, como fetchfazer solicitações de rede, também pode usar fetchpara consultar o GraphQL.

Para um exemplo bem básico, crie um esqueleto HTML em um index.htmlarquivo com uma <pre>tag:index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>GraphQL Client</title>
  </head>

  <pre><!-- data will be displayed here --></pre>

  <body>
    <script>
      // Add query here
    </script>
  </body>
</html>

Na scripttag, crie uma função assíncrona que envie uma POSTsolicitação à API GraphQL:index.html

...
<body>
    <script>
      async function queryGraphQLServer() {
        const response = await fetch('http://localhost:4000/graphql', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            query: '{ warriors { name } }',
          }),
        })
        const data = await response.json()

        // Append data to the pre tag
        const pre = document.querySelector('pre')
        pre.textContent = JSON.stringify(data, null, 2) // Pretty-print the JSON
      }

      queryGraphQLServer()
    </script>
  </body>
...

Content-Typecabeçalho deve ser definido como application/jsone a consulta deve ser passada no corpo como uma string. O script chamará a função para fazer a solicitação e definirá a resposta na pretag.

Aqui está o index.htmlcódigo completo.index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>GraphQL</title>
  </head>

  <pre></pre>

  <body>
    <script>
      async function queryGraphQLServer() {
        const response = await fetch('http://localhost:4000/graphql', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            query: '{ warriors { name } }',
          }),
        })
        const data = await response.json()

        const pre = document.querySelector('pre')
        pre.textContent = JSON.stringify(data, null, 2) // Pretty-print the JSON
      }

      queryGraphQLServer()
    </script>
  </body>
</html>

Salve e feche o arquivo quando terminar.

Agora, ao visualizar o index.htmlarquivo em um navegador, você verá uma solicitação de rede de saída para o http://localhost:4000/graphqlendpoint, que retornará um 200com os dados. Você pode visualizar essa solicitação de rede abrindo as Ferramentas do desenvolvedor e navegando até a guia Rede .

Se sua solicitação foi atendida e você obteve uma 200resposta com os dados da API GraphQL, parabéns! Você criou seu primeiro servidor de API GraphQL.

Postado em Blog
Escreva um comentário