API Gateway is a standard pattern for managing and consolidating multiple APIs in the world of microservices. We use Azure API Management as a Gateway pattern implementation in Oriflame. This is a great service by Microsoft which allows us to focus on the functionality of endpoints instead of on infrastructure.
A good API is a strategic resourcefor us and our markets. Therefore, our work doesn’t end by publishing endpoints to Gateway. We need to manage multiple environments (development, testing, production…), geographical regions and different sets of endpoints (APIs). This means that multiple teams and consumers are working with our APIs in different stages of the development process.
This woldn’t be possible without a source control system(GIT) and automation in CI/CD pipelines(Azure DevOps). But API Management did not support this. Their product team recently presented a basic idea for release management in this blog post.
Oriflame has been working on this task for almost two years, and it is interesting to note that our solution is almost the same as the one presented by Microsoft. Except for one important fact: We don’t use ARM templates!
ARM templates for API Management
Azure resources can be created and distributed through ARM resource templates. These are json fileswhich can describe the whole azure resource. As such, it is a very useful tool for resource distribution which facilitates, e.g., the creation of a new instance of an existing resource in a different region. But there is no code inside the template, only a configuration necessary for creating the resource
The application code (i.e., for an app service) is usually pushed to the instance separately through a release process. But API Management doesn’t have any such code.It’s a service. Everything is only a configuration, which should be in the ARM template as well.
We tried to follow this logic at the beginning. We used this project to extract an API (set of endpoints) from an API Management instance to an ARM template. The ARM template was adjusted by a powershell script and uploaded to another resource. Basically, this is the same solution as the one Microsoft presented in the blog post. But we had alot of trouble with that:
- Updating an existing API with ARM template means that the API is not working during the release process. The reason is that the endpoints are deleted and recreated on the instance. And this is not acceptable for production.
- API Management is continually updated and developed. Our ARM templates must incorporate these changes, but they are not well documented. We spent lot of time updating our release process. And you certainly don’t want to see a broken pipeline when releasing a new build to production.
- Our APIs are well documented. Our OpenAPI definitions contain not only endpoints and their descriptions but contract schemas, examples, tags etc., and all of these must be transformed into an ARM template. But there is no OpenApi property. This process is complicated, not fully implemented in extraction tools, and is not even fully supported by the ARM template itself.
- At the end our ARM templates with all the transformed OpenAPI components became too big for Azure. The Developer-tier API Management often got stuck during upload, and we needed to manually scale it up to make it work. In the Standard tier we encountered problems with timeouts during release.
The API template is our code, not configuration
The “skeleton” of each API in API Management is the API Definition(OpenAPI specification) and the “muscles” are the policies.Together, these are called the API Template.
We realized that theAPI template is our code, analogously to the App Service having an application code. It is not a configuration and it shouldn’t be in the ARM template. It doesn’t even have the same format as ARM – polices are in XML and OpenAPI must be heavy-handedly transformed to ARM.
Therefore, we needed a different process for releasing it. Something clear, stable and transparent: Azure REST API.
1. API definition (OpenAPI specification)
Oriflame uses a dummy WebAPI project with Swagger. Our developers often use Swashbuckle Swagger for documenting their microservice APIs. They only copy headers of their action methods to this dummy project and modify the routes when required.
- No APIM instance outage (update by OpenAPI is a smooth process)
- The OpenAPI document doesn’t have to be transformed into ARM
- Multiple tests for endpoint formats and SwaggerDiff can run before merging the pull request and changing the gateway
2. Defining policies
Policies are defined and tested directly on our developer-level Azure APIM instance. Nothing extra is required here.
It is very simple to get operation policies through the Azure REST API. The Microsoft extractor does the same thing. However, we do not store them in the ARM template but directly in XML files. We attach an OpenAPI specification from previous build or download also through REST API. Everything can be done easily in powershell (our case), or you can customize the Microsoft Extractor if you want.
This is perhaps the best part of the approach. Importing is merely a reverted extraction process. You can PUT an OpenAPI specification, all policies and that’s it. Nice and simple.
What is missing?
Of course, you still have to create and setup all API Management instances. Or at least one if you want to save some money and have development, testing and pre-prod on one instance, for example. And I would advise to do so through ARM, especially if you plan to make another one (i.e., expand this to other regions).
If you would like to have more involvement of your source control system, it would require more coding to push or get API templates to your repository. We started only with CD artifacts and added GIT later. This was a big advantage for tracking of changes and the review process. In the end, it confirmed the correctness of our approach – we found that comparing two small XML files with a policy or OpenAPI documents is much more convenient than comparing two ARM templates.