Aprenda o GraphQL de forma simples e direta

Vou tentar passar neste artigo uma visão simples sobre o GraphQL, tenho ouvido bastante sobre essa tecnologia e resolvi estudar um pouco e escrever também a fim de ajudar quem esteja procurando mais informações para implementar a ferramenta de forma bem básica.

Para isso vou escrever um pouco sobre definições e pontos conceituais importantes e também construir uma aplicação simples em .NET CORE para exemplificar o uso da tecnologia.

A ideia aqui não é comparar o GraphQL com o padrão REST API, são “coisas” diferentes ok.

O artigo é um pouco extenso então navegue pelo sumário abaixo para facilitar:

O que significa?

GraphQL significa Graph Query Language ou Linguagem de Consulta de dados em grafos, como o nome sugere, é uma linguagem de consulta semelhante ao SQL (Structured Query Language), mas seu uso não envolve a implementação de um banco de dados, mas sim a definição de dados para uma API ou servidor.

GraphQL é uma SPEC ou seja uma especificação, uma sintaxe e um runtime, é open source e possui plugins com suporte a várias linguagens.

É importante frisar que GraphQL não é um banco de dados, não substitui o SQL e não é uma ferramenta do lado do servidor.

Quem criou?

GraphQL foi desenvolvido pelo Facebook em 2012 para facilitar a entrega de dados para as aplicações web e mobile, lançada publicamente em 2015.

Vantagens

Permite aos clientes especificar precisamente o que precisam, e nada mais, facilitando o seu uso.

Por exemplo imagine uma situação onde você precise efetuar um GET (REST) para uma listagem de clientes que retorna propriedades como nome, sobrenome, endereço, documentos enfim várias propriedades mas na sua tela (web ou mobile) irá usar somente o nome e o sobrenome do cliente.

Pois bem usando o GraphQL vc pode solicitar apenas as duas propriedades que precisa ou seja somente o nome e o sobrenome.

Ok, mas porque simplesmente não ignorar as propriedades excedentes no FrontEnd?

É a situação comum fazer, simplesmente não usar as propriedades excedentes mas precisamos levar em conta que quanto mais caracteres se manda em uma resposta http mais bytes são trafegados, então enviar dados que não serão utilizados pelo front é custo desnecessário.

Esse cenário é chamado de “Over-Fetching” onde o pacote trafegado contém mais dados que o necessário. O GraphQL vem para resolver esse problema, bem como ao contrario também o chamado “Under-Fetching” que é o trafego de menos dados do que o front precisa.

Trafegar mais dados do que precisa pode parecer “inofensivo” mas pense em um cenário onde sua aplicação está hospedada em uma estrutura paga por uso, por exemplo a AWS, você irá pagar por uso de recursos e um desses recursos é o tráfego ou seja a quantidade de dados (bytes) que estão sendo transmitidos pela rede.

Outro ponto positivo é o aumento de performance, pacotes pequenos com a quantidade correta de dados serão mais rápidos que pacotes com dados sem necessidade.

Ainda temos a facilidade de agregação ou seja podemos agregar os dados no lado servidor consumindo diversas fontes de dados e disponibilizar a API permitindo que o client consuma apenas o que for necessário.

Outra vantagem: temos no GraphQL somente um endpoint (/graphql) isso torna-se muito interessante pois acaba com aquele “monte” de endpoints que as API´s possuem, sem se preocupar com o versionamento.

Ah esse endpoint só aceita um POST e a “query” deve ser enviada no corpo da requisição.

Conceitos

Temos no GraphQL basicamente três operações: Querys, Mutations e Subscription.

Query – use para obter dados fazendo uma analogia ao padrão REST seria similar a operação de GET.

Mutations – use para manipular dados, similar as operações de POST/PUT/PATH e DELETE do padrão REST.

Subscription – é um mecanismo integrado que realiza notificações ao cliente sempre que alguma modificação de dados for feita ou seja uma mutation.

Integração com o .NET

O GraphQL pode conviver junto com sua API Rest, podemos ter nossa API expondo seus endpoints normalmente e também o endpoint /graphql.

