ASP .NET Core - Usando GraphQL - I


  Neste artigo vou apresentar o GraphQL e mostrar como podemos usá-lo em uma aplicação ASP .NET Core.

O GraphQL é uma tecnologia relativamente nova desenvolvida no Facebook e aberta ao mundo em 2015. Em 2017, ela realmente decolou e deu o salto de uma tecnologia de nicho para uma das principais formas pelas quais empresas como Walmart e IBM estão começando para trabalhar com suas APIs e dados.

Segundo o graphql.org :

"GraphQL é uma linguagem de consulta para sua API e um runtime do lado do servidor para executar consultas usando um sistema de tipos que você define para seus dados. O GraphQL não está vinculado a nenhum banco de dados ou mecanismo de armazenamento específico e, em vez disso, é respaldado pelo código e pelos dados existentes."

Dessa forma o GraphQL facilita o processo de entregar ao cliente apenas o que foi requisitado pelo mesmo e na ordem em que foi solicitado.

Ele pode ser entendindo como uma abstração ao protocolo HTTP onde você usa um endpoint que usa um server GraphQL que receberá requisições do tipo POST e GET respondendo no formato JSON.

Alguns conceitos usados no ecosistema GraphQL:

Schema - Descreve a funcionalidade disponível para os clientes que se conectam a ele.

Tipos - Tudo em GraphQL é um tipo,e, um tipo pode ser entendido como uma entidade em seu banco de dados (relacional ou não relacional). Os tipos forma um schema, e, o GraphQL possui 2 tipos padrão: RootQuery e RootMutation.

Query e Mutations - O type Query serve para definir o contrato de consulta de dados e O type Mutation serve para definir o contrato de manipulação de dados

Resolver - Resolvers são funções responsáveis revolver um pedido e devolver o dado solicitado. As funções recebem três argumentos : root , argumentos e contexto.

É importante ressaltar que embora seja uma linguagem de consulta para APIs o GraphQL é diferente do REST, na verdade ele compete como o REST.

Algumas vantagens do GraphQL :

Neste artigo iremos criar uma aplicação ASP .NET Core Web API e usar bibliotecas Nuget para implementar a utilização do GraphQL em nossa API.

Vamos definir uma API para gerenciar produtos e categorias onde vamos definir as entidades Produto e Categoria.

A seguir vamos implementar o padrão repositório definindo as interfaces : IProdutoRepository e ICatgoriaRepository e suas implementações ProdutoRepository e CategoriaRepository

Recursos :

Criando o projeto no VS 2019 Community

Abra o VS 2019 Community e crie uma solução em branco via menu File-> New Project;

Selecione o template ASP .NET Core Web Application;

Informe o nome AspnetCore_GraphQL;

A seguir selecione .NET Core e ASP .NET Core 3.0 e marque o template API e configurações conforme figura abaixo:

A seguir vamos criar no projeto as seguintes pastas para melhor organizar o código que iremos implementar:

A seguir vemos a estrutura do projeto e o arquivo .csproj exibindo as configurações:

A seguir no menu Tools -> Nuget Package Manager -> Manage Nuget Packages for Solution;

Na guia Browse selecione :  microsoft.entityframeworkcore.sqlserver  e clique no botão Install;

Instalei o EF Core para acessar os dados em nosso projeto.

Podemos excluir a pasta Controllers que não iremos usar.

Definindo o modelo de domínio

Na pasta Entities vamos criar as classes Produto e Categoria :

1- Categoria

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
namespace Aspncore_GraphQL.Entities
{
    public class Categoria
    {
        public Categoria()
        {
            Produtos = new Collection<Produto>();
        }
        public int CategoriaId { get; set; }

        [Required]
        [MaxLength(80)]
        public string Nome { get; set; }

        [Required]
        [MaxLength(300)]
        public string ImagemUrl { get; set; }
        public ICollection<Produto> Produtos { get; set; }
    }
}

2- Produto

using System;
using System.ComponentModel.DataAnnotations;
namespace Aspncore_GraphQL.Entities
{
    public class Produto
    {
        public int ProdutoId { get; set; }
        [Required]
        [StringLength(80)]
        public string Nome { get; set; }
        [Required]
        [StringLength(300)]
        public string Descricao { get; set; }
        [Required]
        public decimal Preco { get; set; }
        [Required]
        [StringLength(300)]
        public string ImagemUrl { get; set; }
        public float Estoque { get; set; }
        public DateTime DataCadastro { get; set; }
        public Categoria Categoria { get; set; }
        public int CategoriaId { get; set; }
    }
}

Nosso modelo de domínio onde definimos um relacionamento um para mitos entre Categoria e Produtos.

Definindo a classe de contexto

