Ocelot Api Gateway

Uno de los desafíos al trabajar con mico-servicios es como hacer que se comuniquen entre ellos sin acoplarlos. Por esta razón, seguramente necesitarás un API Gateway para poder lograrlo exitosamente.

Hay varios en el mercado y de gran variedad. Tenemos algunos proyectos open-source y algunos propuestos por las nubes. 

En caso de los oO-promise tenemos:

  • Ocelot, que es el que veremos, es un proyecto de código abierto realizado en .Net Core. 
  • Kong, que se encuentra construido a base Nginx.
  • Express API Gateway, se encuentra construida sobre Express JS

En el caso de nube tenemos:

  • Azure API Management, Microsoft.
  • AWS Api Gateway, Amazon Web Service.
  • APigee, Google Cloud.

Como comentamos, vamos a estar viendo Ocelot y como me gusta el open source usaremos un entorno linux con Visual Studio Code.

¿Por qué necesitamos API Gateway?

El objetivo principal es facilitarnos las cosas. Si estamos trabajando en un arquitectura de micro-servicios tenemos varias estrategias diferentes, podemos exponer cada api por separado para consumidores individuales, o presentar un API unificada a través de un API Gateway por medio de alguna plataforma.

Vamos a ver un ejemplo. Nuestro ejemplo se basará en un API de comercio electrónico. Seguramente tendremos varias API del eCommerce como por ejemplo: catálogo de productos, servicios de envío, servicio de impuestos, servicio de pedidos, servicio de inventario, servicio de correo electrónico, servicios de usuarios, etc.

Para nuestro ejemplo solamente crearemos 2 API, la de pedidos y la de catálogo de productos. Con estas 2 será suficiente para ejemplificar la idea principal del API Gateway y el uso de Ocelot.

Nuestra api de catálogo la tendremos configurada en el puerto 5001, la API de órdenes lo haremos en el puerto 5002 y nuestro API Gateway en el 5000. Vamos a crear nuestra estructura en Visual Studio Code.

Lo primero que haremos será crear un carpeta desde la consola donde tendremos nuestros archivos. La llamaré OcelotSample, pero ustedes pueden llamarla como gusten. Luego, también por la línea de comando con el comando de dotnet creamos un archivo de solución.

Por la línea de comando vamos a crear con el archivo de solución. Ahora abrimos el Visual Studio Code en esta carpeta y ejecutamos el siguiente comando.

dotnet new sln

Tengo instalado un plugin muy útil que se llama Solution Explorer, este nos dejara crear proyectos sin necesidad de la consola, como veremos en la imagen en la imagen. Crearemos 3 proyectos CatalogApi, OrderApi y ApiGateway. 

Bien, tenemos listos los proyectos en las carpetas. No debemos asegurar que los puertos donde tiene que correr sean los adecuados. Para esto vamos la carpeta properties de cada uno y abrimos el archivo launchSetting.json. Buscamos applicationUrl y le cambiamos el puerto a cada uno.

"ApiGateway": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "api/values",
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }

Vamos a nuestro proyecto de ApiCatalog. Creamos un controlador que contendrá un método GetProductos. Este método devolverá una colección de Productos. Nuestra clase producto será sencilla como vemos en el código siguiente:

namespace CatalogApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CatalogController : ControllerBase
    {
        // GET api/values
        [HttpGet("GetProducts")]
        public ActionResult<IList<Product>> GetProducts()
        {
            var result = new List<Product>();
            result.Add(new Product{ ProductId = 1, Description = "Product 1", Price = 10.20M });
            result.Add(new Product{ ProductId = 2, Description = "Product 2", Price = .30M });
            result.Add(new Product{ ProductId = 3, Description = "Product 3", Price = 1.55M });

            return result;
        }

    }

    public class Product{
        public int ProductId { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
    }
}

En nuestra OrdersApi, tendremos 2 métodos, el primero será AddOrder y GetOrderByCustomers. Los utilizaran la clase Order, uno como parámetro de entrada otro como parámetro de devolución como una lista del mismo.

