Aprenda o GraphQL de forma simples e direta – Parte 2

Vamos a segunda parte do meu artigo sobre GraphQL, se não viu a primeira parte corre lá neste link.

No primeiro artigo da série, construimos uma aplicação bem básica e entramos no mundo do GraphQL entendendo como a tecnologia funciona e efetuando queries.

É um artigo bem extenso e com bastante informação bacana. Então se ainda não leu sugiro que vá e leia antes de iniciar este artigo.

Agora vamos ver outras funcionalidades do GraphQL.

IMPORTANTE: Vamos utilizar aqui o mesmo repositório da primeira parte, os exemplos de queries deste tutorial e as mutações estão codificadas na branch “includeMutation“, basta baixar e colocar para rodar.

Como tratar erros e validar parâmetros.

Em alguns cenários precisamos validar parâmetros que a API GraphQL irá receber. Vamos a um exemplo prático:

Quero consultar um cliente pelo ID que em nosso modelo de dados é um GUID, vou passar um valor incorreto e quero que a API me devolva uma mensagem de erro informando que o ID passado como parâmetro está incorreto.

Vamos criar um “Field” novo na classe AppQuery:

Field<CustomerType>(
  "customerById",
  arguments: new QueryArguments(new QueryArgument<NonNullGraphType<IdGraphType>> { Name = "customerId" }),
  resolve: context =>
  {
    Guid id;
    if (!Guid.TryParse(context.GetArgument<string>("customerId"), out id))
    {
      context.Errors.Add(new ExecutionError("Valor inserido não é um guid válido"));
      return null;
    }
    return repository.GetById(id, true);
  }
);

Vamos rodar o projeto e efetuar a “query” enviando um ID (GUID) incorreto:

Enviando um GUID incorreto.

Como pode-se observar na imagem enviei um ID “1234” e o GraphQL retornou a mensagem “Valor inserido não é um guid válido“. Bacana!

Vamos mandar um GUID válido agora e verificar o retorno:

Enviando um GUID válido.

Retornou o cliente corretamente!

Alias ou Apelidos.

Podemos do lado do cliente querer modificar os nomes das propriedades no retorno da consulta.

Por exemplo vamos efetuar uma consulta que deve retornar um “customer” pelo ID:

Consultando um cliente pelo id.

Vamos supor que precise retornar as mesmas propriedades mas minha estrutura necessita que as propriedades venham em português para fazer o parse dos dados, podemos resolver de forma simples criando alias para os campos desta forma:

Consultando com alias.

Usamos “alias” ou apelidos ali para os campos modificando o response de acordo com nossa necessidade.

Consultando dois clientes em um só request.

Podemos customizar nossas queries para por exemplo buscar dois clientes na base de dados em um request só:

Dois clientes na mesma request

A query acima solicitou ao GraphQL dois clientes distintos, com campos distintos e nomenclatura diferente no caso do nome do primeiro cliente.

Imagina a liberdade que isso proporciona! bem legal.

Usar Fragmentos.

No exemplo acima consultamos dois clientes distintos, agora vamos imaginar um cenário onde precisamos consultar 100 clientes, todos possuindo no response campos em comum, para que a query fique mais simples podemos usar os “fragments” do GraphQL:

Uso de fragments.

Foi criado um bloco abaixo da consulta de fragmento:

fragment camposComuns on CustomerType{
  identificador:id
  documento:identificationNumber
}

Para usar o fragmento criado basta trocar os campos pelo comando:

 ...camposComuns

Simples e economiza bastante linha de código ali na requisição.

O que são mutações?

As mutações (mutations) no GraphQL são ações que realizamos para criar, alterar ou deletar dados, são parecidos com os métodos post, put e delete do padrão REST.

O primeiro passo para trabalhar com mutations é criar uma classe que herde de ObjectGraphType:

public class AppMutation: ObjectGraphType
{
   public AppMutation(ICustomerRepository repository)
   {
   }
}

A classe acima recebe no construtor o repositório do customer (interface), não vou tratar aqui no artigo sobre a classe de repositório, nela basicamente estão codificados os métodos de create, update e delete bem básicos conforme a interface abaixo:

Métodos novos para entender as mutações.

Depois precisei fazer uma alteração na classe AppSchema para incluir a classe de mutation:

Alteração necessária para que as mutações funcionem.

Mutação – Create

Vamos criar uma mutação que possui a responsabilidade de criar um “customer” novo em nosso repositório de dados.

Comecei alterando a classe AppMutation inserindo nela um “Field” responsável pela criação:

