Skip to main content

API Security and Rate Limiting

Protect your integration APIs from abuse, overload, and malicious input with rate limiting, request validation, and CORS configuration.

Rate limiting​

Implement rate limiting using a middleware pattern with Ballerina's HTTP interceptors:

import ballerina/http;
import ballerina/cache;
import ballerina/time;

final cache:Cache rateLimitCache = new ({
capacity: 10000,
defaultMaxAge: 60 // 60-second window
});

service class RateLimitInterceptor {
*http:RequestInterceptor;

resource function 'default [string... path](
http:RequestContext ctx, http:Request req) returns http:NextService|http:TooManyRequests|error? {
string clientIp = check req.getHeader("X-Forwarded-For");
int|error count = rateLimitCache.get(clientIp).ensureType();
if count is int && count >= 100 {
return <http:TooManyRequests>{
body: {message: "Rate limit exceeded. Try again later."},
headers: {"Retry-After": "60"}
};
}
rateLimitCache.put(clientIp, (count is int ? count + 1 : 1));
return ctx.next();
}
}

Request size limits​

Configure maximum request payload size on the HTTP listener:

listener http:Listener apiListener = new (9090, {
maxPayloadSize: 1048576, // 1 MB max payload
maxHeaderSize: 8192, // 8 KB max header size
maxUriLength: 4096 // 4 KB max URI length
});

Input validation​

Validate incoming data using Ballerina's type system and constraint annotations:

import ballerina/constraint;

type OrderRequest record {|
@constraint:String {minLength: 1, maxLength: 100}
string customerName;

@constraint:Array {minLength: 1, maxLength: 50}
OrderItem[] items;

@constraint:Float {minValue: 0.01}
float total;
|};

resource function post orders(OrderRequest req) returns http:Created|http:BadRequest {
// Ballerina automatically validates constraints
// Invalid requests return 400 before reaching your code
return <http:Created>{body: {status: "created"}};
}

CORS configuration​

@http:ServiceConfig {
cors: {
allowOrigins: ["https://app.example.com"],
allowMethods: ["GET", "POST", "PUT", "DELETE"],
allowHeaders: ["Content-Type", "Authorization"],
maxAge: 3600
}
}
service /api on apiListener {
// Resources here
}

Security headers​

Add security headers to all responses:

service class SecurityHeaderInterceptor {
*http:ResponseInterceptor;

remote function interceptResponse(http:RequestContext ctx,
http:Response res) returns http:NextService|error? {
res.setHeader("X-Content-Type-Options", "nosniff");
res.setHeader("X-Frame-Options", "DENY");
res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
res.setHeader("X-XSS-Protection", "1; mode=block");
return ctx.next();
}
}

What's next​