

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# GraphQL e arquitetura AWS AppSync
<a name="graphql-overview"></a>

**nota**  
Este guia pressupõe que o usuário tenha um conhecimento prático do estilo de arquitetura REST. Recomendamos revisar este e outros tópicos de front-end antes de trabalhar com o GraphQL e AWS AppSync.

GraphQL é uma linguagem de consulta e manipulação para. APIs O GraphQL fornece uma sintaxe flexível e intuitiva para descrever os requisitos e interações de dados. Ele permite que os desenvolvedores solicitem exatamente o que é necessário e obtenham resultados previsíveis. Ele também possibilita acessar várias fontes em uma única solicitação, reduzindo o número de chamadas de rede e os requisitos de largura de banda, economizando a vida útil da bateria e os ciclos de CPU consumidos pelos aplicativos. 

Fazer atualizações nos dados é simples com as mutações, permitindo que os desenvolvedores descrevam como os dados devem mudar. O GraphQL também facilita a configuração rápida de soluções em tempo real por meio de assinaturas. Todos esses atributos combinados, juntamente com poderosas ferramentas para desenvolvedores, tornam o GraphQL essencial para gerenciar dados de aplicativos.

O GraphQL é uma alternativa ao REST. RESTful a arquitetura é atualmente uma das soluções mais populares para comunicação cliente-servidor. Ele se concentra no conceito de seus recursos (dados) serem expostos por um URL. Eles URLs podem ser usados para acessar e manipular os dados por meio de operações CRUD (criar, ler, atualizar, excluir) na forma de métodos HTTP como `GET``POST`, e. `DELETE` A vantagem do REST é que ele é relativamente simples de aprender e implementar. Você pode se configurar rapidamente RESTful APIs para ligar para uma ampla variedade de serviços. 