Field<CustomerType>(
   "createCustomer",
    arguments: new QueryArguments(new QueryArgument<NonNullGraphType<CustomerInputType>> { Name = "customer" }),
    resolve: context =>
    {
       var customer = context.GetArgument<Customer>("customer");
       return repository.Create(customer);
     }
 );

Depois podemos simplesmente rodar a aplicação e testar a mutação de “create”, para rodar basta apertar o F5, a aplicação irá abrir a tela do swagger padrão da API REST, basta modificar a url para “localhost:5000/ui/playground“:

Enviando uma mutação de create para o GraphQL.

Basicamente criamos um objeto JSON no campo “QUERY VARIABLES” do playground:

{
  "customer": {
    "name" : "Heitor Dias",
    "identificationNumber": "123456789",
    "email": "heitor@teste.com.br"
  }
}

Na request está a “mutation” que recebe como parâmetro o objeto “customerInput“, basicamente ele irá converter o que foi inserido no QUERY VARIABLES para o objeto “customerInput“:

mutation($customer: customerInput!){
  createCustomer(customer: $customer){
    id,
    name,
    identificationNumber,
    email
  }
}

Mutação – Update

Para efetuar uma mutação do tipo “Update” criei mais um “Field” na classe AppMutation conforme o código abaixo:

Field<CustomerType>(
   "updateCustomer",
    arguments: new QueryArguments(
       new QueryArgument<NonNullGraphType<CustomerInputType>> { Name = "customer" },
       new QueryArgument<NonNullGraphType<IdGraphType>> { Name = "customerId" }),
    resolve: context =>
    {
      var customer = context.GetArgument<Customer>("customer");
      var customerId = context.GetArgument<Guid>("customerId");

      var dbCustomer = repository.GetById(customerId, false).Result;
      if (dbCustomer == null)
      {
        context.Errors.Add(new ExecutionError("Cliente não encontrado na base de dados com este id."));
        return null;
      }
      return repository.Update(dbCustomer, customer);
    }
 );

Vamos rodar novamente a aplicação:

Enviando uma mutação de update para o GraphQL.

O funcionamento é basicamente igual ao método de create, criamos um JSON que representa o objeto “customerInput“, definimos os campos a serem alterados.

Precisamos ainda precisamos definir o ID do cliente que vamos alterar:

{
  "customer": {
    "name" : "Heitor Dias Alterado",
    "identificationNumber": "12345678",
    "email": "heitordias@teste.com.br"
  },
  "customerId": "a36169e2-0c47-4134-906f-eda6f05cb166"
  
}

Agora o request da Mutation:

mutation($customer: customerInput!, $customerId: ID!){
  updateCustomer(customer: $customer, customerId: $customerId){
    id,
    name,
    identificationNumber,
    email
  }
}

Mutação – Delete

Alterei novamente a classe AppMutation agora inserindo o “Field” com a operação de exclusão:

Field<StringGraphType>(
  "deleteCustomer",
  arguments: new QueryArguments(new QueryArgument<NonNullGraphType<IdGraphType>> { Name = "customerId" }),
  resolve: context =>
  {
    var customerId = context.GetArgument<Guid>("customerId");
    var customer = repository.GetById(customerId, false).Result; 
    if (customer == null)
    {
      context.Errors.Add(new ExecutionError("Cliente não encontrado na base de dados com este id."));
      return null;
    }
    repository.Delete(customer);
    return $"O Cliente com o id: {customerId} foi excluido da base de dados com sucesso.";
  }
);

Vamos tentar deletar um cliente que não existe passando um id incorreto:

Tentando deletar um cliente que não existe na base de dados.

No exemplo acima tentei deletar um cliente que não existe, e recebi corretamente a mensagem de cliente não encontrado, bem legal isso porque mostra uma maneira de devolver ao “client” mensagens de erros ou de negócios de forma customizada.

Agora vamos realmente deletar o cliente:

Deletando um cliente com sucesso.

Próximo artigo

No próximos artigo sobre GraphQL vamos falar de subscriptions e como consumir uma API GraphQL a partir de aplicativos .NET.

Vamos também ver sobre o “Hot Chocolate” uma outra biblioteca mais recente para trabalhar com a tecnologia juntamente com o .NET.

O que você faz com seu conhecimento? O meu eu tento escrever e distribuir pois acredito na citação abaixo:

“Feliz aquele que transfere o que sabe e aprende o que ensina

Cora Coralina

Por enquanto é isso, como sempre se puder deixar a opinião sobre o artigo, ajuda a melhorar e dar continuidade no trabalho!

Abraço e até a próxima!

Leave a Reply

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