Before we begin
Before we start to talk about our topics, let's take a minute to understand how this will work.
All articles will be divided into three parts:
- What are we trying to solve? - I'll give you a bit of context on what sort of problem that particular topic is trying to solve;
- The Solution: topic name - I'll talk about the topic and how it'll solve those problems; and
- Show Me the Code - I'll go through a simple implementation of that topic and point you to some documentations, should you choose to dive deeper.
Table of Contents
Last time we discussed what are microservices, but now it's time to apply some of its patterns. Today we'll learn about API Gateways!
What are we trying to solve?
Imagine this: you developed an online store that uses microservices. Now, you have a service that returns basic information about your products, another for product availability, another for reviews of products, and so on...
Your front-end wants to access all this information, but it must know ALL of the services addresses. For just a few services, it shouldn't be too hard, but imagine a scenario that your back-end has dozens or maybe hundreds of services. This would be a nightmare!
There's also a few more reasons as to why gateways are important:
- The number of instances and their locations might change dynamically. The clients won't know the new address every time a new instance is started;
- Instances partitioning might change (Z-Axis scaling) and it should be invisible to your clients;
- Services might use a diverse set of protocols, and some of them might not be 'web friendly'.
So, our problem is: How clients of a microservices architecture can access individual services in a simple way? By using API Gateways!
The solution: API Gateways
Gateways act as a Single Point of Entry to you application. All requests will go through the API Gateway and will be routed accordingly.
Instead of having a single API that fits all your clients' needs, your Gateway can expose a different API to each type of client. Better yet, you can have multiple API Gateways, one for each type of client! That's a variation of the pattern called Back-Ends for Front-Ends.
As we'll see in the next article, the Gateway will also have dynamically access to all instances and their address once we implement our Service Registry, but let's not get ahead of ourselves.
Benefits
Let's list the benefits of using an API Gateway:
- The client doesn't need to know how the application is partitioned between the services;
- The client doesn't need to know about the location (host+port) of the instances of the services;
- Provides the best API for each type of client;
- A single request to an API Gateway can retrieve data from multiple services;
- Simplifies the client by moving the logic of calling multiple services to the Gateway; and
- Translates a web protocol to any internal protocols that might be used.
Drawbacks
There are also a couple of drawbacks:
- Increases the complexity, since the Gateway becomes another application that must be developed, deployed and maintained; and
- Increases the response time, as now all requests must make a new hop through the Gateway.
Show Me the Code
Now that we know what an API Gateway is, what it does, its benefits and drawbacks, let's implement a simple Gateway and see how it works.
Start by creating two projects: one for the API Gateway and another for you Web API. Your Web API can be anything, right? If you need an idea just for this tutorial, you can head over to my Github repository. There you'll also have access to a working example of this entire article series.
Ok, now that you created you Web API, it's time to work on your API Gateway. Start by adding the Ocelot package to your Gateway project:
dotnet add package Ocelot
After the installation is complete, create a new JSON file on the project's root called 'ocelot.json'. Next, add the following lines to it:
{
"Routes": [
"DownstreamPathTemplate": "/api/v1/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": "YOUR-LOCAL-PORT"
}
],
"UpstreamPathTemplate": "/api/gateway/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "PATCH", "DELETE" ]
],
"GlobalConfiguration": {}
}
Let's discuss the meaning of each line. Your Gateway, as said before, acts as a router for every request that comes through it. With that in mind, the "Routes" property is where we'll define every routing of our application.
The properties "DownstreamPathTemplate", "DownstreamScheme" and "DownstreamHostAndPorts" define the format of the service routes, the used protocol and the base address respectively. Ocelot also uses some placeholders, e.g. "{everything}", to make it simple to define which routes will be available for each routing option.
The properties "UpstreamPathTemplate" and "UpstreamHttpMethod" define the format of the address that will be available to the external world, and which HTTP methods your route will accept.
So, with this JSON file, everytime someone tries to make a request to "https://localhost:gateway_port/api/gateway/some-resource", Ocelot will route the request to "https://localhost:web_api_port/api/v1/some-resource". Cool, right?
But we're not done yet. We need to configure our Gateway project to read the JSON file and use it to route requests. So, open your "Program.cs" file and edit the "CreateHostBuilder" method:
// Program.cs
public static IWebHostBuilder CreateHostBuilder(
string[] args) => WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(
(host, config) =>
{
config.AddJsonFile("ocelot.json");
}
)
.UseStartup<Startup>();
The line "config.AddJsonFile("ocelot.json")" loads our Ocelot JSON Configuration to our Gateway. We're almost done! We just need to add Ocelot to our services. To do this, we'll edit our "Startup.cs" file:
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddOcelot();
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseOcelot().Wait();
// ...
}
Now, we're done! You can start your Web API and your API Gateway and check the results!
I'll wait for you on our next topic: Service Registry.
Bibliography
- Microservices Patterns: With examples in Java - Chris Richardson
- API gateway pattern - https://microservices.io/patterns/apigateway.html Ocelot Documentation - https://ocelot.readthedocs.io/en/latest/index.html
Top comments (1)
Great article
Personally I find open source API Gateway solutions very easy to use.
Currently using Apache APISIX - You can check it out - apisix.apache.org/docs/apisix/gett...