ASP.NET Core - Criando uma API Gateway com Ocelot - I


Neste artigo veremos como criar uma API Gateway usando o Ocelot na ASP .NET Core.

Como sempre, vamos iniciar com uma definição básica sobre os conceitos que iremos abordar.

O que é uma API ?

Uma API - Application Programming Interface - é  um conjunto de normas, padrões e protocolos que fazem parte de uma interface que possibilita a comunicação entre plataformas permitindo a integração de sistemas.

O objetivo de uma API é atuar de forma transparente atuando no backend de forma a disponibilizar recursos de uma aplicação que serão usados por outra aplicação que para acessar os serviços vai seguir regras específicas.

O que é um API Gateway ?

Uma API Gateway é uma API/serviço que fica entre a API e o Cliente, sendo o ponto de entrada único para requisições para a API e microsserviços de backend definidos. Elas atuam como proxies entre o provedor da API e o consumidor da API.

Como esta situado na frente das APIs, uma API Gateway atua como protetor, reforçando a segurança e garantindo escalabilidade e alta disponibilidade. Assim, a API Gateway recebe todas as solicitações dos clientes para a API,  determina quais serviços são necessários e os combina em uma experiência unificada e contínua para o usuário.

O que são microsserviços ?

Os Microsserviços podem ser entendidos como um modelo arquitetural de aplicações distribuídas onde cada aplicação tem uma responsabilidade exclusiva, um escopo limitado de atuação e um ciclo de vida próprio.

Assim os microsserviços são uma abordagem de arquitetura para a criação de aplicações que decompõe a aplicação em funções básicas onde cada função é denominada um serviço e pode ser criada e implantada de maneira independente. Isso significa que cada serviço individual pode funcionar ou falhar sem comprometer os demais.

API Gateway e microsserviços

Juntando os dois conceitos temos que uma API Gateway funciona como uma porta de entrada para o clientes dos microsserviços do sistema e ao invés de chamar os microsserviços diretamente os clientes chamam a API Gateway que redireciona a requisição para o microsserviço que após o processamento retorna o resultado para a API Gateway que retorna para o cliente.

Portanto, ter um nível intermediário ou uma API Gateway pode ser conveniente para aplicativos baseados em microsserviço. Se você não usar uma API Gateway, as aplicações cliente terão que enviar as solicitações diretamente aos microsserviços e isso levanta problemas, como:

Apresentando o Ocelot

O Ocelot é uma API Gateway para a plataforma .NET direcionada para quem trabalha com uma arquitetura orientada a microsserviços.

A principal funcionalidade do Ocelot é pegar as requisições HTTP de entrada e encaminhá-las para um serviço downstream usado pelos projetos de microsserviços.  Ele é um Gateway de API leve, rápido e escalonável e fornece roteamento e autenticação sendo recomendado para abordagens mais simples.

Para saber mais sobre o Ocelot consulta a página oficial em https://ocelot.readthedocs.io/

A seguir temos uma relação dos principais recursos do Ocelot:

Ele esta disponível via pacote Nuget : Ocelot  atualmente na versão 17.0.0 (NET 5)

Package Manager  - Install-Package Ocelot -Version 17.0.0
NET CLI - dotnet add package Ocelot --version 17.0.0

Um dos principais motivos para escolher o Ocelot para  o seu projeto (desde que ele não seja um projeto muito grande e complexo) é porque ele é um gateway de API leve para o .NET Core que pode ser implantado no mesmo ambiente de implantação de aplicativos em que você está implantando seus microsserviços/contêineres, como um host do Docker, kubernetes, etc.

A seguir veremos um exemplo de utilização da biblioteca Ocelot na ASP .NET Core.

Criando uma solução com 3 projetos no VS 2019 Community

Para mostrar como usar o Ocelot em uma aplicação ASP .NET Core vamos criar uma solução no VS 2019 Community a seguir criar 3 projetos:

Vamos focar apenas no projeto Gateway mostrando como criar e configurar o projeto usando o Ocelot.   

Abra o VS 2019 Community e clique em New Project selecionando o template Blank Solution:

Informe o nome Cafetaria e clique em Create.

A seguir no menu File clique em Add-> New Project e escolha o template

Selecione o template ASP .NET Core Web API e clique em Next;

Informe o nome Cafetaria.Catalogo e clique em Next;

A seguir selecione o Target Framework, Authentication Type e demais configurações conforme mostrada na figura:

Repita o procedimento acima e crie o projeto para Cafetaria.Cliente e para Cafetaria.Gateway.

Ao final teremos na Solution Explorer a solução e os projetos conforme a figura a seguir:

Configurando o Ocelot no projeto Gateway

Vamos focar no projeto Gateway e realizar a implementação do Ocelot.

No projeto Cafetaria.Gateway podemos remover a pasta Controllers e as dependências deste controlador.

No menu Tools clique em Manage Nuget Packages for Solution e a seguir na guia Browse e informe o nome Ocelot selecionando a última versão estável e instalando-a no projeto Cafetaria.Gateway:

Agora vamos configurar o Ocelot registrando o serviço no contêiner IoC.