Ao meu ver é só criar uma separação de classes organizada para entender certinho o escopo de uma abordagem em relação a outra.

Mão na massa

Para exemplificar o uso da ferramenta, gerei uma aplicação em .NET CORE 5 com o seguinte cenário de classes:

diagrama de classes

Basicamente temos um cliente (customer) que tem uma relação de 1 para n orders (ordens de compra de ações do mercado financeiro).

O exemplo está no meu github, separei por branches lá para facilitar o entendimento.

Na branch main está o exemplo sem graphql e rodando o mesmo teremos a saida no formato swagger conforme a imagem abaixo:

swagger da aplicação

O exemplo usa um banco de dados SQL SERVER que já está contido na pasta APP_DATA do exemplo, fiz isso para facilitar o entendimento e o uso, você nem precisa ter o banco instalado ae na sua máquina, usei o Entity Framework CORE para conectar com o repositorio. Tudo simples e direto para nosso exemplo.

Temos ali 3 endpoints:

  • Busca todos os clientes;
  • Busca um cliente retornando as ordens ou não, depende de um parametro;
  • Busca todas as ordens cadastradas.

Basta baixar a aplicação aqui no meu repositório (baixe a branch main) e rodar para funcionar.

Agora vamos instalar o GraphQL no exemplo, para isso adicione as referencias necessárias no projeto:

adicionando referencias no projeto

Existem outras bibliotecas para implementar o GraphQL ok, como por exemplo o Hot Chocolate (https://chillicream.com/docs/hotchocolate/get-started), vou implementar uma versão usando o Hot Chocolate no futuro e posto aqui.

Crie um pasta na raiz do projeto com a descrição “GraphQL” dentro dela teremos as pastas “Query”, “Schema” e “Types”

fluxo

Vamos criar agora as classes que vamos utilizar em nossas consultas GraphQL:

Dentro da pasta types vamos criar 4 classes conforme imagem abaixo:

public class CustomerType: ObjectGraphType<Customer>
{
  public CustomerType()
  {
    Field(x => x.Id, type: typeof(IdGraphType)).Description("Identificador do cliente.");
    Field(x => x.Name).Description("Nome do cliente.");
    Field(x => x.IdentificationNumber).Description("Número de identificaçao do cliente.");
    Field(x => x.Email).Description("Email do cliente.");
    Field(
        name: "orders",
        description: "Lista de ordens",
        type: typeof(ListGraphType<OrderType>),
       resolve: m => m.Source.Orders);
  }
}
public class OrderTypeEnumType: EnumerationGraphType<TypeOrder>
{
   public OrderTypeEnumType()
   {
     Name = "Type";
     Description = "Enumeração para o tipo de ordem";
   }
}
public class StatusOrderEnumType : EnumerationGraphType<StatusOrder>
{
  public StatusOrderEnumType()
  {
    Name = "Status";
    Description = "Status da ordem";
   }
}
public OrderType()
{
  Field(x => x.Id, type: typeof(IdGraphType)).Description("Identificador da ordem de compra.");
  Field(x => x.CustomerId, type: typeof(IdGraphType)).Description("Identificador do cliente.");
  Field(x => x.CreatedAt).Description("Data de criação da ordem.");
  Field(x => x.Price).Description("Preço unitário do ativo.");
  Field(x => x.Quantity).Description("Quantidade de ativos na ordem.");
  Field(x => x.Symbol).Description("Simbolo do ativo.");
  Field<OrderTypeEnumType>("Type", "Enumeração para o tipo de ordem.");
  Field<StatusOrderEnumType>("Status", "Enumeração para o status de ordem.");
 }

Dentro da pasta Query crie a classe AppQuerie.cs:

public class AppQuery: ObjectGraphType
{
  public AppQuery(ICustomerRepository repository)
  {
    Name = "Consultas";
    Description = "A consulta base para todas as entidades em nosso gráfico de objetos.";

    //Para listar todos os clientes com respectivas ordens
    Field<ListGraphType<CustomerType>>(
                "customers",
                "Retorna uma lista de clientes com suas respectivas ordens.",
                resolve: context => repository.GetAllWithOrders()
                );

    //para consultar um cliente pelo ID
    Field<CustomerType>("customer", "Retorna um cliente pelo ID",new QueryArguments(new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "id", Description = "Customer Id" }),
                    context => repository.GetById(Guid.Parse(context.GetArgument<string>("id")), true));
  }
}