Como eu vou usar o EF Core tenho que criar uma classe de contexto que herda de DbContext onde vou definir o provedor para o banco de dados e a string de conexão com o banco de dados SQL Server que iremos acessar.

Na pasta Context crie uma classe chamada AppDbContext com o código abaixo:

using Microsoft.EntityFrameworkCore;
namespace Aspncore_GraphQL.Entities.Context
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options)
            : base(options)
        { }
        public AppDbContext()
        { }
        public DbSet<Categoria> Categorias { get; set; }
        public DbSet<Produto> Produtos { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                IConfigurationRoot configuration = new ConfigurationBuilder()
                   .SetBasePath(Directory.GetCurrentDirectory())
                   .AddJsonFile("appsettings.json")
                   .Build();

                var connectionString = configuration.
                       GetConnectionString("DefaultConnection");
                optionsBuilder.UseSqlServer(connectionString);
            }
        }
    }
}

Nesta classe definimos o seguinte:

  1. O mapeamento das entidade Produto e Categoria para as respectivas tabelas via DbSet;
  2. O provedor do banco de dados SqlServer;
  3. A string de conexão usada para acessar os dados;

Configuando o contexto na classe Startup

No método ConfigureServices vamos registrar o contexto com um serviço:

using Aspncore_GraphQL.Entities.Context;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
...
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>();
            services.AddControllers()
                .AddNewtonsoftJson();
        }
...

A seguir vamos definir a string de conexão no arquivo appsettings.json :

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=Macoratti;Initial Catalog=CatalogoDB;Integrated Security=True"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Migrations

Para aplicar o migrations abra uma janela do Package Manager Console e digite os comandos:

1- add-Migrations Inicial
2- update-database

Apos aplicar o  migrations abrindo o SQL Server Management Studio veremos o banco de dados e as tabelas criadas com o relacionamento definido conforme figura:

Implementando o Repositório

Começaremos desenvolvendo nosso Repositório definindo na pasta Contracts as interfaces ICategoriaRepository e IProdutoRepository.

As interfaces definidas serão bem simples, assim não teremos uma implementação completa:

- ICategoryRepository

using Aspncore_GraphQL.Entities;
using System.Collections.Generic;
namespace Aspncore_GraphQL.Contracts
{
    public interface ICategoriaRepository
    {
        IEnumerable<Categoria> GetAll();
    }
}

- IProdutoRepository

namespace Aspncore_GraphQL.Contracts
{
    public interface IProdutoRepository
    {
    }
}

Já temos o contrato definido e agora vamos definir as classes que irão implementar os contratos.

Na pasta Repository vamos criar as classes CategoriaRepository e ProdutoRepository que irão implementar as nossas interfaces.

- CategoriaRepository

using Aspncore_GraphQL.Contracts;
using Aspncore_GraphQL.Entities;
using Aspncore_GraphQL.Entities.Context;
using System.Collections.Generic;
using System.Linq;
namespace Aspncore_GraphQL.Repository
{
    public class CategoriaRepository : ICategoriaRepository
    {
        private readonly AppDbContext _context;
        public CategoriaRepository(AppDbContext context)
        {
            _context = context;
        }
        public IEnumerable<Categoria> GetAll() => _context.Categorias.ToList();
    }
}

- ProdutoRepository

using Aspncore_GraphQL.Contracts;
using Aspncore_GraphQL.Entities.Context;
namespace Aspncore_GraphQL.Repository
{
    public class ProdutoRepository : IProdutoRepository
    {
        private readonly AppDbContext _context;
        public ProdutoRepository(AppDbContext context)
        {
            _context = context;
        }
    }
}

Agora vamos registrar o nosso repositório como um serviço no arquivo Startup:

using Aspncore_GraphQL.Contracts;
using Aspncore_GraphQL.Entities.Context;
using Aspncore_GraphQL.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
        ...
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>();
            services.AddScoped<ICategoriaRepository, CategoriaRepository>();
            services.AddScoped<IProdutoRepository, ProdutoRepository>();
            services.AddControllers()
                .AddNewtonsoftJson();
        }
        ...

No tempo de vida AddScoped permite criar um objeto do serviço a cada requisição, ou seja, cada requisição obtém uma nova instância do serviço. Os objetos são os mesmos em uma requisição mas diferentes entre requisições diferentes.

Concluímos assim a criação e a configuração da aplicação ASP .NET Core a seguir vamos implementar o GraphQL em nossa aplicação.

"Bom é louvar ao SENHOR, e cantar louvores ao teu nome, ó Altíssimo;
Para de manhã anunciar a tua benignidade, e todas as noites a tua fidelidade;"
Salmos 92:1,2

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

Referências:


José Carlos Macoratti