Para isso abra o arquivo Startup e no método ConfigureServices inclua a linha de código que registra o serviço do Ocelot:

public void ConfigureServices(IServiceCollection services)
 {
            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Cafetaria.Gateway", Version = "v1" });
            });
            services.AddOcelot(Configuration);
 }

A seguir vamos incluir o middleware do Ocelot no pipeline incluindo o código a seguir no método Configure do arquivo Startup:

public async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Cafetaria.Gateway v1"));
            }
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
            await app.UseOcelot();
}

Criando o arquivo de configuração ocelot.json

Agora vamos criar o arquivo de configuração ocelot.json na raiz do projeto.

Este arquivo vai conter a configuração para o Ocelot tratar as requisições e redirecioná-las para os microsserviços, no nosso exemplo, as APIs Cliente e Catalogo.

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/catalogo",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 44320
        }
      ],
      "UpstreamPathTemplate": "/gateway/catalogo",
      "UpstreamHttpMethod": [ "Get" ]
    },
    {
      "DownstreamPathTemplate": "/api/cliente",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 44305
        }
      ],
      "UpstreamPathTemplate": "/gateway/cliente",
      "RateLimitOptions": {
        "ClientWhitelist": [],
        "EnableRateLimiting": true,
        "Period": "1s",
        "PeriodTimespan": 1,
        "Limit": 1
      }
    },
    {
      "DownstreamPathTemplate": "/api/cliente/{id}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 44305
        }
      ],
      "UpstreamPathTemplate": "/gateway/cliente/{id}",
      "UpstreamHttpMethod": [ "Get" ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://localhost:44349"
  }
}

Este arquivo  é o coração do Ocelot e contém todas as informações que ele precisa para receber as requisições dos clientes e redirecioná-las para os microsserviços.

O arquivo contém duas seções principais:

Routes - Define como funcionária o sistema de redirecionamento da API Gateway usando o Ocelot;

GlobalConfiguration - Define as configurações globais que sobrescrevem as configurações em Routes;

Para obter mais detalhes sobre a configuração consulte a documentação oficial em :  Documentação Ocelot

Agora vamos entender os atributos usados em cada seção:

1- GlobalConfiguration

BaseUrl - Indica a URL base onde a nossa API Gateway esta atendendo. Para o nosso exemplo o projeto Cafetaria.Gateway esta atendendo em https://localhost:44349

2- Routes

A seção Routes contém as definições para Upstream que definem a configuração do Gateway e as definições para Downstream que definem a configuração para os microsserviços.

Assim temos:

UpstreamPathTemplate: Define a URL ou padrão de rota que o Ocelot irá utilizar para indicar que deve ser chamado o microserviço definido nos atributos Downstream;

 

UpstreamHttpMethod: Define os métodos HTTP aceitos e roteados;
 

DownstreamPathTemplate: Define a URL que será utilizada na criação da requisição para o microsserviço;
 

DownstreamScheme: Define o schema ou o protocolo usado no request para o microsserviço;
 

DownstreamHostAndPorts: Define o Host e a porta (Port) utilizada na requisição para o microsserviço (API de destino);
 

Assim tomando como exemplo a configuração a seguir :

 

"DownstreamPathTemplate": "/api/catalogo",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 44320
        }
      ],

      "UpstreamPathTemplate": "/gateway/catalogo",
      "UpstreamHttpMethod": [ "Get" ]

    },

Temos que:

A API Gateway vai receber o request em  /gateway/catalogo para uma requisição Get;

E vai redirecionar para o Host localhost na porta 4430 no endpoint /api/catalogo  do microsserviço usando o esquema https;

Estamos usando a opção RateLimitOptions na configuração /gateway/cliente:

"UpstreamPathTemplate": "/gateway/cliente",
      "RateLimitOptions": {
        "ClientWhitelist": [],
        "EnableRateLimiting": true,
        "Period": "1s",
        "PeriodTimespan": 1,
        "Limit": 1
      }

Esta opção define uma limitação da taxa de requisições upstream para não sobrecarregar os serviços downstream.

Os atributos usados aqui são :

Temos assim o arquivo de configuração ocelot.json definido e precisamos agora carregar e permitir que o Ocelot leia este arquivo para aplicar as configurações.

Para isso vamos alterar o código do arquivo Program:

 public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((host, config) =>
            {
                config.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                  webBuilder.UseStartup<Startup>();
            });

Incluímos o código em destaque que permite carregar o ler o arquivo ocelot.json.

Agora temos tudo pronto e já podemos testar a API Gateway usando o Ocelot.

Vamos abrir o arquivo de propriedades da solução em Startup Project vamos marcar a opção - Multiple startup projects e definir start para os 3 projetos:

Assim ao executar o nosso projeto teremos os 3 projetos carregados e poderemos testar a nossa APi Gateway.

Na próxima parte do artigo vamos usar o Postman para testar o funcionamento da nossa API Gateway com Ocelot.

"Não furtareis, nem mentireis, nem usareis de falsidade cada um com o seu próximo;"
Levítico 19:11

Referências:


José Carlos Macoratti