No entanto, a tecnologia está ficando mais complicada. À medida que aplicativos, ferramentas e serviços começam a se expandir para um público mundial, a necessidade de arquiteturas rápidas e escaláveis é de suma importância. O REST tem muitas obstáculos ao lidar com operações escaláveis. Veja este [caso de uso](https://aws.amazon.com/blogs/architecture/what-to-consider-when-modernizing-apis-with-graphql-on-aws/) de exemplo.

Nas seções a seguir, analisaremos alguns dos conceitos relacionados RESTful APIs. Em seguida, apresentaremos o GraphQL e como ele funciona.

Para obter mais informações sobre o GraphQL e os benefícios de migrar para AWS, consulte o Guia de [decisão para implementações do GraphQL](https://aws.amazon.com/graphql/guide/).

**Topics**
+ [O que é uma API](what-is-an-api.md)
+ [O que é REST](what-is-rest.md)
+ [O que é GraphQL](what-is-graphql.md)
+ [Comparação entre REST e GraphQL](comparing-rest-graphql.md)
+ [Por que usar GraphQL em vez de REST](why-use-graphql.md)
+ [Componentes de uma API GraphQL](api-components.md)
+ [Propriedades adicionais do GraphQL](graphql-properties.md)

# O que é uma API?
<a name="what-is-an-api"></a>

Uma interface de programação de aplicações (API) define as regras que você deve seguir para se comunicar com outros sistemas de software. Os desenvolvedores expõem ou criam APIs para que outros aplicativos possam se comunicar com seus aplicativos de forma programática. Por exemplo, o aplicativo de planilha de horas expõe uma API que solicita o nome completo de um funcionário e um intervalo de datas. Quando recebe essas informações, ele processa internamente a planilha de horas do funcionário e retorna o número de horas trabalhadas nesse intervalo de datas.

Você pode pensar em uma API web como um gateway entre clientes e recursos na web.

## Clientes
<a name="what-is-a-client"></a>

Clientes são usuários que desejam acessar informações da web. O cliente pode ser uma pessoa ou um sistema de software que usa a API. Por exemplo, os desenvolvedores podem escrever programas que acessam dados meteorológicos de um sistema meteorológico. Ou você pode acessar os mesmos dados no seu navegador ao visitar diretamente o site meteorológico.

## Recursos
<a name="what-is-a-resource"></a>

Recursos são as informações que diferentes aplicativos fornecem a seus clientes. Os recursos podem ser imagens, vídeos, texto, números ou qualquer tipo de dado. A máquina que fornece o recurso ao cliente também é chamada de servidor. As organizações usam APIs para compartilhar recursos e fornecer serviços web, mantendo a segurança, o controle e a autenticação. Além disso, APIs ajude-os a determinar quais clientes têm acesso a recursos internos específicos.

# O que é REST?
<a name="what-is-rest"></a>

Em um alto nível, a transferência de estado representacional (REST) é uma arquitetura de software que impõe condições sobre como uma API deve funcionar. O REST foi criado inicialmente como uma diretriz para gerenciar a comunicação em uma rede complexa como a Internet. Você pode usar a arquitetura baseada em REST para oferecer suporte à comunicação confiável e de alto desempenho em grande escala. Você pode facilmente implementá-la e modificá-la, trazendo visibilidade e portabilidade multiplataforma para qualquer sistema de API.

Os desenvolvedores de API podem projetar APIs usando várias arquiteturas diferentes. APIs que seguem o estilo arquitetônico REST são chamados de REST APIs. Os serviços da Web que implementam a arquitetura REST são chamados de serviços RESTful da Web. O termo RESTful API geralmente se refere à RESTful web APIs. No entanto, você pode usar os termos API REST e RESTful API de forma intercambiável.

Veja a seguir alguns dos princípios do estilo de arquitetura REST:

## Interface uniforme
<a name="uniform-interface"></a>

A interface uniforme é fundamental para o design de qualquer RESTful serviço web. Isso indica que o servidor transfere informações em um formato padrão. O recurso formatado é chamado de representação em REST. Esse formato pode ser diferente da representação interna do recurso no aplicativo do servidor. Por exemplo, o servidor pode armazenar dados como texto, mas os envia em um formato de representação HTML.

A interface uniforme impõe quatro restrições de arquitetura:

1.  As solicitações devem identificar os recursos. Elas fazem isso usando um identificador de recurso uniforme. 

1.  Os clientes têm informações suficientes na representação do recurso para modificar ou excluir o atributo, se quiserem. O servidor atende a essa condição enviando metadados que descrevem melhor o atributo. 

1.  Os clientes recebem informações sobre como processar ainda mais a representação. O servidor consegue isso enviando mensagens autodescritivas que contêm metadados sobre como o cliente pode melhor usá-las. 

1.  Os clientes recebem informações sobre todos os outros recursos relacionados de que precisam para concluir uma tarefa. O servidor consegue isso enviando hiperlinks na representação para que os clientes possam descobrir dinamicamente mais recursos. 

## Ausência de estado
<a name="statelessness"></a>

Na arquitetura REST, a ausência de estado refere-se a um método de comunicação no qual o servidor conclui todas as solicitações do cliente, independentemente de todas as solicitações anteriores. Os clientes podem solicitar recursos em qualquer ordem, e cada solicitação é sem estado ou isolada de outras solicitações. Essa restrição de design da API REST implica que o servidor possa sempre entender e atender completamente à solicitação. 

## Sistema em camadas
<a name="layered-system"></a>

Em uma arquitetura de sistema em camadas, o cliente pode se conectar a outros intermediários autorizados entre o cliente e o servidor e ainda receberá respostas do servidor. Os servidores também podem transmitir solicitações para outros servidores. Você pode projetar seu serviço RESTful web para ser executado em vários servidores com várias camadas, como segurança, aplicação e lógica de negócios, trabalhando em conjunto para atender às solicitações dos clientes. Essas camadas permanecem invisíveis para o cliente.

## Capacidade de armazenamento em cache
<a name="cacheability"></a>

RESTful os serviços web suportam cache, que é o processo de armazenar algumas respostas no cliente ou em um intermediário para melhorar o tempo de resposta do servidor. Por exemplo, suponha que você acesse um site que tenha imagens de cabeçalho e rodapé comuns em todas as páginas. Toda vez que você acessa uma nova página do site, o servidor precisa reenviar as mesmas imagens. Para evitar isso, o cliente armazena ou armazena essas imagens após a primeira resposta e, em seguida, usa as imagens diretamente do cache. RESTful os serviços da web controlam o armazenamento em cache usando respostas de API que se definem como armazenáveis em cache ou não.

## O que é uma RESTful API?
<a name="what-is-a-restful-api"></a>

RESTful A API é uma interface que dois sistemas de computador usam para trocar informações com segurança pela Internet. A maioria dos aplicativos empresariais precisa se comunicar com outros aplicativos internos e de terceiros para realizar várias tarefas. Por exemplo, para gerar recibos mensais, seu sistema interno de contas precisa compartilhar dados com o sistema bancário do cliente para automatizar o faturamento e se comunicar com um aplicativo interno de quadro de horários. RESTful APIs apoiam essa troca de informações porque seguem padrões de comunicação de software seguros, confiáveis e eficientes.

## Como RESTful APIs funciona?
<a name="how-do-restful-apis-work"></a>

A função básica de uma RESTful API é a mesma de navegar na Internet. O cliente entra em contato com o servidor usando a API quando precisa de um recurso. Os desenvolvedores de API explicam como o cliente deve usar a API REST na documentação da API do aplicativo de servidor. Estas são as etapas gerais para qualquer chamada da API REST:

1.  O cliente envia a seguinte solicitação ao servidor. O cliente segue a documentação da API para formatar a solicitação de uma forma que o servidor entenda. 

1.  O servidor autentica o cliente e confirma que o cliente tem o direito de fazer essa solicitação. 

1.  O servidor recebe a solicitação e a processa internamente. 

1.  O servidor retorna uma resposta para o cliente. A resposta contém informações que informam ao cliente se a solicitação foi bem-sucedida. A resposta também inclui todas as informações solicitadas pelo cliente. 

Os detalhes da solicitação e da resposta da API REST variam um pouco, dependendo de como os desenvolvedores da API projetam a API.

# O que é GraphQL?
<a name="what-is-graphql"></a>

O GraphQL é tanto uma linguagem de consulta APIs quanto um tempo de execução para executar essas consultas. O GraphQL permite que os clientes solicitem exatamente os dados de que precisam, fornecendo uma alternativa mais flexível e eficiente ao REST em muitos cenários. Ao contrário do REST, que depende de endpoints predefinidos, o GraphQL usa um único endpoint em que os clientes podem especificar seus requisitos de dados na forma de consultas e mutações. 

Consulte [Componentes de uma API do GraphQL](https://docs.aws.amazon.com/appsync/latest/devguide/api-components.html) para obter mais informações sobre como o GraphQL é estruturado. APIs 

# Comparação entre REST e GraphQL
<a name="comparing-rest-graphql"></a>

APIs (Interfaces de programação de aplicativos) desempenham um papel crucial na facilitação da troca de dados entre aplicativos. Conforme mencionado anteriormente, APIs surgiram duas abordagens proeminentes para design: GraphQL e REST. Embora ambas atendam ao propósito fundamental de permitir a comunicação cliente-servidor, elas diferem significativamente em seus casos de implementação e uso.

As abordagens GraphQL e REST compartilham várias características importantes: 

1. **Modelo cliente-servidor**: ambas usam uma arquitetura cliente-servidor para troca de dados. 

1. **Ausência de estado**: nenhuma das duas mantém as informações da sessão do cliente entre as solicitações. 

1. **Baseada em HTTP**: ambas normalmente usam HTTP como o protocolo de comunicação subjacente. 

1. **Design orientado a recursos**: ambas projetam seu intercâmbio de dados em torno de recursos, que se referem a quaisquer dados ou objetos que o cliente possa acessar e manipular por meio da API. 

1. **Flexibilidade de formato de dados**: JSON é o formato de troca de dados mais usado em ambas, embora outros formatos, como XML e HTML, também sejam compatíveis. 

1. **Independente de linguagem e banco de dados**: ambas podem funcionar com qualquer linguagem de programação ou estrutura de banco de dados, tornando-as altamente interoperáveis. 

1. **Suporte ao armazenamento em cache**: ambas oferecem suporte ao armazenamento em cache, permitindo que clientes e servidores armazenem dados acessados com frequência para melhorar o desempenho. 

Embora compartilhem alguns princípios fundamentais, GraphQL e REST diferem significativamente na abordagem para design de API e busca de dados:

1. **Estrutura da solicitação e busca de dados**

   REST usa diferentes métodos HTTP (GET, POST, PUT, DELETE) para executar operações em recursos. Isso geralmente requer vários endpoints para diferentes recursos, o que pode levar a ineficiências na recuperação de dados. Por exemplo, executar uma operação GET para recuperar dados de um usuário pode resultar em busca excessiva ou insuficiente dos dados. Para obter os dados corretos, é possível chamar operações de truncamento ou várias operações. 

   GraphQL usa um único endpoint para todas as operações. Ele se baseia em consultas para buscar dados e em mutações para modificá-los. Os clientes podem usar consultas para buscar exatamente os dados de que precisam em uma única solicitação, o que reduz a sobrecarga da rede ao minimizar a transferência de dados. 

1. **Esquema do lado do servidor**

   REST não exige um esquema do lado do servidor, embora seja possível definir um opcionalmente para projeto e documentação eficientes da API.

   GraphQL usa um esquema do lado do servidor fortemente tipado para definir dados e serviços de dados. O esquema, escrito na linguagem de definição de esquema (SDL) do GraphQL, inclui tipos de objetos e campos para cada objeto e funções de resolvedor do lado do servidor que definem operações para cada campo.

1. **Versionamento**

   REST geralmente inclui versionamento no URL, o que pode levar à manutenção de várias versões da API simultaneamente. O versionamento não é obrigatório, mas pode ajudar a evitar alterações significativas. 

   GraphQL promove uma evolução contínua da API sem versionamento explícito, exigindo compatibilidade com versões anteriores. Os campos excluídos retornam mensagens de erro, enquanto as tags de depreciação eliminam gradualmente os campos antigos e retornam mensagens de aviso. 

1. **Tratamento de erros** 

   REST tem uma tipagem fraca, exigindo que o tratamento de erros seja incorporado ao código ao redor. Isso pode não identificar automaticamente erros relacionados ao tipo (por exemplo, analisar um número como texto). 

   Por outro lado, GraphQL é fortemente tipado e requer uma definição de esquema abrangente. Isso permite que seu serviço identifique automaticamente muitos erros de solicitação com um alto nível de detalhes.

1. **Casos de uso**

   REST é mais adequado para: 
   + Aplicações menores com requisitos de dados menos complexos. 
   + Cenários em que dados e operações são usados de forma semelhante por todos os clientes. 
   + Aplicações sem necessidades de consultas complexas de dados. 

   GraphQL é mais adequado para: 
   + Cenários com largura de banda limitada, em que é fundamental minimizar solicitações e respostas. 
   + Aplicações com várias fontes de dados que precisam ser combinados em um único endpoint. 
   + Casos em que as solicitações dos clientes variam significativamente e esperam estruturas de resposta diferentes.

   Observe que é possível usar o GraphQL e o REST APIs em um único aplicativo para diferentes áreas de funcionalidade. Além disso, você pode atualizar uma RESTful API para incluir recursos do GraphQL sem uma reescrita completa. Consulte [Como criar resolvedores GraphQL para fontes de AWS dados para](https://aws.amazon.com/graphql/resolvers/) ver um exemplo.

# Por que usar o GraphQL em vez do REST?
<a name="why-use-graphql"></a>

REST é um dos estilos arquitetônicos fundamentais da web. APIs No entanto, à medida que o mundo se torna mais interconectado, a necessidade de desenvolver aplicativos robustos e escaláveis se tornará uma questão mais urgente. Embora o REST seja frequentemente usado para criar a web APIs, existem várias desvantagens recorrentes nas RESTful implementações que foram identificadas:

1. **Solicitações de dados**: usando RESTful APIs, você normalmente solicitaria os dados de que precisa por meio de endpoints. O problema surge quando há dados que podem não estar tão bem empacotados. Os dados de que você precisa podem estar por trás de várias camadas de abstração, e a única maneira de buscar os dados é usando vários endpoints, o que significa fazer várias solicitações para extrair todos os dados.

1. **Busca excessiva e busca insuficiente**: piorando ainda mais a questão de várias solicitações, os dados de cada endpoint são estritamente definidos, o que significa que você retornará qualquer dado que seja definido para essa API, mesmo que tecnicamente não tenha interesse nele.

   Isso pode resultar em *busca excessiva*, o que significa que nossas solicitações retornam dados supérfluos. Por exemplo, digamos que você esteja solicitando dados pessoais da empresa e queira saber os nomes dos funcionários de um certo departamento. O endpoint que retorna os dados contém os nomes, mas também pode conter outros dados, como cargo ou data de nascimento. Como a API é fixa, você não pode simplesmente solicitar os nomes individualmente; o resto dos dados vem com eles.

   A situação oposta, na qual não retornamos dados suficientes, é chamada de *busca insuficiente*. Para obter todos os dados solicitados, talvez seja necessário fazer várias solicitações ao serviço. Dependendo de como os dados foram estruturados, você pode se deparar com consultas ineficientes, resultando em problemas como o temido problema n\$11.

1. **Iterações de desenvolvimento lentas**: muitos desenvolvedores as adaptam RESTful APIs para se adequarem ao fluxo de seus aplicativos. No entanto, conforme seus aplicativos crescem, tanto o front-end quanto o back-end podem exigir grandes mudanças. Como resultado, eles APIs podem não se ajustar mais ao formato dos dados de uma forma eficiente ou impactante. Isso resulta em iterações de produto mais lentas devido à necessidade de modificações na API.

1. **Desempenho em grande escala**: devido a esse acúmulo de problemas, há muitas áreas em que a escalabilidade será afetada. O desempenho no lado do aplicativo pode ser afetado porque suas solicitações retornarão dados de mais ou de menos (resultando em mais solicitações). Ambas as situações causam sobrecarga desnecessária na rede, resultando em baixo desempenho. Do lado do desenvolvedor, a velocidade de desenvolvimento pode ser reduzida porque você APIs é fixo e não se ajusta mais aos dados que eles estão solicitando.

O ponto de venda do GraphQL é superar as desvantagens do REST. Aqui estão algumas das principais soluções que o GraphQL oferece aos desenvolvedores:

1. **Endpoints únicos**: o GraphQL usa um único endpoint para consultar dados. Não há necessidade de criar vários APIs para se adequar ao formato dos dados. Isso resulta em menos solicitações passando pela rede.

1. **Busca**: o GraphQL resolve os problemas inerentes da busca excessiva e insuficiente simplesmente definindo os dados de que você precisa. O GraphQL permite que você modele os dados de acordo com suas necessidades, para que você receba apenas o que solicitou.

1. **Abstração**: O APIs GraphQL contém alguns componentes e sistemas que descrevem os dados usando um padrão independente de linguagem. Em outras palavras, a forma e a estrutura dos dados são padronizadas para que tanto o front-end quanto o back-end saibam como eles serão enviados pela rede. Isso permite que os desenvolvedores de ambos os lados trabalhem com os sistemas do GraphQL e não em torno deles.

1. **Iterações rápidas**: devido à padronização dos dados, as mudanças em uma extremidade do desenvolvimento podem não ser necessárias na outra. Por exemplo, alterações na apresentação do front-end podem não resultar em alterações extensivas no back-end porque o GraphQL permite que a especificação dos dados seja modificada prontamente. Você pode simplesmente definir ou modificar a forma dos dados para atender às necessidades do aplicativo à medida que ele cresce. Isso resulta em menos trabalho potencial de desenvolvimento.

Esses são apenas alguns dos benefícios do GraphQL. Nas próximas seções, você aprenderá como o GraphQL é estruturado e as propriedades que o tornam uma alternativa exclusiva ao REST.

# Componentes de uma API GraphQL
<a name="api-components"></a>

Uma API GraphQL padrão é composta por um único esquema que manipula a forma dos dados que serão consultados. Seu esquema está vinculado a uma ou mais de suas fontes de dados, como um banco de dados ou uma função do Lambda. Entre os dois, há um ou mais resolvedores que lidam com a lógica de negócios de suas solicitações. Cada componente desempenha um papel importante na implementação do GraphQL. As seções a seguir apresentarão esses três componentes e o papel que eles desempenham no serviço GraphQL.

![\[GraphQL API components: schema, resolvers, and data sources interconnected with AppSync.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/appsync-architecture-graphql-api.png)


**Topics**
+ [Esquemas do GraphQL](schema-components.md)
+ [Fontes de dados](data-source-components.md)
+ [Resolvedores](resolver-components.md)

# Esquemas do GraphQL
<a name="schema-components"></a>

O esquema do GraphQL é a base de uma API GraphQL. Ele serve como o esquema que define a forma dos dados. Também é um contrato entre seu cliente e servidor que define como seus dados serão recuperados e and/or modificados.

Os esquemas do GraphQL são escritos em *Schema Definition Language* (SDL). O SDL é composto por tipos e campos com uma estrutura estabelecida:
+ **Tipos**: os tipos são como o GraphQL define a forma e o comportamento dos dados. O GraphQL é compatível com uma infinidade de tipos que serão explicados ainda nesta seção. Cada um dos tipos definidos em seu esquema terá um escopo próprio. Dentro do escopo, um ou mais campos vão apresentar um valor ou lógica que será usada em seu serviço do GraphQL. Os tipos têm muitas funções diferentes, sendo as mais comuns objetos ou escalares (tipos de valores primitivos).
+ **Campos**: os campos existem dentro do escopo de um tipo e contêm o valor solicitado do serviço do GraphQL. Eles são muito semelhantes às variáveis de outras linguagens de programação. A forma dos dados que você define em seus campos determinará como os dados são estruturados em uma request/response operação. Isso permite que os desenvolvedores prevejam o que será retornado sem saber como o back-end do serviço é implementado.

Para visualizar a aparência de um esquema, vamos revisar o conteúdo de um esquema simples do GraphQL. No código de produção, seu esquema normalmente ficará em um arquivo chamado `schema.graphql` ou `schema.json`. Vamos supor que estamos examinando um projeto que implementa um serviço GraphQL. Este projeto está armazenando dados de funcionários da empresa, e o arquivo `schema.graphql` está sendo usado para recuperar dados de funcionários e adicionar novos funcionários a um banco de dados. O código pode ser semelhante a:

------
#### [ schema.graphql ]

```
type Person {                                  
   id: ID!
   name: String                                  
   age: Int
}
type Query {                                   
  people: [Person]
}
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

------

Podemos ver que há três tipos definidos no esquema: `Person``Query` e `Mutation`. Observando `Person`, podemos supor que esse é o esquema de uma instância de um funcionário da empresa, o que faria desse tipo um objeto. Dentro de seu escopo, vemos `id`, `name` e `age`. Esses são os campos que definem as propriedades de uma `Person`. Isso significa que nossa fonte de dados armazena cada `name` de `Person` como um tipo `String` escalar (primitivo) e `age` como um tipo `Int` escalar (primitivo). O `id` atua como um identificador especial e exclusivo para cada `Person`. Ele também é um valor obrigatório, conforme indicado pelo símbolo `!`.

Os próximos dois tipos de objetos se comportam de forma diferente. O GraphQL reserva algumas palavras-chave para tipos de objetos especiais que definem como os dados serão preenchidos no esquema. Um tipo `Query` recupera dados da fonte. Em nosso exemplo, nossa consulta pode recuperar objetos `Person` de um banco de dados. Isso pode lembrá-lo das `GET` operações na RESTful terminologia. Uma `Mutation` modifica os dados. Em nosso exemplo, nossa mutação pode adicionar mais objetos `Person` ao banco de dados. Isso pode soar familiar devido às operações de alteração de estado, como `PUT` ou `POST`. Os comportamentos de todos os tipos de objetos especiais serão explicados posteriormente nesta seção.

Vamos supor que `Query` em nosso exemplo recupere algo do banco de dados. Se olharmos para os campos de `Query`, veremos um campo chamado `people`. Seu valor de campo é `[Person]`. Isso significa que queremos recuperar alguma instância de `Person` no banco de dados. No entanto, a adição de colchetes significa que queremos retornar uma lista de todas as instâncias de `Person` e não apenas uma específica.

O tipo `Mutation` é responsável por realizar operações de mudança de estado, como modificação de dados. Uma mutação é responsável por realizar alguma operação de alteração de estado na fonte de dados. Em nosso exemplo, nossa mutação contém uma operação chamada `addPerson` que adiciona um novo objeto `Person` ao banco de dados. A mutação usa a `Person` e espera uma entrada para os campos `id`, `name` e `age`.

Neste ponto, você pode estar se perguntando como funcionam operações como `addPerson` sem uma implementação de código, já que ela supostamente executa algum comportamento e se parece muito com uma função, com um nome e parâmetros de função. Neste momento, isso não funcionaria porque um esquema serve apenas como declaração. Para implementar o comportamento de `addPerson`, teríamos que adicionar um resolvedor a ele. Um resolvedor é uma unidade de código que é executada sempre que seu campo associado (nesse caso, a operação `addPerson`) é chamado. Se você quiser usar uma operação, precisará adicionar a implementação do resolvedor em algum momento. De certa forma, você pode pensar na operação do esquema como a declaração da função e no resolvedor como a definição. Os resolvedores serão explicados em uma seção diferente.

Este exemplo mostra apenas as formas mais simples de um esquema manipular dados. Você cria aplicativos complexos, robustos e escaláveis aproveitando os atributos do GraphQL e AWS AppSync. Na próxima seção, definiremos todos os diferentes tipos e comportamentos de campo que você pode utilizar em seu esquema.

# Tipos no GraphQL
<a name="graphql-types"></a>

O GraphQL é compatível com muitos tipos diferentes. Como você viu na seção anterior, os tipos definem a forma ou o comportamento dos seus dados. Eles são os blocos de construção fundamentais de um esquema do GraphQL. 

Os tipos podem ser categorizados em entradas e saídas. As entradas são tipos que podem ser transmitidos como argumento para os tipos de objetos especiais (`Query`, `Mutation`, etc.), enquanto os tipos de saída são usados estritamente para armazenar e retornar dados. Uma lista de tipos e suas categorizações estão listadas abaixo:
+ **Objetos**: um objeto contém campos que descrevem uma entidade. Por exemplo, um objeto pode ser algo como um `book` com campos descrevendo suas características, como `authorName`, `publishingYear`, etc. Eles são estritamente tipos de saída.
+ **Escalares**: esses são tipos primitivos como int, string, etc. Normalmente, eles são atribuídos a campos. Usando o campo `authorName` como exemplo, ele pode ser atribuído ao escalar `String` para armazenar um nome como “John Smith”. Escalares podem ser do tipo de entrada e saída.
+ **Entradas**: as entradas permitem que você transmita um grupo de campos como argumento. Elas são estruturadas de forma muito semelhante aos objetos, mas podem ser passadas como argumentos para objetos especiais. As entradas permitem que você defina escalares, enums e outras entradas em seu escopo. As entradas só podem ser tipos de entrada.
+ **Objetos especiais**: objetos especiais realizam operações de mudança de estado e fazem a maior parte do trabalho pesado do serviço. Há três tipos de objetos especiais: consulta, mutação e assinatura. As consultas normalmente buscam dados; as mutações manipulam dados; as assinaturas abrem e mantêm uma conexão bidirecional entre clientes e servidores para comunicação constante. Objetos especiais não são de entrada nem saída, dada sua funcionalidade.
+ **Enums**: enums são listas predefinidas de valores legais. Se você chamar um enum, seus valores só poderão ser definidos em seu escopo. Por exemplo, se você tivesse uma enumeração chamada `trafficLights` representando uma lista de sinais de trânsito, ela poderia ter valores como `redLight` e `greenLight`, mas não `purpleLight`. Um semáforo real terá um limite de sinais, então você pode usar o enum para defini-los e forçá-los a serem os únicos valores legais ao fazer referência a `trafficLight`. Escalares podem ser do tipo de entrada e saída.
+ **Uniões/interfaces**: as uniões permitem que você retorne uma ou mais coisas em uma solicitação, dependendo dos dados solicitados pelo cliente. Por exemplo, se você tivesse um tipo `Book` com um `title` campo e um tipo `Author` com um campo `name`, você poderia criar uma união entre os dois tipos. Se seu cliente quisesse consultar um banco de dados para a frase “Júlio César”, a união poderia retornar *Júlio César* (a peça de William Shakespeare) do `title` `Book` e *Júlio César* (o autor de *Commentarii de Bello Gallico*) do `name` `Author`. As uniões só podem ser tipos de saída.

  As interfaces são conjuntos de campos que os objetos devem implementar. Isso é um pouco semelhante às interfaces em linguagens de programação como Java, nas quais você precisa implementar os campos definidos na interface. Por exemplo, digamos que você tenha criado uma interface chamada `Book` que continha um campo `title`. Digamos que você tenha criado posteriormente um tipo chamado `Novel` que implementou `Book`. Seu `Novel` teria que incluir um campo `title`. No entanto, seu `Novel` também pode incluir outros campos que não estão na interface, como `pageCount` ou `ISBN`. As interfaces só podem ser tipos de saída.

As seções a seguir explicarão como cada tipo funciona no GraphQL.

## Objetos
<a name="object-components"></a>

Os objetos do GraphQL são o tipo principal que você verá no código de produção. No GraphQL, você pode pensar em um objeto como um agrupamento de campos diferentes (semelhantes às variáveis em outras linguagens), e cada campo é definido por um tipo (normalmente um escalar ou outro objeto) que pode conter um valor. Os objetos representam uma unidade de dados que pode ser retrieved/manipulated da implementação do seu serviço.

Os tipos de objetos são declarados usando a palavra-chave `Type`. Vamos modificar um pouco nosso exemplo de esquema:

```
type Person {
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

Os tipos de objeto aqui são `Person` e `Occupation`. Cada objeto tem seus próprios campos com seus próprios tipos. Um atributo do GraphQL é a capacidade de definir campos como outros tipos. Você pode ver que o campo `occupation` em `Person` contém um tipo de objeto `Occupation`. Podemos fazer essa associação porque o GraphQL está apenas descrevendo os dados e não a implementação do serviço.

## Escalares
<a name="scalar-components"></a>

Os escalares são tipos essencialmente primitivos que contêm valores. Em AWS AppSync, há dois tipos de escalares: os escalares e AWS AppSync escalares padrão do GraphQL. Os escalares costumam ser usados para armazenar valores de campo em tipos de objetos. Os tipos padrão do GraphQL incluem `Int`, `Float`, `String`,`Boolean` e `ID`. Vamos usar o exemplo anterior novamente:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

Destacando os campos `name` e `title` e, ambos possuem um escalar `String`, e `Name` poderia retornar um valor de string como "`John Smith`" e o título poderia retornar algo como "`firefighter`”. Algumas implementações do GraphQL também oferecem suporte a escalares personalizados usando a palavra-chave`Scalar` e implementando o comportamento do tipo. No entanto, atualmente o AWS AppSync **não oferece suporte** a escalares personalizados. Para obter uma lista de escalares, consulte [Tipos de escalares](https://docs.aws.amazon.com//appsync/latest/devguide/scalars.html) no AWS AppSync.

## Entradas
<a name="input-components"></a>

Devido ao conceito de tipos de entrada e saída, existem certas restrições ao transmitir argumentos. Os tipos que normalmente precisam ser transmitidos, principalmente objetos, são restritos. Você pode usar o tipo de entrada para ignorar essa regra. As entradas são tipos que contêm escalares, enums e outros tipos de entrada.

As entradas são definidas usando a palavra-chave `input`:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input personInput { 
  id: ID!
  name: String
  age: Int
  occupation: occupationInput
}

input occupationInput {
  title: String
}
```

Como você pode ver, podemos ter entradas separadas que imitam o tipo original. Essas entradas geralmente serão usadas em suas operações de campo da seguinte forma:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Observe como ainda estamos transmitindo `occupationInput` em vez de `Occupation` para criar uma `Person`. 

Este é apenas um dos cenários para entradas. Elas não precisam copiar objetos 1:1 e, no código de produção, você provavelmente não as usará dessa forma. É uma prática recomendada aproveitar os esquemas do GraphQL definindo somente o que você precisa inserir como argumentos.

Além disso, as mesmas entradas podem ser usadas em várias operações, mas não recomendamos fazer isso. Preferencialmente, cada operação deve conter sua própria cópia exclusiva das entradas, caso os requisitos do esquema mudem.

## Objetos especiais
<a name="special-object-components"></a>

O GraphQL reserva algumas palavras-chave para objetos especiais que definem parte da lógica de negócios de como seu esquema processará os dados. retrieve/manipulate No máximo, pode haver uma de cada uma dessas palavras-chave em um esquema. Eles atuam como pontos de entrada para todos os dados solicitados que seus clientes executam no seu serviço GraphQL. 

Objetos especiais também são definidos usando a palavra-chave `type`. Embora sejam usados de forma diferente dos tipos de objetos comuns, sua implementação é muito semelhante.

------
#### [ Queries ]

As consultas são muito semelhantes às operações `GET`, pois realizam uma busca somente para leitura para obter dados da sua fonte. No GraphQL, a `Query` define todos os pontos de entrada para clientes que fazem solicitações em seu servidor. Sempre haverá um `Query` em sua implementação do GraphQL.

Aqui estão os tipos `Query` de objetos modificados que usamos em nosso exemplo de esquema anterior:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
type Occupation {
  title: String
}
type Query {                                   
  people: [Person]
}
```

Nosso `Query` contém um campo chamado `people` que retorna uma lista de instâncias `Person` da fonte de dados. Digamos que precisemos mudar o comportamento do nosso aplicativo e agora precisamos retornar uma lista somente das instâncias de `Occupation` para algum propósito separado. Poderíamos simplesmente adicioná-lo à consulta:

```
type Query {                                   
  people: [Person]
  occupations: [Occupation]
}
```

No GraphQL, podemos tratar nossa consulta como a única fonte de solicitações. Como você pode ver, isso é potencialmente muito mais simples do que RESTful implementações que podem usar endpoints diferentes para alcançar a mesma coisa (`.../api/1/people`e). `.../api/1/occupations`

Supondo que tenhamos uma implementação de resolvedor para essa consulta, agora podemos realizar uma consulta real. Embora o tipo `Query` exista, precisamos chamá-lo explicitamente para que ele seja executado no código do aplicativo. Isso pode ser feito usando a palavra-chave `query`:

```
query getItems {
   people {
      name
   }
   occupations {
      title
   }
}
```

Como você pode ver, essa consulta é chamada `getItems` e retorna `people` (uma lista de objetos `Person`) e `occupations` (uma lista de objetos `Occupation`). Em `people`, estamos retornando somente o campo `name` de cada `Person`, enquanto retornamos o campo `title` de cada `Occupation`. A resposta pode ser semelhante a:

```
{
  "data": {
    "people": [
      {
        "name": "John Smith"
      },
      {
        "name": "Andrew Miller"
      },
      .
      .
      .
    ],
    "occupations": [
      {
        "title": "Firefighter"
      },
      {
        "title": "Bookkeeper"
      },
      .
      .
      .
    ]
  }
}
```

O exemplo de resposta mostra como os dados seguem a forma da consulta. Cada entrada recuperada é listada dentro do escopo do campo. `people` e `occupations` estão retornando itens como listas separadas. Embora isso seja útil, talvez seja mais conveniente modificar a consulta para retornar uma lista dos nomes e ocupações das pessoas:

```
query getItems {
   people {
      name   
      occupation {
        title
      }
}
```

Essa é uma modificação legal porque nosso tipo `Person` contém um campo `occupation` de tipo `Occupation`. Quando listados no escopo de `people`, retornamos cada um `name` de `Person` junto com os `Occupation` associados por `title`. A resposta pode ser semelhante a:

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "occupation": {
          "title": "Firefighter"
        }
      },
      {
        "name": "Andrew Miller",
        "occupation": {
          "title": "Bookkeeper"
        }
      },
      .
      .
      .
    ]
  }
}
```

------
#### [ Mutations ]

As mutações são semelhantes às operações de alteração de estado, como ou `PUT` `POST`. Eles realizam uma operação de gravação para modificar os dados na fonte e, em seguida, buscam a resposta. Eles definem seus pontos de entrada para solicitações de modificação de dados. Diferentemente das consultas, uma mutação pode ou não ser incluída no esquema, dependendo das necessidades do projeto. Veja a mutação do exemplo do esquema:

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

O campo `addPerson` representa um ponto de entrada que adiciona uma `Person` à fonte de dados. `addPerson` é o nome do campo; `id`,`name` e `age` são os parâmetros; e `Person` é o tipo de retorno. Relembrando o tipo `Person`:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
```

Adicionamos o campo `occupation`. No entanto, não podemos definir esse campo como `Occupation` diretamente porque os objetos não podem ser passados como argumentos; eles são estritamente tipos de saída. Em vez disso, devemos passar uma entrada com os mesmos campos de um argumento:

```
input occupationInput {
  title: String
}
```

 Também podemos atualizar facilmente nosso `addPerson` para incluir isso como um parâmetro ao criar novas instâncias de `Person`:

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Veja o esquema atualizado:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Observe que `occupation` passará o campo `title` de `occupationInput` para concluir a criação do objeto `Person` em vez do `Occupation` original. Supondo que tenhamos uma implementação de resolvedor para `addPerson`, agora podemos realizar uma mutação real. Embora o tipo `Mutation` exista, precisamos chamá-lo explicitamente para que ele seja executado no código do aplicativo. Isso pode ser feito usando a palavra-chave `mutation`:

```
mutation createPerson {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput) {
    name
    age
    occupation {
      title
    }
  }
}
```

Essa mutação é chamada de `createPerson`, e `addPerson` é a operação. Para criar uma nova `Person`, podemos inserir os argumentos para `id`, `name`, `age` e `occupation`. No escopo de `addPerson`, também podemos ver outros campos como `name`, `age`, etc. Esta é sua resposta; esses são os campos que serão retornados após a conclusão da operação `addPerson`. Aqui está a parte final do exemplo:

```
mutation createPerson {
  addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner") {
    id
    name
    age
    occupation {
      title
    }
  }
}
```

Usando essa mutação, o resultado pode ser semelhante a:

```
{
  "data": {
    "addPerson": {
      "id": "1",
      "name": "Steve Powers",
      "age": "50",
      "occupation": {
        "title": "Miner"
      }
    }
  }
}
```

Como você pode ver, a resposta retornou os valores que solicitamos no mesmo formato definido em nossa mutação. A prática recomendada é retornar todos os valores que foram modificados para reduzir a confusão e a necessidade de mais consultas no futuro. As mutações permitem que você inclua várias operações em seu escopo. Eles serão executados sequencialmente na ordem listada na mutação. Por exemplo, se criarmos outra operação chamada `addOccupation` que adiciona cargos à fonte de dados, podemos chamar isso na mutação depois de `addPerson`. `addPerson` será tratado primeiro, seguido por `addOccupation`.

------
#### [ Subscriptions ]

As assinaturas são usadas [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)para abrir uma conexão bidirecional duradoura entre o servidor e seus clientes. Normalmente, um cliente assina ou escuta o servidor. Sempre que o servidor fizer uma alteração no servidor ou realizar um evento, o cliente assinante receberá as atualizações. Esse tipo de protocolo é útil quando vários clientes são assinantes e precisam ser notificados sobre alterações que estão acontecendo no servidor ou em outros clientes. Por exemplo, as assinaturas podem ser usadas para atualizar feeds de mídia social. Pode haver dois usuários, o usuário A e o usuário B, que são assinantes das atualizações automáticas de notificação sempre que recebem mensagens diretas. O usuário A no cliente A poderia enviar uma mensagem direta para o usuário B no cliente B. O cliente do usuário A enviaria a mensagem direta, que seria processada pelo servidor. O servidor então enviaria a mensagem direta para a conta do Usuário B enquanto enviaria uma notificação automática para o Cliente B.

Aqui está um exemplo de uma `Subscription` que poderíamos adicionar ao exemplo do esquema:

```
type Subscription {                                   
  personAdded: Person
}
```

O campo `personAdded` enviará uma mensagem aos clientes inscritos sempre que uma nova `Person` for adicionada à fonte de dados. Supondo que tenhamos uma implementação de resolvedor para `personAdded`, agora podemos usar a assinatura. Embora o tipo `Subscription` exista, precisamos chamá-lo explicitamente para que ele seja executado no código do aplicativo. Isso pode ser feito usando a palavra-chave `subscription`:

```
subscription personAddedOperation {
  personAdded {
    id
    name
  }
}
```

A assinatura é chamada de `personAddedOperation` e a operação é `personAdded`. `personAdded`retornará os campos `id` e `name` de novas instâncias de `Person`. Analisando o exemplo de mutação, adicionamos uma `Person` usando esta operação:

```
addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner")
```

Se nossos clientes tiverem assinatura para receber atualizações da `Person` recém-adicionada, eles poderão ver isso após as execuções de `addPerson`:

```
{
  "data": {
    "personAdded": {
      "id": "1",
      "name": "Steve Powers"
    }
  }
}
```

Veja abaixo um resumo do que as assinaturas oferecem:

As assinaturas são canais bidirecionais que permitem que o cliente e o servidor recebam atualizações rápidas, mas constantes. Eles normalmente usam o WebSocket protocolo, que cria conexões padronizadas e seguras.

As assinaturas são ágeis, pois reduzem a sobrecarga de configuração da conexão. Depois de fazer uma assinatura, o cliente pode continuar executando essa assinatura por longos períodos. Eles geralmente usam recursos de computação de forma eficiente, permitindo que os desenvolvedores personalizem a vida útil da assinatura e configurem quais informações serão solicitadas.

No geral, o cliente pode fazer várias assinaturas ao mesmo tempo. No que diz respeito AWS AppSync, as assinaturas são usadas apenas para receber atualizações em tempo real do serviço. AWS AppSync Elas não podem ser usadas para realizar consultas ou mutações.

A principal alternativa às assinaturas é a sondagem, que envia consultas em intervalos definidos para solicitar dados. Esse processo geralmente é menos eficiente do que as assinaturas e sobrecarrega muito o cliente e o back-end.

------

Algo que não foi mencionado em nosso exemplo de esquema é o fato de que seus tipos de objetos especiais também devem ser definidos em um `schema` raiz. Então, quando você exporta um esquema AWS AppSync, ele pode ter a seguinte aparência:

------
#### [ schema.graphql ]

```
schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

.
.
.

type Query {                                   
  # code goes here
}
type Mutation {                                   
  # code goes here
}
type Subscription {                                   
  # code goes here
}
```

------

## Enumerações
<a name="enum-components"></a>

Enumerações, ou enums, são escalares especiais que limitam os argumentos legais que um tipo ou campo pode ter. Isso significa que sempre que uma enum for definida no esquema, seu tipo ou campo associado será limitado aos valores da enum. As enums são serializadas como escalares de string. Observe que diferentes linguagens de programação podem lidar com enumerações do GraphQL de forma diferente. Por exemplo, não JavaScript tem suporte nativo para enum, portanto, os valores enum podem ser mapeados para valores int em vez disso.

As enums são definidas usando a palavra-chave `enum`. Veja um exemplo abaixo:

```
enum trafficSignals {
  solidRed
  solidYellow
  solidGreen
  greenArrowLeft
  ...
}
```

Ao chamar o `trafficLights` enum, os argumentos só podem ser `solidRed`, `solidYellow`, `solidGreen`, etc. É comum usar enums para descrever coisas que têm um número distinto, mas limitado, de opções.

## Uniões/Interfaces
<a name="union-interface-components"></a>

Consulte [Interfaces e uniões](https://docs.aws.amazon.com/appsync/latest/devguide/interfaces-and-unions.html) no GraphQL.

# Campos do GraphQL
<a name="graphql-fields"></a>

Os campos existem dentro do escopo de um tipo e contêm o valor solicitado do serviço do GraphQL. Eles são muito semelhantes às variáveis de outras linguagens de programação. Por exemplo, veja um tipo de objeto `Person`:

```
type Person {                                  
   name: String                                  
   age: Int
}
```

Nesse caso, os campos são `name` e `age` e contêm um valor `String` e `Int` respectivamente. Campos de objetos como os mostrados acima podem ser usados como entradas nos campos (operações) de suas consultas e mutações. Por exemplo, veja a `Query` a seguir:

```
type Query {                                   
  people: [Person]
}
```

O campo `people` está solicitando todas as instâncias de `Person` da fonte de dados. Ao adicionar ou recuperar uma `Person` em seu servidor GraphQL, você pode esperar que os dados sigam o formato dos seus tipos e campos, ou seja, a estrutura dos seus dados no esquema determina como eles serão estruturados na sua resposta:

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "age": "50"
      },
      {
        "name": "Andrew Miller",
        "age": "60"
      },
      .
      .
      .
    ]
  }
}
```

Os campos desempenham um papel importante na estruturação dos dados. Há algumas propriedades adicionais explicadas abaixo que podem ser aplicadas aos campos para maior personalização.

## Listas
<a name="list-components"></a>

As listas retornam todos os itens de um tipo especificado. Uma lista pode ser adicionada ao tipo de um campo usando colchetes `[]`: 

```
type Person { 
  name: String
  age: Int
}
type Query {                                   
  people: [Person]
}
```

Na `Query`, os colchetes ao redor de `Person` indicam que você deseja retornar todas as instâncias de `Person` da fonte de dados como uma matriz. Na resposta, os valores `name` e `age` de cada `Person` serão retornados como uma única lista delimitada:

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",         # Data of Person 1
        "age": "50"
      },
      {
        "name": "Andrew Miller",      # Data of Person 2
        "age": "60"
      },
      .                               # Data of Person N
      .
      .
    ]
  }
}
```

