15%

Poupe 15% em todos os serviços

Teste as suas habilidades e obtenha Desconto em qualquer plano

Utilizar o código:

Skills
Começar a trabalhar
01.11.2024
1 +1

O Guia Completo do GraphQL: Construa APIs Mais Rápidas e Inteligentes em Hospedagem de Alto Desempenho

GraphQL mudou fundamentalmente a forma como os desenvolvedores projetam e consomem APIs. Nascido dentro das equipas de engenharia do Facebook em 2012 e lançado para a comunidade de código aberto em 2015, GraphQL cresceu para se tornar uma das linguagens de consulta de API mais amplamente adotadas no desenvolvimento web moderno. Quer esteja a construir uma aplicação de chat em tempo real, um painel de controlo pesado em dados, ou um produto mobile-first com restrições rigorosas de largura de banda, GraphQL oferece-lhe controlo cirúrgico sobre exatamente que dados viajam pela rede.

Neste guia abrangente, aprenderá o que é GraphQL, por que supera as APIs REST tradicionais em muitos cenários, como configurar o seu primeiro servidor GraphQL, e como implementá-lo em infraestrutura que pode lidar com as exigências de cargas de trabalho em produção.

Índice

  1. O que é GraphQL?
  2. GraphQL vs. REST: Por que Importa
  3. Características Principais do GraphQL
  4. Configurar um Servidor GraphQL
  5. Definir o Seu Schema
  6. Implementar Resolvers
  7. Consultar e Mutar Dados
  8. Atualizações em Tempo Real com Subscrições
  9. Introspecção GraphQL e Ferramentas de Desenvolvimento
  10. Implementar GraphQL em Produção
  11. Melhores Práticas de Segurança
  12. Conclusão

