Criando um API Gateway com ASP.NET Core e Ocelot

Atualmente fala-se muito na criação de microsserviços, aplicações que executam uma função específica. Quando se cria um sistema baseado nesta arquitetura, teremos vários microsserviços executando funcionalidades específicas do sistema.

Como demostrado na imagem abaixo:

Assim, pode ocorrer situações onde é necessário obter informações de mais de um microsserviço, ou o sistema precisa ser consumido por vários clients. Com aplicações mobile, web, aplicações de terceiro, etc.

Nestes cenários, pode ser custoso ter que gerenciar o acesso de cada microsserviço do sistema. Cada um com as suas particularidades. É neste ponto que entra o API Gateway.

API Gateway

O API Gateway funciona como uma porta de entrada para o clients dos microsserviços do sistema. No lugar de chamar os microsserviços diretamente, os clients chamam a API Gateway, que redireciona a solicitação para o microsserviço apropriado. Quando o microsserviço retornar à solicitação, o API Gateway a retorna para o client.

Ou seja, ele funciona como uma camada intermediária entre os clients e os microsserviços. Como todas as solicitações irão passar por ele, o gateway pode modificar as solicitações recebidas e retornadas, o que nos fornece algumas vantagens:

  • Os microsserviços podem ser modificados sem se preocupar com os clients;
  • Os microsserviços podem se comunicar utilizando qualquer tipo de protocolo. O importante é o gateway implementar um protocolo que seja compreendido pelos clients;
  • O gateway pode implementar recursos que não impactam nos microsserviços, como autenticação, logging, SSL, balanceamento de carga, etc.

A imagem abaixo ilustra bem o funcionamento do API Gateway:

Ocelot

Ocelot é uma biblioteca que permite criar um API Gateway com o ASP.NET. Possuindo uma grande gama de funcionalidades, como:

  • Agregação de solicitações;
  • Roteamento;
  • Autenticação;
  • Cache;
  • Balanceamento de carga;
  • Log;
  • WebSockets;
  • Service Fabric.

Mesmo que seja voltado para aplicações .NET que estejam implementando uma arquitetura de microsserviços, o Ocelot pode ser utilizado como API Gateway de qualquer tipo de sistema que implemente esta arquitetura.

Para conhecê-lo melhor, vamos ver um exemplo prático.

Criando microsserviços de exemplo

Para exemplificar o uso do Ocelot, criarei dois microsserviços, que serão apenas aplicações ASP.NET Web API. Uma se chamará Pedido e a outra Catalogo. A única diferença dessas aplicações para a padrão criada pelo .NET é uma modificação no controller Values:

  • Pedido:
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "Item 1", "Item 2" };
}
  • Catalogo:
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "Produto 1", "Produto 2" };
}

Com isso, conseguiremos diferenciar cada uma.

Criando a API Gateway

Como dito , o Ocelot permite configurar uma aplicação ASP.NET para que se comporte como API Gateway. Assim, para criá-lo inicialmente é necessário criar uma aplicação ASP.NET.

Como a aplicação funcionará apenas como API Gateway, podemos criar uma “vazia”:

dotnet new web -n Gateway

Este é o procedimento recomendado, mas é possível definir o Ocelot em qualquer tipo de aplicação ASP.NET.

Após a criação da aplicação é necessário adicionar a referência do Ocelot:

dotnet add package Ocelot

As configurações do Ocelot devem ser definidas em um arquivo JSON. Assim, vamos alterar a classe Program para que carregue este arquivo no início da execução da aplicação:

public class Program
{
    //Código omitido

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration(ic => ic.AddJsonFile("configuration.json"))
            .UseStartup<Startup>();
}

Veremos este arquivo de configuração à frente. Antes, iremos alterar a classe Startup.

Nela iremos habilitar o serviço e o middleware do Ocelot:

public class Startup
{
    private readonly IConfiguration _configuration;

    public Startup(IConfiguration configuration)
    {
        this._configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOcelot(_configuration);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseOcelot().Wait();
    }
}

Como o arquivo de configuração do Ocelot está sendo carregado pelo sistema de configuração do ASP.NET, uma referência dele é passada para o serviço Ocelot:

services.AddOcelot(_configuration);

Já no método Configure, o middleware do Ocelot é adicionado ao pipeline de execução do ASP.NET:

app.UseOcelot().Wait();

É importante que esta sempre seja a última linha do método Configure. Pois o middleware do Ocelot é terminal. Ou seja, ele não invoca nenhum outro middleware do pipeline. Caso a solicitação realizada não seja encontrada nas configurações do Ocelot, ele gera um erro 404.

Configurando a API Gateway

O arquivo de configuração do Ocelot é composto de dois atributos:

{
    "ReRoutes": [],
    "GlobalConfiguration": {}
}

Em ReRoutes definimos como funcionará o sistema de redirecionamento da API Gateway. Já GlobalConfiguration definimos configurações globais que sobrescrevem configurações do ReRoutes.

Já no ReRoutes é possível definir uma série de funcionalidades, mas os pontos mais importantes são:

  • DownstreamPathTemplate: Define a URL que será utilizada na criação da solicitação para o microsserviço;
  • DownstreamScheme: Define o scheme utilizado na solicitação para o microsserviço;
  • DownstreamHostAndPorts: Define o Host e a porta (Port) utilizada na solicitação para o microsserviço;
  • UpstreamPathTemplate: Define a URL que o Ocelot irá utilizar para indicar que deve ser chamado o microsserviço definido nos atributos Downstream
  • UpstreamHttpMethod: Define os métodos HTTP aceitos;

Com isso em mente, podemos definir a seguinte configuração para a nossa API Gateway:

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "pedido",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/pedido/",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    },
    {
      "DownstreamPathTemplate": "/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "pedido",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/pedido/{everything}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    },
    {
      "DownstreamPathTemplate": "/",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "catalogo",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/catalogo/",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    },
    {
      "DownstreamPathTemplate": "/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "catalogo",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/catalogo/{everything}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    }
  ],
  "GlobalConfiguration": { }
}

Como os microsserviços serão executados em containers, o Ocelot consegue redirecionar as solicitações com base no nome dos containers. Assim, os hosts definidos no arquivo acima utilizam o nome dos containers.

Mas é possível definir um host “qualquer”, pelo IP, como:

"DownstreamHostAndPorts": [
  {
    "Host": "189.0.0.1",
    "Port": 80,
  }
],

Ou até pela URL:

"DownstreamHostAndPorts": [
  {
    "Host": "www.servidor.com",
    "Port": 80,
  }
],

Rodando

Como estamos lidando com microsserviços, o ideal é que eles sejam executados em containers (esta é a recomendação da Microsoft) e como isso não é o foco do artigo, aqui não explicarei a configuração dos containers, mas você pode vê-lo no repositório do projeto aqui

Ao executar as aplicações através do docker composer, conseguiremos acessar cada microsserviço através da API Gateway:

Ou mesmo diretamente (devido a configuração realizada nos containers):

Concluindo

Caso pretenda criar uma aplicação que implemente o padrão de microsserviços, a criação de uma API Gateway é quase uma tarefa obrigatória. No caso de aplicações .NET, o Ocelot facilita esta criação.

Então caso esteja interessado nesta biblioteca, recomendo a leitura da sua documentação, aqui, pois ela possui uma série de recursos que não foram abordados aqui.

Por hoje é só, até a próxima 🙂

Deixe seu comentário

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.

JUNTE-SE A MAIS DE 150.000 PROGRAMADORES