Não é necessário usar apenas tipos de objetos especiais. Você também pode usar listas nos campos de tipos de objetos regulares.

## Não nulos
<a name="non-null-components"></a>

Os valores não nulos indicam um campo que não pode ser nulo na resposta. Você pode definir um campo como não nulo usando o símbolo `!`:

```
type Person { 
  name: String!
  age: Int
}
type Query {                                   
  people: [Person]
}
```

O campo `name` não pode ser explicitamente nulo. Se você consultasse a fonte de dados e fornecesse uma entrada nula para esse campo, um erro seria gerado.

Você pode combinar listas e não nulos. Compare estas consultas:

```
type Query {                                   
  people: [Person!]      # Use case 1
}

.
.
.

type Query {                                   
  people: [Person]!      # Use case 2
}

.
.
.

type Query {                                   
  people: [Person!]!     # Use case 3
}
```

No caso de uso 1, a lista não pode conter itens nulos. No caso de uso 2, a lista em si não pode ser definida como nula. No caso de uso 3, a lista e seus itens não podem ser nulos. No entanto, em qualquer um dos casos, você ainda pode retornar listas vazias.

Como você pode ver, há muitos componentes móveis no GraphQL. Nesta seção, mostramos a estrutura de um esquema simples e os diferentes tipos e campos que um esquema permite. Na seção a seguir, você descobrirá os outros componentes de uma API GraphQL e como eles funcionam com o esquema.