1. O que é GraphQL? {#what-is-graphql}

GraphQL é uma linguagem de consulta de código aberto para APIs e um runtime para executar essas consultas contra os seus dados. Ao contrário do REST, que expõe um conjunto fixo de endpoints cada um retornando uma estrutura de dados predeterminada, GraphQL expõe um único endpoint através do qual os clientes podem solicitar precisamente os campos e relacionamentos de que necessitam — nada mais, nada menos.

Esta abordagem elimina dois dos problemas mais persistentes no design de API REST:

  • Over-fetching — receber muito mais dados do que o cliente realmente necessita, desperdiçando largura de banda e tempo de processamento.
  • Under-fetching — receber dados insuficientes numa única solicitação, forçando o cliente a fazer múltiplas chamadas de acompanhamento para montar uma imagem completa.

Com GraphQL, o cliente conduz a forma da resposta. O servidor cumpre o contrato definido pelo schema, e o cliente solicita apenas o que pretende utilizar.

2. GraphQL vs. REST: Por que Importa {#graphql-vs-rest}

Compreender quando escolher GraphQL em vez de REST — e vice-versa — é crítico para tomar decisões arquitetónicas sólidas.

DimensãoRESTGraphQL
EndpointsMúltiplos (um por recurso)Único endpoint unificado
Obtenção de dadosEstrutura de resposta fixaCampos especificados pelo cliente
Over-fetchingComumEliminado por design
Under-fetchingComum (problema N+1)Resolvido com consultas aninhadas
VersionamentoVersionamento de URL ou header necessárioEvolução de schema sem versionamento
Suporte em tempo realRequer WebSockets ou pollingSubscrições nativas
Sistema de tiposOpcional (OpenAPI/Swagger)Schema obrigatório integrado
CacheCache ao nível HTTP diretoRequer cache ciente de consultas

GraphQL é particularmente poderoso para:

  • Modelos de dados complexos e interconectados onde uma única visualização requer dados de múltiplos recursos.
  • Aplicações mobile onde minimizar o tamanho da carga útil melhora diretamente a experiência do utilizador e reduz custos de dados.
  • Iteração rápida de produtos onde as equipas de frontend precisam de evoluir os seus requisitos de dados sem esperar por alterações de API de backend.
  • Agregação de microserviços onde um gateway GraphQL une múltiplos serviços downstream numa superfície de API unificada.

REST permanece uma escolha sólida para APIs CRUD simples, APIs públicas consumidas por terceiros que beneficiam da semântica HTTP previsível, e cenários onde o cache ao nível HTTP é um requisito obrigatório.

3. Características Principais do GraphQL {#key-features}

3.1 Obtenção Precisa de Dados

A característica definidora do GraphQL é que os clientes declaram os seus requisitos de dados na própria consulta. Uma única solicitação para um único endpoint pode recuperar um gráfico profundamente aninhado de objetos relacionados, com apenas os campos que o cliente especificou preenchidos na resposta.

Isto é transformador para equipas que constroem produtos em múltiplas plataformas — web, iOS, Android, smart TV — onde cada superfície tem diferentes necessidades de dados. Em vez de manter endpoints REST separados ou aceitar cargas úteis inchadas, cada cliente envia uma consulta personalizada e recebe uma resposta personalizada.

3.2 Schema Fortemente Tipado

Cada API GraphQL é apoiada por um schema escrito na Linguagem de Definição de Schema GraphQL (SDL). O schema é o contrato autoritário entre o servidor e cada cliente que o consome. Define:

  • Tipos — a forma de cada objeto no seu modelo de dados.
  • Consultas — operações de leitura que os clientes podem realizar.
  • Mutações — operações de escrita (criar, atualizar, eliminar).
  • Subscrições — fluxos de eventos em tempo real.
  • Relacionamentos — como os tipos se referenciam mutuamente.

Como o schema é fortemente tipado, categorias inteiras de bugs são capturadas em tempo de desenvolvimento em vez de em produção. As ferramentas podem validar consultas contra o schema antes de serem executadas, e os IDEs podem fornecer autocomplete preciso e documentação inline.

3.3 Atualizações em Tempo Real com Subscrições

O mecanismo de subscrição do GraphQL permite conexões persistentes e orientadas por eventos entre cliente e servidor — tipicamente implementadas sobre WebSockets. Quando um evento subscrito ocorre no servidor (uma nova mensagem é publicada, um preço de ação muda, um estado de encomenda é atualizado), o servidor envia os dados relevantes para todos os clientes subscritos imediatamente.

Isto torna GraphQL uma escolha natural para:

  • Aplicações de chat ao vivo e mensagens
  • Ferramentas de edição colaborativa
  • Painéis de controlo financeiros com dados de mercado ao vivo
  • Notificações em tempo real e feeds de atividade
  • Sincronização de estado de jogos multijogador

3.4 Introspecção

As APIs GraphQL são auto-documentadas por design. O sistema de introspecção permite aos clientes consultar o próprio schema — descobrindo tipos disponíveis, campos, consultas, mutações, e as suas descrições em tempo de execução. Esta capacidade alimenta ferramentas de desenvolvimento como GraphiQL e Apollo Studio, que fornecem exploradores de API interativos, construtores de consultas, e geração automática de documentação sem qualquer esforço adicional do autor da API.

3.5 Evolução de Schema Sem Versionamento

Um dos aspetos mais praticamente valiosos do GraphQL é como lida graciosamente com mudanças. Como os clientes solicitam apenas os campos de que necessitam, pode adicionar novos campos e tipos ao schema sem quebrar clientes existentes. Deprecar campos antigos é tratado através de anotações de schema em vez de versionamento de URL, mantendo a sua superfície de API limpa e os seus clientes estáveis.

4. Configurar um Servidor GraphQL {#setting-up}

GraphQL é agnóstico de linguagem. Bibliotecas de servidor maduras existem em toda a stack de tecnologia. Aqui estão as opções mais amplamente utilizadas:

Linguagem / RuntimeBiblioteca / Framework
Node.jsApollo Server, GraphQL Yoga, Express-GraphQL
PythonStrawberry, Graphene
JavaSpring for GraphQL, graphql-java
Gogqlgen, graphql-go
Rubygraphql-ruby
PHPLighthouse (Laravel), webonyx/graphql-php
Rustasync-graphql
.NET / C#Hot Chocolate, GraphQL.NET

Passo a Passo: Node.js com Apollo Server

Apollo Server é o servidor GraphQL mais amplamente implementado no ecossistema Node.js. O seguinte walkthrough leva-o de zero para um servidor em execução.

Pré-requisitos:

  • Node.js 18 ou posterior instalado
  • gestor de pacotes npm ou yarn

Passo 1: Inicializar o seu projeto

mkdir graphql-api && cd graphql-api
npm init -y
npm install @apollo/server graphql

Passo 2: Criar o seu ficheiro de servidor

Crie um ficheiro denominado index.js (ou index.mjs para módulos ES):

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

// Step 1: Define your type definitions (schema)
const typeDefs = `#graphql
  type Book {
    id: ID!
    title: String!
    author: String!
    publishedYear: Int
    genre: String
  }

  type Query {
    books: [Book!]!
    book(id: ID!): Book
  }
`;

// Step 2: Define your data source (in-memory for this example)
const books = [
  {
    id: '1',
    title: 'The Pragmatic Programmer',
    author: 'David Thomas & Andrew Hunt',
    publishedYear: 1999,
    genre: 'Technology',
  },
  {
    id: '2',
    title: 'Clean Code',
    author: 'Robert C. Martin',
    publishedYear: 2008,
    genre: 'Technology',
  },
];

// Step 3: Define your resolvers
const resolvers = {
  Query: {
    books: () => books,
    book: (_, { id }) => books.find((b) => b.id === id),
  },
};

// Step 4: Create and start the server
const server = new ApolloServer({ typeDefs, resolvers });

const { url } = await startStandaloneServer(server, {
  listen: { port: 4000 },
});

console.log(`🚀 GraphQL server ready at: ${url}`);

Passo 3: Iniciar o servidor

node index.js
# Output: 🚀 GraphQL server ready at: http://localhost:4000/

Navegue para http://localhost:4000/ no seu navegador para abrir o Apollo Sandbox — um explorador de consultas interativo onde pode testar a sua API imediatamente.

5. Definir o Seu Schema {#defining-schema}

O schema é a espinha dorsal de cada API GraphQL. Investir tempo num schema bem projetado compensa ao longo de toda a vida útil da sua aplicação.

Tipos Escalares

GraphQL inclui cinco tipos escalares integrados:

    Int — inteiro assinado de 32 bits
    Float — ponto flutuante de dupla precisão
    String — sequência de caracteres UTF-8
    Boolean — true ou false
  • ID — identificador único, serializado como uma string
  • Também pode definir escalares personalizados para tipos como Date, DateTime, Email, URL, ou JSON.

    Tipos de Objeto

    type Author {
      id: ID!
      name: String!
      biography: String
      books: [Book!]!
    }
    
    type Book {
      id: ID!
      title: String!
      author: Author!
      publishedYear: Int
      genre: String
      tags: [String!]
    }

    O modificador ! denota um campo não anulável. [Book!]! significa uma lista não anulável de objetos Book não anuláveis.

    Consultas

    type Query {
      books: [Book!]!
      book(id: ID!): Book
      authors: [Author!]!
      author(id: ID!): Author
      booksByGenre(genre: String!): [Book!]!
    }

    Mutações

    type Mutation {
      createBook(title: String!, authorId: ID!, genre: String): Book!
      updateBook(id: ID!, title: String, genre: String): Book
      deleteBook(id: ID!): Boolean!
    }

    Tipos de Entrada

    Para mutações com múltiplos argumentos, tipos de entrada mantêm o seu schema limpo e reutilizável:

    input CreateBookInput {
      title: String!
      authorId: ID!
      publishedYear: Int
      genre: String
      tags: [String!]
    }
    
    type Mutation {
      createBook(input: CreateBookInput!): Book!
    }

    6. Implementar Resolvers {#implementing-resolvers}

    Resolvers são as funções que cumprem cada campo no seu schema. Cada campo num schema GraphQL pode ter um resolver. Se nenhum resolver for definido para um campo, GraphQL recua para um resolver padrão que simplesmente retorna a propriedade do mesmo nome do objeto pai.

    Assinatura do Resolver

    fieldName: (parent, args, context, info) => value
    • parent — o valor resolvido do tipo pai (útil para resolvers aninhados).
    • args — os argumentos passados para o campo na consulta.
    • context — um objeto compartilhado passado através de toda a cadeia de resolver, tipicamente contendo o utilizador autenticado, conexão de base de dados, ou data loaders.
    • info — metadados sobre a execução da consulta, incluindo o nome do campo e o schema.

    Exemplo: Resolvers com uma Base de Dados

    const resolvers = {
      Query: {
        books: async (_, __, { db }) => {
          return db.collection('books').find().toArray();
        },
        book: async (_, { id }, { db }) => {
          return db.collection('books').findOne({ _id: id });
        },
      },
    
      Mutation: {
        createBook: async (_, { input }, { db, user }) => {
          if (!user) throw new Error('Authentication required');
          const result = await db.collection('books').insertOne(input);
          return { id: result.insertedId, ...input };
        },
      },
    
      Book: {
        // Nested resolver: fetch the author for each book
        author: async (book, _, { db }) => {
          return db.collection('authors').findOne({ _id: book.authorId });
        },
      },
    };

    Evitar o Problema N+1 com DataLoader

    Resolvers aninhados podem desencadear o problema de consulta N+1 — obter uma lista de 100 livros e depois fazer 100 chamadas de base de dados separadas para resolver o autor de cada livro. A solução é DataLoader, um utilitário de batching e caching:

    import DataLoader from 'dataloader';
    
    // In your context factory:
    const authorLoader = new DataLoader(async (authorIds) => {
      const authors = await db.collection('authors')
        .find({ _id: { $in: authorIds } })
        .toArray();
      return authorIds.map((id) => authors.find((a) => a._id === id));
    });
    
    // In your resolver:
    Book: {
      author: (book, _, { authorLoader }) => authorLoader.load(book.authorId),
    }

    DataLoader agrupa todas as pesquisas author dentro de um único tick do event loop numa única consulta de base de dados, reduzindo 100 consultas para 1.

    7. Consultar e Mutar Dados {#querying-data}

    Consulta Básica

    query GetAllBooks {
      books {
        id
        title
        author {
          name
        }
        genre
      }
    }

    Consulta com Argumentos

    query GetBook {
      book(id: "1") {
        title
        author {
          name
          biography
        }
        publishedYear
        tags
      }
    }

    Consulta com Variáveis

    Variáveis mantêm as suas consultas dinâmicas e previnem vulnerabilidades de injeção:

    query GetBook($bookId: ID!) {
      book(id: $bookId) {
        title
        author {
          name
        }
      }
    }
    {
      "bookId": "1"
    }

    Exemplo de Mutação

    mutation AddBook($input: CreateBookInput!) {
      createBook(input: $input) {
        id
        title
        author {
          name
        }
      }
    }
    {
      "input": {
        "title": "Designing Data-Intensive Applications",
        "authorId": "42",
        "publishedYear": 2017,
        "genre": "Technology"
      }
    }

    Fragmentos

    Fragmentos permitem-lhe reutilizar seleções de campos em múltiplas consultas:

    fragment BookDetails on Book {
      id
      title
      genre
      publishedYear
    }
    
    query {
      books {
        ...BookDetails
        author {
          name
        }
      }
    }

    8. Atualizações em Tempo Real com Subscrições {#subscriptions}

    As subscrições GraphQL mantêm uma conexão persistente — tipicamente sobre WebSockets — e enviam dados para clientes quando eventos específicos ocorrem no servidor.

    Definição de Schema

    type Subscription {
      bookAdded: Book!
      bookUpdated(id: ID!): Book!
    }

    Implementação de Servidor (Apollo Server com WebSockets)

    npm install graphql-ws ws @graphql-tools/schema
    import { createServer } from 'http';
    import { WebSocketServer } from 'ws';
    import { useServer } from 'graphql-ws/lib/use/ws';
    import { makeExecutableSchema } from '@graphql-tools/schema';
    import { PubSub } from 'graphql-subscriptions';
    
    const pubsub = new PubSub();
    
    const resolvers = {
      Mutation: {
        createBook: async (_, { input }, { db }) => {
          const book = await db.collection('books').insertOne(input);
          pubsub.publish('BOOK_ADDED', { bookAdded: book });
          return book;
        },
      },
      Subscription: {
        bookAdded: {
          subscribe: () => pubsub.asyncIterator(['BOOK_ADDED']),
        },
      },
    };
    
    const schema = makeExecutableSchema({ typeDefs, resolvers });
    const httpServer = createServer();
    const wsServer = new WebSocketServer({ server: httpServer, path: '/graphql' });
    useServer({ schema }, wsServer);

    Subscrição de Cliente

    subscription OnBookAdded {
      bookAdded {
        id
        title
        author {
          name
        }
      }
    }

    9. Introspecção GraphQL e Ferramentas de Desenvolvimento {#introspection}

    O sistema de introspecção do GraphQL é uma das suas características mais amigáveis para desenvolvedores. Ao consultar os meta-campos __schema e __type, clientes e ferramentas podem descobrir a estrutura completa da sua API em tempo de execução.

    Exemplo de Consulta de Introspecção

    {
      __schema {
        types {
          name
          kind
          description
        }
      }
    }

    Ferramentas Essenciais de Desenvolvimento

    FerramentaPropósito
    GraphiQLIDE no navegador para escrever e testar consultas
    Apollo StudioGestão completa de API, monitorização de desempenho, registo de schema
    PostmanSuporte de consulta GraphQL com gestão de coleções
    InsomniaCliente de API leve com suporte GraphQL
    GraphQL Code GeneratorGera automaticamente tipos TypeScript a partir do seu schema
    Apollo Client DevToolsExtensão do navegador para depuração de cache Apollo Client

    > Nota de Segurança: Desative a introspecção em ambientes de produção para evitar expor o seu schema de API a potenciais atacantes. Apollo Server torna isto direto:

    >

    > “`javascript

    > new ApolloServer({ typeDefs, resolvers, introspection: false });

    > “`

    10. Implementar GraphQL em Produção {#deploying}

    Mover uma API GraphQL de desenvolvimento para produção requer atenção cuidadosa à infraestrutura, desempenho e confiabilidade.

    Escolher a Infraestrutura de Alojamento Correta

    A infraestrutura em que executa a sua API GraphQL impacta diretamente o seu desempenho, confiabilidade e escalabilidade. Para cargas de trabalho em produção, tem várias opções fortes:

    Alojamento VPS é um excelente ponto de partida para a maioria das APIs GraphQL. Um plano de Alojamento VPS oferece-lhe recursos dedicados, acesso root, e a liberdade de configurar o seu runtime Node.js, proxy reverso, e gestor de processos exatamente como necessita. Os planos VPS AlexHost são construídos para cargas de trabalho sensíveis ao desempenho e incluem armazenamento SSD e conectividade de alta largura de banda.

    Servidores Dedicados são a escolha correta quando a sua API GraphQL lida com volumes elevados de consultas, cargas de trabalho complexas de subscrição, ou funciona como um gateway agregando múltiplos microserviços. Com um Servidor Dedicado, obtém acesso exclusivo a todos os recursos de CPU, RAM e I/O — sem vizinhos barulhentos, sem contenção de recursos, e a potência bruta para lidar com milhares de conexões WebSocket simultâneas para subscrições.

    Alojamento GPU vale a pena considerar se a sua API GraphQL funciona como a camada de interface para inferência de aprendizado de máquina, pipelines de processamento de dados em tempo real, ou características alimentadas por IA. Alojamento GPU da AlexHost coloca recursos GPU NVIDIA à sua disposição, permitindo à sua API entregar resultados computacionalmente intensivos com latência baixa.

    Stack de Implementação em Produção

    Uma implementação robusta em produção para uma API GraphQL tipicamente parece assim:

    Client → CDN / Load Balancer → Nginx (Reverse Proxy) → Node.js (PM2) → Database
                                                          ↘ Redis (Caching / PubSub)

    Passo 1: Instalar e configurar Nginx como proxy reverso

    server {
        listen 80;
        server_name api.yourdomain.com;
    
        location /graphql {
            proxy_pass http://localhost:4000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_cache_bypass $http_upgrade;
        }
    }

    Os headers Upgrade e Connection são críticos para suporte WebSocket, que alimenta subscrições GraphQL.

    Passo 2: Gerir o seu processo Node.js com PM2

    npm install -g pm2
    pm2 start index.js --name graphql-api --instances max
    pm2 save
    pm2 startup

    --instances max ativa o modo cluster, gerando um processo worker por núcleo de CPU para maximizar o throughput.

    Passo 3: Proteger com SSL

    Cada API em produção deve ser servida sobre HTTPS. Um Certificado SSL da AlexHost garante que todos os dados em trânsito entre clientes e o seu endpoint GraphQL são encriptados. Isto é especialmente importante para APIs que lidam com tokens de autenticação, dados pessoais, ou informações financeiras.

    # Install Certbot and obtain a certificate
    sudo apt install certbot python3-certbot-nginx
    sudo certbot --nginx -d api.yourdomain.com

    Passo 4: Registar o seu domínio

    A sua API precisa de um domínio memorável e profissional. Registo de Domínio através da AlexHost oferece-lhe acesso a todos os TLDs principais com gestão de DNS direta, tornando fácil apontar o seu domínio para o seu servidor e configurar subdomínios para ambientes de staging e produção.

    Estratégias de Cache

    O modelo de endpoint único do GraphQL significa que o cache ao nível HTTP (que depende de diferenciação de URL) não funciona fora da caixa. Use estas estratégias em vez disso:

    • Consultas Persistidas — os clientes enviam um hash da consulta em vez da string de consulta completa, permitindo cache de CDN por hash.
    • Cache de Resposta — cache de resultados de resolver em Redis baseado em hash de consulta e variáveis.
    • DataLoader — batch e cache de chamadas de base de dados dentro de uma única execução de solicitação.
    • Apollo Cache — cache normalizado do lado do cliente que elimina solicitações de rede redundantes.

    11. Melhores Práticas de Segurança {#security}

    A flexibilidade do GraphQL é uma faca de dois gumes. Sem salvaguardas apropriadas, uma única consulta maliciosa pode esgotar os recursos do seu servidor.

    Limitação de Profundidade de Consulta

    Previna consultas profundamente aninhadas de causarem pesquisas recursivas de base de dados:

    import depthLimit from 'graphql-depth-limit';
    
    new ApolloServer({
      typeDefs,
      resolvers,
      validationRules: [depthLimit(7)],
    });

    Análise de Complexidade de Consulta

    Atribua um custo a cada campo e rejeite consultas que excedem um orçamento de complexidade:

    import { createComplexityLimitRule } from 'graphql-validation-complexity';
    
    new ApolloServer({
      validationRules: [createComplexityLimitRule(1000)],
    });

    Limitação de Taxa

    Aplique limitação de taxa ao nível Nginx ou dentro da sua aplicação usando uma biblioteca como express-rate-limit para prevenir abuso.

    Autenticação e Autorização

    Use a função context para anexar o utilizador autenticado a cada solicitação:

    const server = new ApolloServer({
      typeDefs,
      resolvers,
      context: async ({ req }) => {
        const token = req.headers.authorization?.split('Bearer ')[1];
        const user = token ? await verifyToken(token) : null;
        return { user, db, authorLoader };
      },
    });

    Depois aplique autorização dentro de resolvers:

    createBook: (_, { input }, { user }) => {
      if (!user || !user.roles.includes('EDITOR')) {
        throw new ForbiddenError('You do not have permission to create books.');
      }
      // proceed with creation
    },

    Desativar Introspecção em Produção

    new ApolloServer({
      introspection: process.env.NODE_ENV !== 'production',
    });

    Validação de Entrada

    Nunca confie em entrada fornecida pelo cliente. Valide todos os argumentos de mutação usando uma biblioteca como joi ou zod antes de passar dados para a sua camada de base de dados.

    12. Conclusão {#conclusion}

    GraphQL representa um salto significativo na filosofia de design de API. Ao colocar o cliente no controlo da obtenção de dados, aplicar um schema fortemente tipado como o contrato entre sistemas, e fornecer suporte nativo para subscrições em tempo real, GraphQL permite que as equipas de desenvolvimento construam mais rápido, lancem com mais confiança, e iterar sem o atrito do versionamento de API.

    Os conceitos-chave a levar adiante deste guia:

    • Design schema-first produz APIs mais mantíveis e auto-documentadas.
    • Resolvers
    15%

    Poupe 15% em todos os serviços

    Teste as suas habilidades e obtenha Desconto em qualquer plano

    Utilizar o código:

    Skills
    Começar a trabalhar