WSO2 APIM is a leading platform for building, integrating and exposing digital services as managed APIs. In the digital landscape, APIs serves as the bridge between applications, enabling seamless data exchange and paving path for digital transformation. The WSO2 API Manager centrally operates in this ecosystem, offering a comprehensive suite of features and capabilities for managing the complete lifecycle of APIs.
One of the major features of WSO2 APIM is rate limiting. Rate limiting of APIs is a critical aspect of API management that involves limiting the number of requests that can be made to an API during a given period. The primary purpose of rate limiting is to prevent abuse, protect server resources, ensure fair usage, monetization and maintain the overall quality of service for API consumers.
There are different types and levels of rate limiting supported by WSO2. Custom rate limiting is where it allows system administrators to define dynamic custom policies to tailor your API rate limiting rules to specific use cases and requirements. It’s important to note that custom rate-limiting policies are globally applied to all tenants. Custom rate limiting policies are defined by Siddhi query language. Hence, policies can be written by using Siddhi queries.
A custom policy consists of two major parts: the key template and Siddhi query. There are set of allowed keys which can be used as key templates. Multiple keys can be used separated by a colon (:), where each key must start with the prefix $. Allowed keys in the key template are as below,
- $resourceKey
- $userId
- $apiContext
- $apiVersion
- $appTenant
- $apiTenant
- $appId
- $clientIp
In the Siddhi query, we write the actual policy. In the query we must set a throttle key. If there is a mismatch between the throttle key and the key template the request will not be throttled. Hence throttle key in the Siddhi query should match the key template.
Create and test a custom throttling policy
For this purpose, I will be using the latest WSO2 APIM 4.2 running in my local. If you do not know how, read one of our blogs which explains how to run WSO2 products on Linux/Windows/Mac.
Once WSO2 server is up and running we can access the portals with the below URLs,
- Publisher portal – https://localhost:9443/pubisher
- Developer portal – https://localhost:9443/devportal
- Admin portal – https://localhost:9443/admin
Before creating a custom throttling policy, an API must be created and subscribed, to ensure that the API undergoes testing for throttling in accordance with the customized throttling policy.
Create an API
A new API is created in the publisher portal with the required resources, then it is deployed and published. Hence, a custom throttling policy can be created to throttle the API.
- Go to Publisher portal – https://localhost:9443/pubisher
- Create an API with the following details
- Go to Resources and delete the generated resources and add two GET resources for posts and todos as below,
- Go to Deployments and deploy the created API
- Go to Lifecycle and publish the deployed API
Subscribe to the API
An application is needed to be created in the developer portal and subscribed to the created API for us to generate a token and invoke the API resources.
- Go to Developer portal – https://localhost:9443/devportal
- Create an application
- Subscribe to the API
- Generate a token
Access the API
For accessing the API, any REST client or CURL can be used. In this case, I’m using Postman to invoke the API resources with the generated token to make sure the API resources are working as expected.
- Call the /posts API by using the generated token in the previous step
- Call the /todos API by using the generated token in the previous step
Both the APIs are working as expected.
Create a custom throttling policy
Let’s create a custom throttling policy to throttle the posts endpoint when more than 5 requests are made within a minute.
- Go to Admin portal – https://localhost:9443/admin
- Select Custom Policies and click Define
- Create policy with below details,
Key Template: $resourceKey
Siddhi Query:
FROM
RequestStream
SELECT
userId,
(resourceKey == '/test/v1/v1/posts:GET') AS isEligible,
resourceKey as throttleKey
INSERT INTO
EligibilityStream;
FROM
EligibilityStream [ isEligible == true ] # throttler: timeBatch(1 min)
SELECT
throttleKey,
(count(userId) >= 5) as isThrottled,
expiryTimeStamp
group by
throttleKey
INSERT
ALL EVENTS into ResultStream;
As per the policy,
- KeyTemplate has the value $resourceKey which implies the throttling should be done based on the resource path
- In SiddhiQuery,
- resourceKey =
/test/v1/v1/posts:GET
– throttling is to be check for the endpoint/test/v1/v1/posts
which is a GET resource. - resourceKey as throttleKey – is where the value of KeyTemplate will be same as the value of throttleKey
- timeBatch(1 min) — is the throttling policy time period.
- count(userId) >= 5) as isThrottled — is the throttling request count checker (5 requests for each userID).
- resourceKey =
Therefore, the summary of above Siddhi query is that this policy allows a user to send only 5 requests per 1 minute for the GET resource /test/v1/v1/posts
and then it will throttle the request.
Test custom throttling policy
Now we must call the posts endpoint more than 5 times to check if the request gets throttled. When it is tested by calling the endpoint more than 5 times it gives the following message with the status code 429 (too many requests),
As per the above, custom throttling works as expected and this custom policy has no affect for the other endpoint todos. If todos endpoint is called more that 5 times, it will continue to work as the custom policy is created only to throttle the posts resource.
Additional Policy – Throttle a specific API resource for a specific user
This is a policy to throttle a specific API resource which is the ‘/posts’ resource for a specific user called ‘saad’ under the super tenant.
Key Template: $userId:$resourceKey
Siddhi Query:
FROM
RequestStream
SELECT
userId,
(
userId == 'saad@carbon.super'
and resourceKey == '/test/v1/v1/posts:GET'
) AS isEligible,
str: concat('saad@carbon.super', ':', '/test/v1/v1/posts:GET') as throttleKey
INSERT INTO
EligibilityStream;
FROM
EligibilityStream [ isEligible == true ] # throttler: timeBatch(1 min)
SELECT
throttleKey,
(count(throttleKey) >= 5) as isThrottled,
expiryTimeStamp
group by
throttleKey
INSERT
ALL EVENTS into ResultStream;
As per the above query,
- (userId == ‘saad@carbon.super‘ and resourceKey == ‘/test/v1/v1/posts:GET’ ) AS isEligible – is where the specific userId and resource path is selected for throttling
- str: concat(‘saad@carbon.super’, ‘:’, ‘/test/v1/v1/posts:GET’) as throttleKey – specific userId and the resource path are concatanated and set as the throttle key to which will then be same as the key template.
- timeBatch(1 min) — is the throttling policy time period.
- count(throttleKey) >= 5) as isThrottled – is the throttling request count checker (5 requests for the throttle key where 5 requests allowed for the specific user for the specific resource).
Therefore, the summary of above Siddhi query is that this policy allows the user saad@carbon.super
to send only 5 requests per 1 minute for the GET resource /test/v1/v1/posts
and then it will throttle the request. And the throttling will not apply for any other resources and also not for any other users for this specific resource.
Additional Policy – Throttle API requests for all the users other than the super admin user
This is a policy to throttle API requests for any users other than the super admin user. Hence, the request will get throttled for any user unless the user is an admin in the super tenant.
Key Template: $userId
Siddhi Query:
FROM
RequestStream
SELECT
userId,
(userId != 'admin@carbon.super') AS isEligible,
userId as throttleKey
INSERT INTO
EligibilityStream;
FROM
EligibilityStream [ isEligible == true ] # throttler: timeBatch(1 min)
SELECT
throttleKey,
(count(userId) >= 5) as isThrottled,
expiryTimeStamp
group by
throttleKey
INSERT
ALL EVENTS into ResultStream;
As per the above query,
- (userId != ‘admin@carbon.super’) AS isEligible – is where the specific userId selected for throttling (in this case it is all the users except for the super admin user)
- userId as throttleKey – userId is set as the throttle key, which will then be same as the key template.
- timeBatch(1 min) — is the throttling policy time period.
- count(userId) >= 5) as isThrottled – is the throttling request count checker (5 requests for each userID).
Therefore, the summary of above Siddhi query is that this policy allows the super admin user (admin@carbon.super) to send any number of requests and any other user can send only 5 requests per 1 minute for any resources then it will throttle the requests.
Conclusion
Rate limiting is a primary feature in any API management platform. With custom rate limiting you/it can offer several advantages, particularly when you have specific use cases and requirements that go beyond standard rate limiting policies. It provides fine grained controls on throttling based on API context, version, resource path, user ID etc. Having such control allows for adjustments based on evolving conditions or business needs. Custom rate limiting can support personalized experiences for users. You can tailor rate limits to individual users’ behaviour, providing a smoother and more responsive experience for your most active users.
For industries with specific compliance requirements, custom rate limiting can help ensure that your API usage adheres to regulatory standards. You can implement rate limits that align with compliance mandates. It’s important to note that while custom rate limiting offers these advantages, it also requires careful planning, testing, and ongoing monitoring. Implementing complex rate limiting logic should be done thoughtfully to avoid unintentional service disruptions or overly restrictive policies. Additionally, consider the scalability of your custom rate limiting solution to accommodate growing API usage.