Dentro da pasta Schema crie a classe AppSchema.cs

public class AppSchema: Schema
{
   public AppSchema(IServiceProvider provider)
      : base(provider)
   {
     Query = provider.GetRequiredService<AppQuery>();
   }
}

Agora vamos as mudanças na classe Startup.cs, insira dentro do método ConfigureServices:

services.AddScoped<AppSchema>();

services.AddGraphQL()
        .AddSystemTextJson()
        .AddGraphTypes(typeof(AppSchema), ServiceLifetime.Scoped)
        .AddErrorInfoProvider(opt => opt.ExposeExceptionStackTrace = true);

E no método Configure:

app.UseGraphQL<AppSchema>("/graphql");
app.UseGraphQLPlayground();

Pronto! com isso o GraphQL deve estar funcional, lembrando que voce não precisa codar, já está tudo pronto no repositório, baixe a solution que está na branch “includeGraphQLQuery“.

Rodando o projeto

Boa, agora vamos rodar o projeto para isso basta selecionar o projeto conforme imagem abaixo:

rodando o projeto

O padrão é abrir a tela do swagger normalmente, e aqui vai uma evidência muito legal, o padrão REST pode conviver junto com o padrão do GraphQL.

projeto aberto na tela do swagger

Agora pra abrir o “PlayGround” do GraphQL basta alterar a url para:

http://localhost:5000/ui/playground

tela inicial do playground

O GraphQL Playground é uma interface para que o usuário trabalhe com a API GraphQL, ele fornece vários recursos como intellisense, sugestões, notificações de erros de sintaxe em tempo real e muito mais.

Agora vamos executar nossa primeira query no projeto, para isso basta digitar o seguinte comando no quadro esquerdo da ferramenta:

{
  customers {
    id
    name
    identificationNumber
    email
    orders{
      id
      customerId
      createdAt
      price
      quantity
      symbol
      type
      status
    }
  }
}
Consultando todos os clientes

Para consultar um cliente pelo ID utilize o comando abaixo:

{
  customer(id: "6e2eccf5-0204-45c5-b519-a49944fa08c8") {
    id
    name
    identificationNumber
    email
    orders{
      id
      customerId
      createdAt
      price
      quantity
      symbol
      type
      status
    }
  }
}
Consultando um cliente pelo ID

Importante: Nas consultas você pode solicitar que só retorne os dados que necessita por exemplo poderia rodar uma query que só retorna-se do cliente os campos id, nome e email por exemplo:

consulta definindo apenas alguns campos de retorno

Ah é possivel utilizar qualquer ferramenta de consulta para buscar os dados ok, podemos fazer isso com o POSTMAN por exemplo:

consulta via postman na API GraphQL

Para este primeiro artigo era isso que queria mostrar.

Vou fazer um segundo explicando como criar as mutations, trabalhar com subscriptions, como melhorar as consultas, criar fragmentos, consultas nomeadas, variaveis na consulta e mais coisas legais que podemos fazer com o GraphQL, aguardem !

Onde aprender mais?

Para aprender mais sobre o GraphQL não faltam tutoriais bons espalhados pela internet, mas abaixo segue dois ótimos links:

Conclusão

GraphQL é uma linguagem de consulta criada pelo Facebook para facilitar o processamento eficiente de dados sem criar rotas infinitas na API. Ao contrário do que você possa pensar, o REST não vai morrer com a popularidade do GraphQL, e os dois têm propostas diferentes para situações diferentes.

Por esse motivo, a tecnologia do Facebook não é recomendada para todos os projetos, pois é relativamente nova e ainda está buscando seu espaço no mercado de trabalho.

Fico por aqui, agradeço sua leitura, qualquer comentário será muito bem vindo e fortalece demais. Aguardem o próximo artigo!

Obrigado e até mais!

Leave a Reply

O seu endereço de e-mail não será publicado.