![]() |
Neste post veremos como implementar o GraphQL em uma aplicação ASP .NET Core usando o HotChocolate. |
Continuando a primeira parte do artigo vamos implementar agora o contrato de
consulta, manipulação e os ouvintes dos eventos no GraphQL.
Podemos fazer uma relação entre os conceitos usados em uma API REST com os do
GraphQL.
Em uma API REST, usamos GET para buscar dados e usamos POST, PUT DELETE para modificar o estado dos dados. Assim podemos dizer que :
No GraphQL Query é o mesmo que o GET na API REST;
O POST, PUT, DELETE da API REST é o mesmo que Mutation;
No GraphQL, também existe a Subscription que é usada para configurar ouvintes de eventos;
Criando os objetos GraphQL
Vamos criar no projeto a pasta DataAccessGraphQL e vamos inciar criando a classe Query:
1- Query
using GraphQLNet.Models;
using GraphQLNet.Repositories;
using HotChocolate.Subscriptions;
namespace GraphQLNet.DataAccessGraphQL;
public class Query
{
public List<Funcionario> TodosFuncionarios([Service]
IFuncionarioRepository funcionarioRepository) =>
funcionarioRepository.GetFuncionarios();
public List<Funcionario> TodosFuncionariosComDepartamentos([Service]
IFuncionarioRepository funcionarioRepository) =>
funcionarioRepository.GetFuncionariosComDepartamento();
public async Task<Funcionario> FuncionarioPeloId([Service]
IFuncionarioRepository funcionarioRepository,
[Service] ITopicEventSender eventSender, int id)
{
Funcionario funcionarioRetornado = funcionarioRepository.GetFuncionarioPorId(id);
await eventSender.SendAsync("FuncionarioRetornado", funcionarioRetornado);
return funcionarioRetornado;
}
public List<Departamento> TodosDepartamentos([Service]
IDepartamentoRepository departamentoRepository) =>
departamentoRepository.GetListaDepartamentos();
public List<Departamento> DepartamentosComFuncionarios([Service]
IDepartamentoRepository departamentoRepository) =>
departamentoRepository.GetDepartamentosComFuncionarios();
}
|
Nesta classe temos os seguintes métodos:
TodosFuncionarios() que retorna todos os Funcionarios cadastrados;
TodosFuncionariosComDepartamentos() que retorna os funcionários e seus departamentos;
FuncionarioPeloId(int id) retorna um funcionário pelo seu Id;
TodosDepartamentos() retorna todos os departamentos;
DepartamentosComFuncionarios() retorna os departamentos e seus funcionários;
Observe que injetamos instâncias dos repositórios IFuncionarioRepository e IDepartamentoRepository para poder usar os métodos que irão obter os dados.
O método que retorna o funcionário pelo id usa o parâmetro ITopicEventSender eventSender que é usado para criar uma assinatura com o Tópico "FuncionarioRetornado". Sempre que esse método é chamado, o evento é enviado usando eventSender.SendAsync() e qualquer método que se inscreva nesse evento receberá os dados.
2- Mutation
A seguir vamos criar nesta pasta a classe Mutation que vão conter todas as Mutations ou manipulação dos dados:
using GraphQLNet.Models;
using GraphQLNet.Repositories;
using HotChocolate.Subscriptions;
namespace GraphQLNet.DataAccessGraphQL;
public class Mutation
{
public async Task<Departamento> CriarDepartamento([Service]
IDepartamentoRepository departamentoRepository,
[Service] ITopicEventSender eventSender, string nomeDepartamento)
{
var novoDepartamento = new Departamento
{
Nome = nomeDepartamento
};
var departamentoCriado = await departamentoRepository.CriarDepartamento(novoDepartamento);
await eventSender.SendAsync("DepartamentoCriado", departamentoCriado);
return departamentoCriado;
}
public async Task<Funcionario> CriaFuncionarioComDepartamentoId([Service]
IFuncionarioRepository funcionarioRepository,
string nome, int idade, string email, int departamentoId)
{
Funcionario novoFuncionario = new Funcionario
{
Nome = nome,
Idade = idade,
Email = email,
DepartamentoId = departamentoId
};
var funcionarioCriado = await funcionarioRepository.CriarFuncionario(novoFuncionario);
return funcionarioCriado;
}
public async Task<Funcionario> CriaFuncionarioComDepartamento([Service]
IFuncionarioRepository funcionarioRepository,
string nome, int idade, string email, string departamentoNome)
{
Funcionario novoFuncionario = new Funcionario
{
Nome = nome,
Idade = idade,
Email = email,
Departamento = new Departamento { Nome = departamentoNome }
};
var funcinarioCriado = await funcionarioRepository.CriarFuncionario(novoFuncionario);
return funcinarioCriado;
}
}
|
Nesta classe criamos :
O método CriarDepartamento()
onde o parâmetro
nomeDepartamento
será fornecido pelo
usuário. O parâmetro ITopicEventSender eventSender é usado para criar uma
assinatura com o Tópico "DepartamentoCriado".
A seguir criamos o método
CriaFuncionarioComDepartamentoId()
que pode ser usado para criar um novo Funcionario passando um DepartomentoId
existente, ou seja, criar um Funcionario com um departamento existente. Os
parâmetros nome: string, idade: int, email: string e departomentoId: int
serão fornecidos pelo usuário. Observe que configuramos o DepartamentoId para o
departomentoId passado pelo usuário.
Depois criamos o método
CriaFuncionarioComDepartamento()
que é usado para criar um novo funcionário. No processo de criação do
Funcionário, um novo Departamento é criado e a propriedade DepartamentoId deste
Funcionário é definida automaticamente para o DepartamentoId do
Departamento recém-criado.
2- Subscription
Para concluir vamos criar nesta pasta a classe Subscription.
As subscriptions ou assinaturas são usadas para configurar ouvintes de eventos, por exemplo. podemos configurar um ouvinte de eventos que responde quando criamos um novo Departamento ou Consultamos o banco de dados para um Funcionário:
using GraphQLNet.Models;
using HotChocolate.Execution;
using HotChocolate.Subscriptions;
namespace GraphQLNet.DataAccessGraphQL;
public class Subscription
{
[SubscribeAndResolve]
public async ValueTask<ISourceStream<Departamento>> OnDepartamentoCreate([Service]
ITopicEventReceiver eventReceiver,CancellationToken cancellationToken)
{
return await eventReceiver.SubscribeAsync<string, Departamento>("DepartamentoCriado", cancellationToken);
}
[SubscribeAndResolve]
public async ValueTask<ISourceStream<Funcionario>> OnFuncionarioGet([Service]
ITopicEventReceiver eventReceiver,CancellationToken cancellationToken)
{
return await eventReceiver.SubscribeAsync<string, Funcionario>("FuncionarioRetornado", cancellationToken);
}
}
|
Criamos os eventos
OnDepartamentoCreate
que define um assinante do tópico : "DepartamentoCriado",
e evento OnFuncionarioGet que define um assinante
do tópico
"FuncionarioRetornado".
Com isso concluímos a criação dos recursos que iremos usar no GraphQL.
Configurando o GraphQL
Precisamos agora configurar o GraphQL para poder usá-lo. Para isso vamos incluir no arquivo Program as linhas de código destacadas abaixo:
using GraphQLNet.DataAccessGraphQL;
using GraphQLNet.DataContext;
using GraphQLNet.Repositories;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddInMemorySubscriptions();
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddSubscriptionType<Subscription>();
builder.Services.AddScoped<IFuncionarioRepository, FuncionarioRepository>();
builder.Services.AddScoped<IDepartamentoRepository, DepartamentoRepository>();
string AllowedOrigin = "allowedOrigin";
builder.Services.AddCors(option =>
{
option.AddPolicy("AllowedOrigin",
builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()
);
});
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseCors(AllowedOrigin);
app.UseWebSockets();
app.UseRouting()
.UseEndpoints(endpoints =>
{
endpoints.MapGraphQL();
});
app.Run();
|
Vamos entender o código incluído:
- Registramos o serviço par ao armazenamento na memória do aplicativo usado pelas subscriptions do GraphQL;
- Adicionamos o serviço para o GraphQL, Query, Mutation e Subscription onde AddQueryType(), AddMutationType() e AddSubscriptionType() recebem as classes Query, Mutation e Subscription respectivamente que foram criadas.
- Incluímos o middleware para dar suporte a comunicação com Sockets;
- Mapeamos o endpoint para usar o GraphQL;
Agora temos tudo pronto para poder usar o GraphQL em nosso
projeto ASP .NET Core.
Na próxima parte do artigo vamos realizar os testes usando os recursos das
classes Query, Mutation e Subscription
criadas.
"Miserável homem que eu sou! quem me livrará do corpo desta morte ?
Dou
graças a Deus por Jesus Cristo nosso Senhor. Assim que eu mesmo com o
entendimento sirvo à lei de Deus, mas com a carne à lei do pecado. "
Romanos 7:24,25
Referências: