Jul 27 2022 10:59 AM
The API Gateway topic could easily carry several blog posts like this one. In this section, we focus specifically on the usage of Apache APISIX API Gateway for applications developed in ASP.NET Core (Assume that you have an API that manages products) and provide an easy example of how to deploy multiple images using docker compose.
Now before going to the demo session. Let's discuss first what is API gateway?🤔
In today's microservices architecture, we usually create multiple microservices for a particular product and the client apps usually need to consume functionality from more than one microservice. And for each of these services, we will have different endpoints accessing these services from the external world it doesn't make sense to expose multiple URLs we should have a single entry point to all our services, and based on the different paths we should be doing the routing as it is shown in the below picture.
There are other numerous aspects of an API Gateway in building .NET microservices APIs and web applications. In many scenarios, authentication, security, observability, caching, and transformation are handled centrally. Without an API Gateway in place, you might typically implement these concerns for each service, because maintaining them for each service would be a very challenging task and time-consuming. At the same time, you can get the benefit of an API Gateway in reducing complexity, and delivering high performance for your APIs and it helps you to scale your microservices.
👉 To execute and customize the example project per your need shown in this post, here are the minimum requirements you need to install in your system:
:right_arrow: .NET 6 SDK
:right_arrow: Visual Studio 2022 with the Web Development, and/or .NET cross-platform development workload installed. This includes by default .NET 6 development tools. Or Visual Studio code.
:right_arrow: Docker Desktop - you need also Docker desktop installed locally to complete this tutorial. It is available for Windows or macOS. Or install the Docker ACI Integration CLI for Linux.
:white_heavy_check_mark: Clone the demo project apisix-dotnet-docker from GitHub.
:white_heavy_check_mark: Understand the structure of the project and docker-compose.yaml file.
:white_heavy_check_mark: Build a multi-container APISIX via Docker CLI.
:white_heavy_check_mark: Configure APISIX API Gateway routing for the ASP.NET API.
:white_heavy_check_mark: Enable a traffic management plugin.
For this demonstration, we’ll leverage the demo project apisix-dotnet-docker I prepared in advance. You can see the complete source code on Github.
Use git to clone the repository:
git clone 'https://github.com/Boburmirzo/apisix-dotnet-docker'
Go to root directory of apisix-dotnet-docker
cd apisix-dotnet-docker
You can open the project in your favorite code editor. I used VS Code. You’ll see the following project directory structure:
In the project folders, here is the list of main components you can take a look at:
You can also see ProductsController.cs file where there is a simple API to get all products list from the service layer. We will enable routing and Apache APISIX plugins for this endpoint in the next steps.
[Route("api/[controller]")] [ApiController] public class ProductsController : ControllerBase { private IProductsService _productsService; public ProductsController(IProductsService productsService) { _productsService = productsService; } [HttpGet] public IActionResult GetAll() { return Ok(_productsService.GetAll()); } }
Now let's have a look at a Dockerfile inside the ProductApi folder. It has just a standard Docker file structure and this file is responsible for pulling .NET6 SDK and ASP.NET6 images from docker registry, building and running the applications docker images.
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env WORKDIR /app COPY . ./ RUN dotnet restore "ProductApi.csproj" RUN dotnet publish "ProductApi.csproj" -c Release -o out FROM mcr.microsoft.com/dotnet/aspnet:6.0 ENV TZ=America/Sao_Paulo RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "ProductApi.dll"]
Docker compose file - The docker-compose.yml file defines an application with some services:
☝️You may notice all services are mapped to apisix network.
The apisix-dotnet-docker project makes use of the similar example APISIX docker compose template.
Now we can start our application by running docker compose up command from the root folder of the project:
docker compose up -d
Sample output:
[+] Running 7/7
- Network apisix-dotnet-docker_apisix Created 0.0s
- Container apisix-dotnet-docker-apisix-dashboard-1 Started 1.2s
- Container apisix-dotnet-docker-prometheus-1 Started 0.7s
- Container apisix-dotnet-docker-etcd-1 Started 0.9s
- Container apisix-dotnet-docker-grafana-1 Started 1.2s
- Container apisix-dotnet-docker-productapi-1 Started 0.7s
- Container apisix-dotnet-docker-apisix-1 Started 2.0s
The running container list you can see by running docker compose ps CLI command or using docker desktop:
NAME COMMAND SERVICE STATUS PORTS apisix-dotnet-docker-apisix-1 "sh -c '/usr/bin/api…" apisix running 0.0.0.0:9080->9080/tcp, 0.0.0.0:9091-9092->9091-9092/tcp, 0.0.0.0:9443->9443/tcp apisix-dotnet-docker-apisix-dashboard-1 "/usr/local/apisix-d…" apisix-dashboard running 0.0.0.0:9000->9000/tcp apisix-dotnet-docker-etcd-1 "/opt/bitnami/script…" etcd running 0.0.0.0:12379->2379/tcp apisix-dotnet-docker-grafana-1 "/run.sh" grafana running 0.0.0.0:3000->3000/tcp apisix-dotnet-docker-productapi-1 "dotnet ProductApi.d…" productapi running 0.0.0.0:5555->80/tcp apisix-dotnet-docker-prometheus-1 "/bin/prometheus --c…" prometheus running 0.0.0.0:9090->9090/tcp
Once the containers are running, navigate to http://localhost:5555/api/products in your web browser and you will see the following output:
When you set up Apache APISIX API Gateway for your APIs, it adds many capabilities including :downwards_button:
For more information see the documentation.
Apache APISIX is based on a couple of primitives:
We can create a Route and configure the underlying Upstream. When Apache APISIX receives a request matching the Route, it forwards it to the underlying Upstream.
Now let's start with adding a Route and Upstream for the /api/products endpoint. The following command creates a sample Route together with an upstream:
curl "http://127.0.0.1:9080/apisix/admin/routes/1" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d ' { "methods": ["GET"], "uri": "/api/products", "upstream": { "type": "roundrobin", "nodes": { "productapi:80": 1 } } }'
Once we have created the Route and upstream, we can check whether it works. Apache APISIX should forward the request to our target API /api/products.
curl http://127.0.0.1:9080/api/products -i
Urraaa👏, yes, it actually does. You can see a sample output:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: APISIX/2.13.1 [{"name":"Macbook Pro","price":1299.9},{"name":"SurfaceBook 3","price":1599.9}]
You can also add two or more routes to the API Gateway, let's say one will serve for you Product and another for Customer microservices with the URL path /api/customers.
With the help of the API Gateway, one can set automatic retries, timeouts, circuit breakers, or rate-limiting for an external upstream API or microservice. Rate limiting is a strategy for limiting network traffic. It puts a cap on how often someone can repeat an action within a specific timeframe – for instance, trying to log into an account.
The Limit count plugin :electric_plug: is one among many limiting plugins. It limits the request rate by a fixed number of requests in a given time window.
Let’s enable the limit-count plugin on the Route and Upstream. To do so, run the following command:
curl -i http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "methods": ["GET"], "uri": "/api/products", "plugins": { "limit-count": { "count": 2, "time_window": 60, "rejected_code": 403, "rejected_msg": "Requests are too frequent, please try again later.", "key_type": "var", "key": "remote_addr" } }, "upstream": { "type": "roundrobin", "nodes": { "productapi:80": 1 } } }'
The above configuration limits the number of requests to two in 60 seconds. Apache APISIX will handle the first two requests as usual, but a third request in the same period will return a 403 HTTP code:
curl http://127.0.0.1:9080/api/products -i
Sample output after calling the API 3 times within 60 sec:
HTTP/1.1 403 Forbidden Content-Type: text/plain; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: APISIX/2.13.1 {"error_msg":"Requests are too frequent, please try again later."}
Indeed, after reaching the threshold, subsequent requests are not allowed by APISIX.
We made use of Apache APISIX docker compose repo where we deployed several components in one run and we demonstrated how the API Gateway can be used to manage sample ASP.NET Core application to retrieve product data using Product microservice's API. Also, you learned how to enable limit-count plugin for the API endpoint. There are many other built-in plugins available in Apache APISIX, you can check them on Plugin Hub page. Basically, APISIX can be a lightweight middleware API Gateway regardless of which programming language, frameworks, tools, or platforms you are developing a microservice or application.
➔ Watch Video Tutorial Getting Started with Apache APISIX.
➔ Read the blog post Overview of Apache APISIX API Gateway Plugins.
➔ Read the blog post Run Apache APISIX on Microsoft Azure Container Instance.
➔ Read the blog post API Security with OIDC by using Apache APISIX and Microsoft Azure AD.
➔ Read the blog post API Observability with Apache APISIX Plugins.
Community:right_arrow_curving_down:
🙋 Join the Apache APISIX Community
:bird: Follow us on Twitter
:memo: Find us on Slack
:e_mail: Mail to us with your questions.