# Fontes de dados
<a name="data-source-components"></a>

Na seção anterior, aprendemos que um esquema define a forma dos seus dados. No entanto, não explicamos de onde vieram esses dados. Em projetos reais, seu esquema é como um gateway que manipula todas as solicitações feitas ao servidor. Quando uma solicitação é feita, o esquema atua como o único endpoint que interage com o cliente. O esquema acessa, processa e retransmite dados da fonte de dados para o cliente. Veja o infográfico abaixo:

![\[GraphQL schema integrating multiple Serviços da AWS for a single endpoint API architecture.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/aws-flow-infographic.png)


AWS AppSync e o GraphQL implementam de forma excelente as soluções Backend For Frontend (BFF). Eles trabalham em conjunto para reduzir a complexidade em grande escala ao abstrair o back-end. Caso seu serviço use fontes de dados e/ou microsserviços diferentes, você pode basicamente abstrair parte da complexidade definindo a forma dos dados de cada fonte (subgráfico) em um único esquema (supergráfico). Isso significa que sua API GraphQL não precisa usar uma única fonte de dados. Você pode associar qualquer número de fontes de dados à sua API GraphQL e especificar no seu código como elas interagirão com o serviço.

Como você pode ver no infográfico, o esquema do GraphQL contém todas as informações que os clientes precisam para solicitar dados. Isso significa que tudo pode ser processado em uma única solicitação, em vez de várias solicitações, como é o caso do REST. Essas solicitações passam pelo esquema, que é o único endpoint do serviço. Quando as solicitações são processadas, um resolvedor (explicado na próxima seção) executa seu código para processar os dados da fonte de dados relevante. Quando a resposta for retornada, o subgráfico vinculado à fonte de dados será preenchido com os dados no esquema. 

AWS AppSync oferece suporte a vários tipos diferentes de fontes de dados. Na tabela abaixo, descreveremos cada tipo, listaremos alguns dos benefícios de cada um e forneceremos links úteis que trazem mais contexto.


| Fonte de dados | Description | Benefícios | Informações complementares | 
| --- | --- | --- | --- | 
| Amazon DynamoDB | “O Amazon DynamoDB é um serviço de banco de dados NoSQL totalmente gerenciado que fornece uma performance rápida e previsível com escalabilidade integrada. O DynamoDB permite que você transfira os encargos administrativos de operação e escalabilidade de um banco de dados distribuído. Assim, você não precisa se preocupar com provisionamento, instalação e configuração de hardware, replicação, correção de software nem escalabilidade de cluster. Além disso, o DynamoDB oferece criptografia em repouso, o que elimina a carga e a complexidade operacionais envolvidas na proteção de dados confidenciais.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  | 
| AWS Lambda | “AWS Lambda é um serviço de computação que permite executar código sem provisionar ou gerenciar servidores.O Lambda executa seu código em uma infraestrutura de computação de alta disponibilidade e executa toda a administração dos recursos computacionais, incluindo manutenção do servidor e do sistema operacional, provisionamento e escalabilidade automática da capacidade e registro em log do código. Com o Lambda, tudo o que você precisa fazer é fornecer seu código em um dos runtimes de linguagens compatíveis com o Lambda.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  | 
| OpenSearch | “O Amazon OpenSearch Service é um serviço gerenciado que facilita a implantação, a operação e a escalabilidade de OpenSearch clusters na AWS nuvem. O Amazon OpenSearch Service suporta OpenSearch e lega o Elasticsearch OSS (até a versão 7.10, a versão final de código aberto do software). Ao criar um cluster, você tem a opção de escolher qual mecanismo de pesquisa deseja usar.**OpenSearch**é um mecanismo de pesquisa e análise totalmente de código aberto para casos de uso como análise de registros, monitoramento de aplicativos em tempo real e análise de fluxo de cliques. Para obter mais informações, consulte a [documentação do OpenSearch](https://opensearch.org/docs/).**O Amazon OpenSearch Service** provisiona todos os recursos do seu OpenSearch cluster e o executa. Ele também detecta e substitui automaticamente os nós de OpenSearch serviço com falha, reduzindo a sobrecarga associada às infraestruturas autogerenciadas. Você pode escalar seu cluster com uma única chamada de API ou alguns cliques no console.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  | 
| Endpoints de HTTP | Você pode usar endpoints HTTP como fontes de dados. AWS AppSync pode enviar solicitações aos endpoints com as informações relevantes, como parâmetros e carga útil. A resposta HTTP será exposta ao resolvedor, que retornará a resposta final após concluir suas operações. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  | 
| Amazon EventBridge | “EventBridge é um serviço sem servidor que usa eventos para conectar componentes do aplicativo, facilitando a criação de aplicativos escaláveis orientados por eventos. Use-o para rotear eventos de fontes como aplicativos, AWS serviços e software de terceiros desenvolvidos internamente para aplicativos de consumo em toda a sua organização. EventBridge fornece uma maneira simples e consistente de ingerir, filtrar, transformar e entregar eventos para que você possa criar novos aplicativos rapidamente.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  | 
| Bancos de dados relacionais | “O Amazon Relational Database Service (Amazon RDS) é um serviço web que facilita a configuração, a operação e a escalabilidade de um banco de dados relacional na nuvem. AWS Ele fornece capacidade econômica e redimensionável para um banco de dados relacional padrão do setor e gerencia tarefas comuns de administração de banco de dados. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  | 
| Fonte de dados none | Se você não pretende usar uma fonte de dados, pode defini-la como none. Uma fonte de dados none, embora ainda seja explicitamente categorizada como fonte de dados, não é um meio de armazenamento. Apesar disso, ela ainda é útil em algumas instâncias para manipulação e passagem de dados. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/data-source-components.html)  | 

**dica**  
Para obter mais informações sobre como as fontes de dados interagem AWS AppSync, consulte [Anexando uma fonte de dados](https://docs.aws.amazon.com//appsync/latest/devguide/attaching-a-data-source.html).

# Resolvedores
<a name="resolver-components"></a>

Nas seções anteriores, você aprendeu sobre os componentes do esquema e da fonte de dados. Agora, precisamos abordar como o esquema e as fontes de dados interagem. Tudo começa com o resolvedor.

Um resolvedor é uma unidade de código que controla como os dados desse campo serão resolvidos quando uma solicitação for feita ao serviço. Os resolvedores são anexados a campos específicos dentro dos seus tipos em seu esquema. Eles costumam ser usados para implementar as operações de mudança de estado para suas operações de campo de consulta, mutação e assinatura. O resolvedor processará a solicitação de um cliente e retornará o resultado, que pode ser um grupo de tipos de saída, como objetos ou escalares:

![\[GraphQL schema with resolvers connecting to various AWS data sources for a single endpoint.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/aws-flow-infographic.png)


## Runtime do resolvedor
<a name="resolver-components-runtime"></a>

Em AWS AppSync, você deve primeiro especificar um tempo de execução para seu resolvedor. Um runtime do resolvedor indica o ambiente no qual um resolvedor é executado. Também determina o idioma em que seus resolvedores serão escritos. AWS AppSync atualmente suporta APPSYNC\$1JS JavaScript e Velocity Template Language (VTL). Consulte os [recursos JavaScript de tempo de execução para resolvedores e funções](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html) JavaScript ou a [referência do utilitário de modelo de mapeamento Resolver](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html) para VTL.

## Estrutura do resolvedor
<a name="resolver-components-structure"></a>

Em termos de código, os resolvedores podem ser estruturados de duas maneiras. Existem resolvedores de **unidades** e de **pipeline**.

### Resolvedores de unidade
<a name="resolver-components-unit"></a>

Um resolvedor de unidade é composto de código que define um único manipulador de solicitação e resposta que é executado em uma fonte de dados. O manipulador da solicitação usa um objeto de contexto como argumento e retorna a payload da solicitação usada para chamar sua fonte de dados. O manipulador de respostas recebe uma payload da fonte de dados com o resultado da solicitação executada. O manipulador de respostas transforma a payload em uma resposta do GraphQL para resolver o campo do GraphQL.

![\[GraphQL request flow showing request and response handlers interacting with a data source.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/unit-resolver-js.png)


### Resolvedores de pipeline
<a name="resolver-components-pipeline"></a>

Ao implementar resolvedores, eles seguem uma estrutura geral:
+ **Etapa Anterior**: quando uma solicitação é feita pelo cliente, os resolvedores dos campos do esquema que estão sendo usados (normalmente consultas, mutações e assinaturas) recebem os dados da solicitação. O resolvedor começará a processar os dados da solicitação com um manipulador de etapas anteriores, o que permite que algumas operações de pré-processamento sejam executadas antes que os dados passem pelo resolvedor.
+ **Função(ões)**: Após a execução da etapa anterior, a solicitação é passada para a lista de funções. A primeira função na lista será executada na fonte de dados. Uma função é um subconjunto do código do resolvedor contendo seu próprio manipulador de solicitações e respostas. Um manipulador de solicitações pegará os dados da solicitação e executará operações na fonte de dados. O manipulador de respostas processará a resposta da fonte de dados antes de passá-la de volta para a lista. Se houver mais de uma função, os dados da solicitação serão enviados para a próxima função a ser executada na lista. As funções na lista serão executadas na ordem definida pelo desenvolvedor. Depois que todas as funções forem executadas, o resultado final será passado para a etapa posterior.
+ **Etapa Posterior**: a etapa Posterior é uma função do manipulador que permite realizar algumas operações finais na resposta da função final antes de passá-la para a resposta do GraphQL.

![\[GraphQL request flow diagram showing interactions between request, data sources, and response components.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/appsync-js-resolver-logic.png)


## Estrutura do manipulador do resolvedor
<a name="resolver-components-handlers"></a>

Os manipuladores são normalmente funções chamadas `Request` e `Response`:

```
export function request(ctx) {
    // Code goes here
}

export function response(ctx) {
    // Code goes here
}
```

Em um resolvedor de unidades, haverá apenas um conjunto dessas funções. Em um resolvedor de pipeline, haverá um conjunto dessas etapas para a etapa Anterior e etapa Posterior e um conjunto adicional por função. Para visualizar esse caso, vamos analisar um tipo `Query` simples:

```
type Query {
	helloWorld: String!
}
```

Essa é uma consulta simples com um campo chamado `helloWorld` do tipo `String`. Vamos supor que sempre queremos que esse campo retorne a string “Hello World”. Para implementar esse comportamento, precisamos adicionar o resolvedor a esse campo. Em um resolvedor de unidades, poderíamos adicionar algo assim:

```
export function request(ctx) {
    return {}
}

export function response(ctx) {
    return "Hello World"
}
```

A `request` pode ser deixada em branco porque não estamos solicitando ou processando dados. Também podemos supor que nossa fonte de dados seja `None`, indicando que esse código não precisa realizar nenhuma invocação. A resposta simplesmente retorna “Hello World”. Para testar esse resolvedor, precisamos fazer uma solicitação usando o tipo de consulta:

```
query helloWorldTest {
  helloWorld
}
```

Essa é uma consulta chamada `helloWorldTest` que retorna o campo `helloWorld`. Quando executado, o resolvedor do campo `helloWorld` também executa e retorna a resposta:

```
{
  "data": {
    "helloWorld": "Hello World"
  }
}
```

Retornar constantes como essa é a coisa mais simples que você pode fazer. Na realidade, você retornará entradas, listas e muito mais. O exemplo a seguir é mais complicado:

```
type Book {
  id: ID!
  title: String
}

type Query {
  getBooks: [Book]
}
```

Aqui estamos retornando uma lista de `Books`. Vamos supor que estejamos usando uma tabela do DynamoDB para armazenar dados do livro. Os manipuladores podem ser semelhantes a estes:

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

Nossa solicitação usou uma operação de verificação integrada para pesquisar todas as entradas na tabela, armazenar as descobertas no contexto e depois passá-las para a resposta. A resposta pegou os itens do resultado e os retornou na resposta:

```
{
  "data": {
    "getBooks": {
      "items": [
        {
          "id": "abcdefgh-1234-1234-1234-abcdefghijkl",
          "title": "book1"
        },
        {
          "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
          "title": "book2"
        },

        ...

      ]
    }
  }
}
```

## Contexto do resolvedor
<a name="resolver-components-context"></a>

Em um resolvedor, cada etapa na cadeia de manipuladores deve estar ciente do estado dos dados das etapas anteriores. O resultado de um manipulador pode ser armazenado e passado para outro como argumento. O GraphQL define quatro argumentos básicos do resolvedor:


****  

| Argumentos básicos do resolvedor | Description | 
| --- | --- | 
| obj, root, parent etc. | O resultado do pai. | 
| args | Os argumentos fornecidos ao campo na consulta do GraphQL. | 
| context | Um valor que é fornecido a cada resolvedor e contém informações contextuais importantes, como o usuário atualmente conectado ou o acesso a um banco de dados. | 
| info | Um valor que contém informações específicas do campo relevantes para a consulta atual, bem como os detalhes do esquema. | 

Em AWS AppSync, o argumento `[context](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)` (ctx) pode conter todos os dados mencionados acima. Trata-se um objeto criado por solicitação e contém dados como credenciais de autorização, dados de resultados, erros, metadados de solicitações etc. O contexto é uma maneira fácil para os programadores manipularem dados provenientes de outras partes da solicitação. Considere este trecho novamente:

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

A solicitação recebe o contexto (ctx) como argumento; esse é o estado da solicitação. Ele executa uma varredura de todos os itens em uma tabela e, em seguida, armazena o resultado no contexto em `result`. O contexto é então passado para o argumento de resposta, que acessa o `result` e retorna seu conteúdo.

## Solicitações e análises
<a name="resolver-ast"></a>

Quando você faz uma consulta ao seu serviço do GraphQL, ela deve passar por um processo de análise e validação antes de ser executada. Sua solicitação será analisada e traduzida em uma árvore de sintaxe abstrata. O conteúdo da árvore é validado por meio da execução de vários algoritmos de validação em relação ao seu esquema. Após a etapa de validação, os nós da árvore são percorridos e processados. Os resolvedores são invocados, os resultados são armazenados no contexto e a resposta é retornada. Por exemplo, considere esta consulta:

```
query {
  Person {  //object type
    name  //scalar
    age   //scalar
  } 
}
```

Estamos retornando `Person` com campos `name` e `age`. Ao executar essa consulta, a árvore será semelhante a esta:

![\[Hierarchical diagram showing query, Person, name, and age nodes connected by arrows.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/ast-1.png)


Na árvore, parece que essa solicitação pesquisará a raiz de `Query` no esquema. Dentro da consulta, o campo `Person` será resolvido. Com base em exemplos anteriores, sabemos que isso pode ser uma entrada do usuário, uma lista de valores, etc. A `Person` provavelmente está vinculada a um tipo de objeto que contém os campos de que precisamos (`name` e `age`). Depois que esses dois campos secundários são encontrados, eles são resolvidos na ordem indicada (`name` seguido por `age`). Depois que a árvore for completamente resolvida, a solicitação será concluída e enviada de volta ao cliente.

# Propriedades adicionais do GraphQL
<a name="graphql-properties"></a>

O GraphQL consiste em vários princípios de design para manter a simplicidade e a robustez em grande escala.

## Declarativo
<a name="declarative-property"></a>

O GraphQL é declarativo, o que significa que o usuário descreverá (moldará) os dados declarando apenas os campos que deseja consultar. A resposta retornará somente os dados dessas propriedades. Por exemplo, aqui está uma operação que recupera um `Book` objeto em uma tabela do DynamoDB com o valor ISBN 13 de: `id` *9780199536061*

```
{
  getBook(id: "9780199536061") {
    name
    year
    author
  }
}
```

A resposta retornará os campos na payload (`name`, `year` e `author`) e nada mais:

```
{
  "data": {
    "getBook": {
      "name": "Anna Karenina",
      "year": "1878",
      "author": "Leo Tolstoy",
    }
  }
}
```

Por causa desse princípio de design, o GraphQL elimina os problemas perenes de busca excessiva e insuficiente que o REST APIs enfrenta em sistemas complexos. Isso resulta em coleta de dados mais eficiente e melhor desempenho da rede.

## Hierárquico
<a name="hierarchical-property"></a>

O GraphQL é flexível, pois os dados solicitados podem ser moldados pelo usuário para atender às necessidades do aplicativo. Os dados solicitados sempre seguem os tipos e a sintaxe das propriedades definidas na sua API GraphQL. Por exemplo, o trecho a seguir mostra a `getBook` operação com um novo escopo de campo chamado `quotes` que retorna todas as cadeias de aspas armazenadas e páginas vinculadas ao: `Book` *9780199536061*

```
{
  getBook(id: "9780199536061") {
    name
    year
    author
    quotes {
      description
      page
    }
  }
}
```

Ao executar esta consulta, retornaremos o seguinte resultado:

```
{
  "data": {
    "getBook": {
      "name": "Anna Karenina",
      "year": "1878",
      "author": "Leo Tolstoy",
      "quotes": [
         {
            "description": "The highest Petersburg society is essentially one: in it everyone knows everyone else, everyone even visits everyone else.",
            "page": 135
         },
         { 
            "description": "Happy families are all alike; every unhappy family is unhappy in its own way.",
            "page": 1
         },
         {        
            "description": "To Konstantin, the peasant was simply the chief partner in their common labor.",
            "page": 251
         }
      ]
    }
  }
}
```

Como você pode ver, os campos `quotes` vinculados ao livro solicitado foram retornados como uma matriz no mesmo formato descrito em nossa consulta. Embora não tenha sido mostrado aqui, o GraphQL tem a vantagem adicional de não ser restrito sobre a localização dos dados que está recuperando. `Books` e `quotes` podem ser armazenados separadamente, mas o GraphQL ainda recuperará as informações enquanto a associação existir. Isso significa que sua consulta pode recuperar vários dados autônomos em uma única solicitação.

## Introspectivo
<a name="introspective-property"></a>

O GraphQL é autodocumentado ou introspectivo. Ele oferece suporte a várias operações integradas que permitem que os usuários visualizem os tipos e campos subjacentes no esquema. Por exemplo, aqui está um tipo `Foo` com um campo `date` e `description`:

```
type Foo {
	date: String
	description: String
}
```

Poderíamos usar a operação `_type` para encontrar os metadados de digitação abaixo do esquema:

```
{
  __type(name: "Foo") {
    name                   # returns the name of the type
    fields {               # returns all fields in the type
      name                 # returns the name of each field
      type {               # returns all types for each field
        name               # returns the scalar type
      }
    }
  }
}
```

Isso retornará uma resposta:

```
{
  "__type": {
    "name": "Foo",                     # The type name
    "fields": [
      {
        "name": "date",                # The date field
        "type": { "name": "String" }   # The date's type
      },
      {
        "name": "description",         # The description field
        "type": { "name": "String" }   # The description's type
      },
    ]
  }
}
```

Esse atributo pode ser usado para descobrir quais tipos e campos um determinado esquema do GraphQL aceita. O GraphQL é compatível com uma ampla variedade dessas operações introspectivas. Para obter mais informações, consulte [Introspecção](https://graphql.org/learn/introspection/).

## Tipificação forte
<a name="strong-typing-property"></a>

O GraphQL oferece suporte a tipificação forte por meio de seu sistema de tipos e campos. Quando você define algo em seu esquema, ele deve ter um tipo que possa ser validado antes do runtime. Ele também deve seguir a especificação de sintaxe do GraphQL. Esse conceito não é diferente da programação em outras linguagens. Por exemplo, este é o tipo `Foo` anterior:

```
type Foo {
	date: String
	description: String
}
```

Podemos ver que esse `Foo` é o objeto que será criado. Dentro de uma instância de `Foo`, haverá um campo `date` e `description`, ambos do tipo primitivo `String` (escalar). Sintaticamente, vemos que `Foo` foi declarado e seus campos existem dentro de seu escopo. Essa combinação de verificação de tipo e sintaxe lógica garante que sua API GraphQL seja concisa e evidente. A especificação de tipificação e sintaxe do GraphQL pode ser encontrada [aqui](https://spec.graphql.org/).