Ocelot: Awesome API Gateway

Ocelot: Awesome API Gateway

The client I'm currently working is quite strict about what is going to be exposed externally, so basically no database will have external access directly nor any internal services. So because of that, we had to add a gateway layer on top of all their internal services.

I've worked on several clients with similar situation and I've seen some very nasty implementations to make it work. In some cases, they would even have every single endpoint replicated in both the gateway and the internal service.

Since I was starting this project from scratch and I had full autonomy to choose the tool, I refused to make the same mistake. It would be great to use Azure Functions Proxies for that, but unfortunately it wasn't one of the available choices.

With a bit of research I found this awesome package for .net core called Ocelot which is basically a gateway with very simple configuration required.

In this post, I'm going to show you how to get started with Ocelot.

The source code covered in this post is here

  1. Create a .net Core 2.0 application
  2. Import the Ocelot package
  3. Add a configuration.json file. This file is the mapping for your gateway.
{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/",
      "DownstreamScheme": "http",
      "DownstreamPort": 80,
      "DownstreamHost": "servicea",
      "UpstreamPathTemplate": "/a/",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    }
  ],
  "GlobalConfiguration": {}
}
  1. Update program.cs. Mine is looking like this.
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace Gateway
{
    public class Program
    {
        public static void Main(string[] args)
        {

            IWebHostBuilder builder = new WebHostBuilder();

            builder.ConfigureServices(s => {
                s.AddSingleton(builder);
            });

            builder.UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseStartup<Startup>();

            var host = builder.Build();

            host.Run();
        }
    }
}
  1. Update startup.cs.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Ocelot.DependencyInjection;
using CacheManager.Core;
using Ocelot.Middleware;
using Microsoft.Extensions.Logging;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;

namespace Gateway
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddJsonFile("configuration.json")
            .AddEnvironmentVariables();

            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddOcelot(Configuration)
                    .AddCacheManager(x => {
                        x.WithMicrosoftLogging(log =>
                        {
                            log.AddConsole(LogLevel.Debug);
                        })
                        .WithDictionaryHandle();
                    });
        }
        
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            app.UseOcelot().Wait();
        }
    }
}

And you're good to go.

If you now access your gateway through http://localhost/a/ for example, you're going to get whatever comes from http://servicea/.

In the sample I posted on my GitHub repository, you'll find two services and the gateway configure to redirect request to them.

Hope it helps.

Cheers