API gateways play a critical role in modern enterprise architecture. As microservices strengthen their hold on modern-day application architectures, cloud native API gateways are high in demand. Ballerina, being a programming language designed to address and simplify the complexities of heavily distributed systems primarily built on microservice architectures, provides a rich set of language features and a smart compiler that makes it a good choice of technology to build a cloud native API gateway.
10. Forwarding request to the target
http:Client targetEndpoint = new ("https://api.pizzastore.com/pizzashack/v1");
@http:ServiceConfig {
basePath: "/pizzashack/1.0.0"
}
service passthrough on new http:Listener (9090) {
@http:ResourceConfig {
methods:["GET"],
path:"/menu"
}
resource function getMenu (http:Caller caller, http:Request req) {
. . . . . . .
}
}
11. Forwarding request to the target
resource function getMenu (http:Caller caller, http:Request req) {
//Forward the client request to the /menu resource of the Target Endpoint.
var clientResponse = targetEndpoint -> forward(“/menu”, req);
//Check if the response from the target Endpoint was a success or not.
if clientResponse is http:Response{
var result = caller->respond(res);
if result is error {
log:printError("Error sending response");
}
}
else {
http:Response res = new;
res.statusCode = 500;
res.setPayload(err.message);
var result = caller->respond(res);
if result is error {
log:printError("Error sending response");
}
}
14. Listeners and Filters service passthrough on new http:Listener
(9090) {
import wso2/gateway;
AuthnFilter authnFilter;
OAuthzFilter authzFilter;
RateLimitFilter rateLimitFilter;
AnalyticsFilter analyticsFilter;
ExtensionFilter extensionFilter;
listener gateway:APIGatewayListener
apiListener = new (9095, {
filters:[authnFilter, authzFilter,
rateLimitFilter,
analyticsFilter,
extensionFilter]
});
service passthrough on apiListener {
A listener is what a service binds
itself to.
A listener may have one or more
filters to filter requests being
received on the port of the listener.
16. Authentication listener gateway:APIGatewayListener
apiListener = new (9095, {
filters:[authnFilter, authzFilter]}, {
authProviders:[jwtAuthProvider, basic]
});
http:AuthProvider jwtAuthProvider = {
scheme:"jwt",
issuer:"ballerina",
audience: "ballerina.io",
certificateAlias: "ballerina",
trustStore: {
path:
"${ballerina.home}/bre/security/ballerinaTr
uststore.p12",
password: "ballerina"
}
};
The microgateway supports
different authentication
mechanisms such as OAuth2,
basic authentication, etc.
Which mechanisms to apply
against a request is decided by the
declared authentication providers
in the listener.
17. Enabling/Disabling
security by service
//This service is accessible at
// /pizzashack/1.0.0 on port 9095
@http:ServiceConfig {
basePath: "/pizzashack/1.0.0",
authConfig: {
authentication: { enabled: true }
}
}
service passthrough on apiListener {
. . . . .
. . . . .
}
Each service bound to the listener
can chose to enable or disable
security by itself.
18. Authorization
Authorization is enabled per each
operation of the service using
‘scopes’.
Scopes are used as a means of
abstracting the authorization
mechanism.
@http:ResourceConfig {
methods:["PUT"],
path:"/menu",
authConfig: {
scopes: ["edit_menu"]
}
}
resource function editMenu (http:Caller
caller, http:Request req)
19. Microgateway in-bound security architecture.
CLIENT DEVICES MICROGATEWAY MICROSERVICE
SECURITY TOKEN SERVICE
1 OBTAIN TOKEN FROM
STS
2 SEND TOKEN TO MICROGATEWAY
WITH REQUEST
3
OPTIONAL VALIDATION
REQUEST FROM
MICROGATEWAY TO STS
4
FORWARD REQUEST TO
TARGET
21. Ballerina Streams
The RateLimitFilter on the listener
adds metadata of every
successful request into a
data-stream.
public stream<RequestStreamDTO>
requestStream;
public function
publishNonThrottleEvent(RequestStreamDTO
request) {
requestStream.publish(request);
}
22. Rate limiting Policies
Rate limiting policies on the
microgateway are modelled as
stream processors where it
executes logic on the data
received via the stream.
forever {
from gateway:requestStream
select messageID, (tier == "Silver")
as isEligible,
subscriptionKey as throttleKey
=> (gateway:EligibilityStreamDTO[]
counts) {
eligibilityStream.publish(counts);
}
from eligibilityStream
throttler:timeBatch(60000, 0)
where isEligible == true
select throttleKey, count(messageID)
>= 2000 as isThrottled,
expiryTimeStamp
group by throttleKey
=>
(gateway:GlobalThrottleStreamDTO[] counts)
{
resultStream.publish(counts);
}
24. Microgateway analytics architecture.
CLIENT DEVICES MICROGATEWAY ANALYTICS ENGINE
1 SEND REQUEST TO
MICROGATEWAY
2 WRITE REQUEST META-DATA TO
FILE SYSTEM
3
PERIODICALLY READ
DATA FROM FILE SYSTEM
4
UPLOAD DATA TO ANALYTICS
ENGINE FOR PROCESSING
BALLERINA BASED
PERIODIC TASK
25. Using Ballerina Streams to
avoid write-lock contentions
on the file system
public function filterRequest(http:Request
request, http:FilterContext context)
returns http:FilterResult {
http:FilterResult requestFilterResult;
AnalyticsRequestStream requestStream =
generateRequestEvent(request, context);
EventDTO eventDto =
generateEventFromRequest(requestStream);
eventStream.publish(eventDto);
requestFilterResult = { canProceed:
true, statusCode: 200, message:
"Analytics filter processed." };
return requestFilterResult;
}
SERVICE 1 SERVICE 2 SERVICE 3
EVENT STREAM
FILE SYSTEM
26. Ballerina Character I/O API for
writing data to file
io:ByteChannel channel =
io:openFile("api-usage-data.dat",
io:APPEND);
io:CharacterChannel charChannel =
new(channel, "UTF-8");
try {
match
charChannel.write(getEventData(eventDTO),0)
{
. . . .
. . . .
}
} finally {
match charChannel.close() {
. . . .
. . . .
}
}