Implement API Management
Explore API Management
After completing this module, you'll be able to:
- Describe the components, and their function, of the API Management service.
- Explain how API gateways can help manage calls to your APIs.
- Secure access to APIs by using subscriptions and certificates.
- Create a backend API.
Discover the API Management service
API Management provides the core functionality to ensure a successful API program through developer engagement, business insights, analytics, security, and protection. Each API consists of one or more operations, and each API can be added to one or more products. To use an API, developers subscribe to a product that contains that API, and then they can call the API's operation, subject to any usage policies that may be in effect.
API Management components
Azure API Management is made up of an API gateway, a management plane, and a developer portal. These components are Azure-hosted and fully managed by default. API Management is available in various tiers differing in capacity and features.
- The API gateway is the endpoint that:
- Accepts API calls and routes them to appropriate backends
- Verifies API keys and other credentials presented with requests
- Enforces usage quotas and rate limits
- Transforms requests and responses specified in policy statements
- Caches responses to improve response latency and minimize the load on backend services
- Emits logs, metrics, and traces for monitoring, reporting, and troubleshooting
- The management plane is the administrative interface where you set up your API program. Use it to:
- Provision and configure API Management service settings
- Define or import API schema
- Package APIs into products
- Set up policies like quotas or transformations on the APIs
- Get insights from analytics
- Manage users
- The Developer portal is an automatically generated, fully customizable website with the documentation of your APIs. Using the developer portal, developers can:
- Read API documentation
- Call an API via the interactive console
- Create an account and subscribe to get API keys
- Access analytics on their own usage
- Download API definitions
- Manage API keys
Products
Products are how APIs are surfaced to developers. Products in API Management have one or more APIs, and are configured with a title, description, and terms of use. Products can be Open or Protected. Protected products must be subscribed to before they can be used, while open products can be used without a subscription. Subscription approval is configured at the product level and can either require administrator approval, or be auto approved.
Groups
Groups are used to manage the visibility of products to developers. API Management has the following immutable system groups:
- Administrators - Manage API Management service instances and create the APIs, operations, and products that are used by developers. Azure subscription administrators are members of this group.
- Developers - Authenticated developer portal users that build applications using your APIs. Developers are granted access to the developer portal and build applications that call the operations of an API.
- Guests - Unauthenticated developer portal users. They can be granted certain read-only access, like the ability to view APIs but not call them.
In addition to these system groups, administrators can create custom groups or use external groups in associated Microsoft Entra tenants.
Developers
Developers represent the user accounts in an API Management service instance. Developers can be created or invited to join by administrators, or they can sign up from the Developer portal. Each developer is a member of one or more groups, and can subscribe to the products that grant visibility to those groups.
Policies
Policies are a collection of statements that are executed sequentially on the request or response of an API. Popular statements include format conversion from XML to JSON and call rate limiting to restrict the number of incoming calls from a developer, and many other policies are available.
Policy expressions can be used as attribute values or text values in any of the API Management policies, unless the policy specifies otherwise. Some policies such as the Control flow and Set variable policies are based on policy expressions.
Policies can be applied at different scopes, depending on your needs: global (all APIs), a product, a specific API, or an API operation.
Explore API gateways
Your solution may contain several front- and back-end services. In this scenario, how does a client know what endpoints to call? What happens when new services are introduced, or existing services are refactored? How do services handle SSL termination, authentication, and other concerns?
The API Management gateway (also called data plane or runtime) is the service component that's responsible for proxying API requests, applying policies, and collecting telemetry.
An API gateway sits between clients and services. It acts as a reverse proxy, routing requests from clients to services. It may also perform various cross-cutting tasks such as authentication, SSL termination, and rate limiting. If you don't deploy a gateway, clients must send requests directly to back-end services. However, there are some potential problems with exposing services directly to clients:
- It can result in complex client code. The client must keep track of multiple endpoints, and handle failures in a resilient way.
- It creates coupling between the client and the backend. The client needs to know how the individual services are decomposed. That makes it harder to maintain the client and also harder to refactor services.
- A single operation might require calls to multiple services.
- Each public-facing service must handle concerns such as authentication, SSL, and client rate limiting.
- Services must expose a client-friendly protocol such as HTTP or WebSocket. This limits the choice of communication protocols.
- Services with public endpoints are a potential attack surface, and must be hardened.
A gateway helps to address these issues by decoupling clients from services.
Managed and self-hosted
API Management offers both managed and self-hosted gateways:
- Managed - The managed gateway is the default gateway component that is deployed in Azure for every API Management instance in every service tier. With the managed gateway, all API traffic flows through Azure regardless of where backends implementing the APIs are hosted.
- Self-hosted - The self-hosted gateway is an optional, containerized version of the default managed gateway. It's useful for hybrid and multicloud scenarios where there's a requirement to run the gateways off of Azure in the same environments where API backends are hosted. The self-hosted gateway enables customers with hybrid IT infrastructure to manage APIs hosted on-premises and across clouds from a single API Management service in Azure.
Explore API Management policies
In Azure API Management, policies allow the publisher to change the behavior of the API through configuration. Policies are a collection of Statements that are executed sequentially on the request or response of an API.
Policies are applied inside the gateway that sits between the API consumer and the managed API. The gateway receives all requests and usually forwards them unaltered to the underlying API. However a policy can apply changes to both the inbound request and outbound response. Policy expressions can be used as attribute values or text values in any of the API Management policies, unless the policy specifies otherwise.
Understanding policy configuration
The policy definition is a simple XML document that describes a sequence of inbound and outbound statements. The XML can be edited directly in the definition window.
The configuration is divided into inbound
, backend
, outbound
, and on-error
. The series of specified policy statements is executed in order for a request and a response.
<policies>
<inbound>
<!-- statements to be applied to the request go here -->
</inbound>
<backend>
<!-- statements to be applied before the request is forwarded to
the backend service go here -->
</backend>
<outbound>
<!-- statements to be applied to the response go here -->
</outbound>
<on-error>
<!-- statements to be applied if there is an error condition go here -->
</on-error>
</policies>
If there's an error during the processing of a request, any remaining steps in the inbound
, backend
, or outbound
sections are skipped and execution jumps to the statements in the on-error
section. By placing policy statements in the on-error
section you can review the error by using the context.LastError
property, inspect and customize the error response using the set-body
policy, and configure what happens if an error occurs.
Policy expressions
Unless the policy specifies otherwise, policy expressions can be used as attribute values or text values in any of the API Management policies. A policy expression is either:
- a single C# statement enclosed in
@(expression)
, or - a multi-statement C# code block, enclosed in
@{expression}
, that returns a value
Each expression has access to the implicitly provided context
variable and an allowed subset of .NET Framework types.
Policy expressions provide a sophisticated means to control traffic and modify API behavior without requiring you to write specialized code or modify backend services.
The following example uses policy expressions and the set-header policy to add user data to the incoming request. The added header includes the user ID associated with the subscription key in the request, and the region where the gateway processing the request is hosted.
<policies>
<inbound>
<base />
<set-header name="x-request-context-data" exists-action="override">
<value>@(context.User.Id)</value>
<value>@(context.Deployment.Region)</value>
</set-header>
</inbound>
</policies>
Apply policies specified at different scopes
If you have a policy at the global level and a policy configured for an API, then whenever that particular API is used both policies are applied. API Management allows for deterministic ordering of combined policy statements via the base element.
<policies>
<inbound>
<cross-domain />
<base />
<find-and-replace from="xyz" to="abc" />
</inbound>
</policies>
In the previous example policy definition, The cross-domain
statement would execute first. The find-and-replace
policy would execute after any policies at a broader scope.
Filter response content
The policy defined in following example demonstrates how to filter data elements from the response payload based on the product associated with the request.
The snippet assumes that response content is formatted as JSON and contains root-level properties named "minutely", "hourly", "daily", "flags".
<policies>
<inbound>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<choose>
<when condition="@(context.Response.StatusCode == 200 && context.Product.Name.Equals("Starter"))">
<!-- NOTE that we are not using preserveContent=true when deserializing response body stream into a JSON object since we don't intend to access it again. See details on /azure/api-management/api-management-transformation-policies#SetBody -->
<set-body>
@{
var response = context.Response.Body.As<JObject>();
foreach (var key in new [] {"minutely", "hourly", "daily", "flags"}) {
response.Property (key).Remove ();
}
return response.ToString();
}
</set-body>
</when>
</choose>
</outbound>
<on-error>
<base />
</on-error>
</policies>
Create advanced policies
This unit provides a reference for the following API Management policies:
- Control flow - Conditionally applies policy statements based on the results of the evaluation of Boolean expressions.
- Forward request - Forwards the request to the backend service.
- Limit concurrency - Prevents enclosed policies from executing by more than the specified number of requests at a time.
- Log to Event Hub - Sends messages in the specified format to an Event Hub defined by a Logger entity.
- Mock response - Aborts pipeline execution and returns a mocked response directly to the caller.
- Retry - Retries execution of the enclosed policy statements, if and until the condition is met. Execution will repeat at the specified time intervals and up to the specified retry count.
Control flow
The choose
policy applies enclosed policy statements based on the outcome of evaluation of boolean expressions, similar to an if-then-else or a switch construct in a programming language.
<choose>
<when condition="Boolean expression | Boolean constant">
<!— one or more policy statements to be applied if the above condition is true -->
</when>
<when condition="Boolean expression | Boolean constant">
<!— one or more policy statements to be applied if the above condition is true -->
</when>
<otherwise>
<!— one or more policy statements to be applied if none of the above conditions are true -->
</otherwise>
</choose>
The control flow policy must contain at least one <when/>
element. The <otherwise/>
element is optional. Conditions in <when/>
elements are evaluated in order of their appearance within the policy. Policy statement(s) enclosed within the first <when/>
element with condition attribute equals true will be applied. Policies enclosed within the <otherwise/>
element, if present, will be applied if all of the <when/>
element condition attributes are false.
Forward request
The forward-request
policy forwards the incoming request to the backend service specified in the request context. The backend service URL is specified in the API settings and can be changed using the set backend service policy.
Removing this policy results in the request not being forwarded to the backend service and the policies in the outbound section are evaluated immediately upon the successful completion of the policies in the inbound section.
Limit concurrency
The limit-concurrency
policy prevents enclosed policies from executing by more than the specified number of requests at any time. Upon exceeding that number, new requests will fail immediately with a 429 Too Many Requests status code.
<limit-concurrency key="expression" max-count="number">
<!— nested policy statements -->
</limit-concurrency>
Log to Event Hub
The log-to-eventhub
policy sends messages in the specified format to an Event Hub defined by a Logger entity. As its name implies, the policy is used for saving selected request or response context information for online or offline analysis.
<log-to-eventhub logger-id="id of the logger entity" partition-id="index of the partition where messages are sent" partition-key="value used for partition assignment">
Expression returning a string to be logged
</log-to-eventhub>
Mock response
The mock-response
, as the name implies, is used to mock APIs and operations. It aborts normal pipeline execution and returns a mocked response to the caller. The policy always tries to return responses of highest fidelity. It prefers response content examples, whenever available. It generates sample responses from schemas, when schemas are provided and examples are not. If neither examples or schemas are found, responses with no content are returned.
Retry
The retry
policy executes its child policies once and then retries their execution until the retry condition
becomes false
or retry count
is exhausted.
<retry
condition="boolean expression or literal"
count="number of retry attempts"
interval="retry interval in seconds"
max-interval="maximum retry interval in seconds"
delta="retry interval delta in seconds"
first-fast-retry="boolean expression or literal">
<!-- One or more child policies. No restrictions -->
</retry>
Return response
The return-response
policy aborts pipeline execution and returns either a default or custom response to the caller. Default response is 200 OK
with no body. Custom response can be specified via a context variable or policy statements. When both are provided, the response contained within the context variable is modified by the policy statements before being returned to the caller.
<return-response response-variable-name="existing context variable">
<set-header/>
<set-body/>
<set-status/>
</return-response>
Additional resources
- Visit API Management policies for more policy examples.
- Error handling in API Management policies
Secure APIs by using subscriptions
When you publish APIs through API Management, it's easy and common to secure access to those APIs by using subscription keys. Developers who need to consume the published APIs must include a valid subscription key in HTTP requests when they make calls to those APIs. Otherwise, the calls are rejected immediately by the API Management gateway. They aren't forwarded to the back-end services.
To get a subscription key for accessing APIs, a subscription is required. A subscription is essentially a named container for a pair of subscription keys. Developers who need to consume the published APIs can get subscriptions. And they don't need approval from API publishers. API publishers can also create subscriptions directly for API consumers.
Subscriptions and Keys
A subscription key is a unique auto-generated key that can be passed through in the headers of the client request or as a query string parameter. The key is directly related to a subscription, which can be scoped to different areas. Subscriptions give you granular control over permissions and policies.
The three main subscription scopes are:
Scope | Details |
---|---|
All APIs | Applies to every API accessible from the gateway |
Single API | This scope applies to a single imported API and all of its endpoints |
Product | A product is a collection of one or more APIs that you configure in API Management. You can assign APIs to more than one product. Products can have different access rules, usage quotas, and terms of use. |
Applications that call a protected API must include the key in every request.
You can regenerate these subscription keys at any time, for example, if you suspect that a key has been shared with unauthorized users.
Every subscription has two keys, a primary and a secondary. Having two keys makes it easier when you do need to regenerate a key. For example, if you want to change the primary key and avoid downtime, use the secondary key in your apps.
For products where subscriptions are enabled, clients must supply a key when making calls to APIs in that product. Developers can obtain a key by submitting a subscription request. If you approve the request, you must send them the subscription key securely, for example, in an encrypted message. This step is a core part of the API Management workflow.
Call an API with the subscription key
Applications must include a valid key in all HTTP requests when they make calls to API endpoints that are protected by a subscription. Keys can be passed in the request header, or as a query string in the URL.
The default header name is Ocp-Apim-Subscription-Key, and the default query string is subscription-key.
To test out your API calls, you can use the developer portal, or command-line tools, such as curl. Here's an example of a GET
request using the developer portal, which shows the subscription key header:
Here's how you can pass a key in the request header using curl:
curl --header "Ocp-Apim-Subscription-Key: <key string>" https://<apim gateway>.azure-api.net/api/path
Here's an example curl command that passes a key in the URL as a query string:
If the key is not passed in the header, or as a query string in the URL, you'll get a 401 Access Denied response from the API gateway.
Secure APIs by using certificates
Certificates can be used to provide Transport Layer Security (TLS) mutual authentication between the client and the API gateway. You can configure the API Management gateway to allow only requests with certificates containing a specific thumbprint. The authorization at the gateway level is handled through inbound policies.
Transport Layer Security client authentication
With TLS client authentication, the API Management gateway can inspect the certificate contained within the client request and check for properties like:
Property | Description |
---|---|
Certificate Authority (CA) | Only allow certificates signed by a particular CA |
Thumbprint | Allow certificates containing a specified thumbprint |
Subject | Only allow certificates with a specified subject |
Expiration Date | Only allow certificates that have not expired |
These properties are not mutually exclusive and they can be mixed together to form your own policy requirements. For instance, you can specify that the certificate passed in the request is signed by a certain certificate authority and hasn't expired.
Client certificates are signed to ensure that they are not tampered with. When a partner sends you a certificate, verify that it comes from them and not an imposter. There are two common ways to verify a certificate:
- Check who issued the certificate. If the issuer was a certificate authority that you trust, you can use the certificate. You can configure the trusted certificate authorities in the Azure portal to automate this process.
- If the certificate is issued by the partner, verify that it came from them. For example, if they deliver the certificate in person, you can be sure of its authenticity. These are known as self-signed certificates.
Accepting client certificates in the Consumption tier
The Consumption tier in API Management is designed to conform with serverless design principals. If you build your APIs from serverless technologies, such as Azure Functions, this tier is a good fit. In the Consumption tier, you must explicitly enable the use of client certificates, which you can do on the Custom domains page. This step is not necessary in other tiers.
Certificate Authorization Policies
Create these policies in the inbound processing policy file within the API Management gateway:
Check the thumbprint of a client certificate
Every client certificate includes a thumbprint, which is a hash, calculated from other certificate properties. The thumbprint ensures that the values in the certificate have not been altered since the certificate was issued by the certificate authority. You can check the thumbprint in your policy. The following example checks the thumbprint of the certificate passed in the request:
<choose>
<when condition="@(context.Request.Certificate == null || context.Request.Certificate.Thumbprint != "desired-thumbprint")" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
Check the thumbprint against certificates uploaded to API Management
In the previous example, only one thumbprint would work so only one certificate would be validated. Usually, each customer or partner company would pass a different certificate with a different thumbprint. To support this scenario, obtain the certificates from your partners and use the Client certificates page in the Azure portal to upload them to the API Management resource. Then add this code to your policy:
<choose>
<when condition="@(context.Request.Certificate == null || !context.Request.Certificate.Verify() || !context.Deployment.Certificates.Any(c => c.Value.Thumbprint == context.Request.Certificate.Thumbprint))" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
Check the issuer and subject of a client certificate
This example checks the issuer and subject of the certificate passed in the request:
<choose>
<when condition="@(context.Request.Certificate == null || context.Request.Certificate.Issuer != "trusted-issuer" || context.Request.Certificate.SubjectName.Name != "expected-subject-name")" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
Exercise: Create a backend API
Create an API management instance
Let's set some variables for the CLI commands to use to reduce the amount of retyping. Replace <myLocation>
with a region that makes sense for you. The APIM name needs to be a globally unique name, and the following script generates a random string. Replace <myEmail>
with an email address you can access.
Create a resource group. The following commands create a resource group named az204-apim-rg.
Create an APIM instance. The az apim create
command is used to create the instance. The --sku-name Consumption
option is used to speed up the process for the walkthrough.
az apim create -n $myApiName \
--location $myLocation \
--publisher-email $myEmail \
--resource-group az204-apim-rg \
--publisher-name AZ204-APIM-Exercise \
--sku-name Consumption
Import a backend API
This section shows how to import and publish an OpenAPI specification backend API.
- In the Azure portal, search for and select API Management services.
- On the API Management screen, select the API Management instance you created.
-
Select APIs in the API management service navigation pane.
-
Select OpenAPI from the list and select Full in the pop-up.
Use the values from the table below to fill out the form. You can leave any fields not mentioned their default value.
Setting | Value | Description |
---|---|---|
OpenAPI Specification | https://conferenceapi.azurewebsites.net?format=json |
References the service implementing the API, requests are forwarded to this address. Most of the necessary information in the form is automatically populated after you enter this. |
Display name | Demo Conference API | This name is displayed in the Developer portal. |
Name | demo-conference-api | Provides a unique name for the API. |
Description | Automatically populated | Provide an optional description of the API. |
API URL suffix | conference | The suffix is appended to the base URL for the API management service. API Management distinguishes APIs by their suffix and therefore the suffix must be unique for every API for a given publisher. |
Configure the backend settings
The Demo Conference API is created and a backend needs to be specified.
- Select Settings in the blade to the right and enter
https://conferenceapi.azurewebsites.net/
in the Web service URL field. - Deselect the Subscription required checkbox.
- Select Save.
Test the API
Now that the API has been imported and the backend configured it's time to test the API.
-
Select Test.
-
Select GetSpeakers. The page shows Query parameters and Headers, if any. The
Ocp-Apim-Subscription-Key
is filled in automatically for the subscription key associated with this API. - Select Send. Backend responds with 200 OK and some data.
Clean up Azure resources
When you're finished with the resources you created in this exercise you can use the command below to delete the resource group and all related resources.