namespace OrderApi.Controllers
{
    [Route("api/Order")]
    [ApiController]
    public class OrderController : ControllerBase
    {        
        [HttpGet("GetOrderByCustomerId/{id}")]
        public ActionResult<List<Order>> GetOrderByCustomerId(int id)
        {
            return ListOrder().Where(p => p.CustomerId == id).ToList();            
        }
        [HttpPost("AddOrder")]
        public ActionResult<List<Order>> AddOrder([FromBody] Order order)
        {            
            var result = ListOrder();
            result.Add(order);
            return result.ToList();
        }
        private IList<Order> ListOrder(){

            var result = new List<Order>();
            result.Add(new Order(){ OrderId = 1, CustomerId = 1, CustomerName = "Customer 1"});
            result.Add(new Order(){ OrderId = 2, CustomerId = 2, CustomerName = "Customer 2"});
            result.Add(new Order(){ OrderId = 3, CustomerId = 3, CustomerName = "Customer 3"});

            return result;
        }

    }

    public class Order{
        public int OrderId { get; set; }
        public int CustomerId { get; set; }
        public string CustomerName { get; set; }
    }
}

Agregar API Gateway

Iremos a nuestro proyecto en ApiGateway. Al igual que en los otros proyectos, eliminaremos el ValuesController que no nos será útil.

Ahora en nuestro proyecto agregaremos el componente Ocelot desde los paguetes Nuget Lo haremos por la línea de comando que se encuentra integrada en Visual Studio Code.

dotnet "add" "/home/fernando/OcelotSample/ApiGateway/ApiGateway.csproj" "package" "Ocelot"oller

Lo siguiente es agregar el archivo ocelot.json que será el que contendrá las direcciones y re-direcciones a los servicios. Por el momento, será lo agregar un archivo json con ese nombre.

Siguiente paso, debemos agregar el archivo de configuración al hoster para que esté disponible para el servicio:

public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((host, config) => {
                    config.AddJsonFile("ocelot.json");
                }).UseStartup<Startup>();
    }

Por último, debemos configurar nuestro servicio de Ocelot en el StartUp como vemos en el siguiente ejemplo de código:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddOcelot(Configuration);
        }
public async Task ConfigureAsync(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();

            await app.UseOcelot();
        }

Archivo de configuración de Ocelot

Veamos la estructura del archivo:

{
    "ReRoutes":[
        {
            "DownstreamPathTemplate": "/api/catalog/{catchAll}",
            "DownstreamSCheme": "http",
            "DownstreamHostAndPorts":[
                {
                    "Host": "localhost",
                    "Port": 5002
                }
            ],
            "UpstreamPathTemplate": "/catalog-api/{catchAll}"
        },
        {
            "DownstreamPathTemplate": "/api/orders/{catchAll}",
            "DownstreamSCheme": "http",
            "DownstreamHostAndPorts":[
                {
                    "Host": "localhost",
                    "Port": 5001
                }
            ],
            "UpstreamPathTemplate": "/orders-api/{catchAll}"
        }
    ],
    "GlobalConfiguration":{
        "BaseUrl": "https://localhost:5000"
    }
}

Lo más importante de nuestro archivo de configuración es, Globalconfiguration. Nos permite definir la url base donde Ocelot estará escuchando para recepcionar las solicitudes. En nuestra aplicación, el puerto 5000.

La sección ReRouters es un objetivo del tipo matriz. No permite configurar las redirecciones que necesitemos. Downstream representa las rutas de los microservicios. UpStream representa como el usuario debe acceder al microservicio por medio del API Gateway.

Tenemos algunos comodines interesantes, por ejemplo, {catchAll} que capturara todo el tráfico para esa API y lo redireccionará como corresponde.

Ahora hagamos una pruebas con postman para ver los resultados:

Conclusiones

Si estamos trabajando con microservicios, es natural que necesiten en algún momento comunicarse entre ellos. Un buen camino para poder hacerlo es usar un API Gateway. Con esto nos liberaremos del acoplamiento o de consumir microservicios directamente.

0 0 votos
Valora la Publicación
Suscribirse
Notificación de
guest
0 Comentarios
Feedback en línea
Ver todos los Comentarios

Comentarios Recientes

0
Nos encantaría conocer tu opinión: ¡comenta!x
Ir a la barra de herramientas