import ballerina/http;

// Header name to be set to the request in the request interceptor.
final string interceptor_header1 = "X-requestHeader1";
final string interceptor_header2 = "X-requestHeader2";

// Header value to be set to the request in the request interceptor.
final string interceptor_header_value1 = "RequestInterceptor1";
final string interceptor_header_value2 = "RequestInterceptor2";

// A Request Interceptor service class implementation. It intercepts the request and adds a header before it is dispatched to the 
// target HTTP Resource. A Request Interceptor service class can have only one resource function.
service class RequestInterceptor1 {
    *http:RequestInterceptor;

    // A default resource function, which will be executed for all requests. A `RequestContext` is used to share data between 
    // interceptors. Resource methods are only allowed to return an `http:NextService|error?`.
    resource function 'default [string... path](http:RequestContext ctx, 
                            http:Request req) returns http:NextService|error? {
        // Sets a header to the request inside the interceptor service.
        req.setHeader(interceptor_header1, interceptor_header_value1);
        // Returns the next interceptor or the target service in the pipeline. An error is returned when the call fails.
        return ctx.next();
    }
}

// Creates a new Request Interceptor.
RequestInterceptor1 requestInterceptor1 = new;

// Another Request Interceptor service class.
service class RequestInterceptor2 {
    *http:RequestInterceptor;

    // This interceptor is only executed for GET requests with the default path. 
    resource function get [string... path](http:RequestContext ctx, 
                            http:Request req) returns http:NextService|error? {
        req.setHeader(interceptor_header2, interceptor_header_value2);
        return ctx.next();
    }
}

// Creates another new Request Interceptor.
RequestInterceptor2 requestInterceptor2 = new;

// Creates an HTTP Listener and assigns the interceptors as a config parameter. 
// Interceptor services will be executed in the configured order.
listener http:Listener interceptorListener = new http:Listener(9090, config = { 
    // Interceptor pipeline. Only interceptors with default path can be engaged 
    // at listener level.
    interceptors: [requestInterceptor1, requestInterceptor2] 
});

service / on interceptorListener {

    resource function get greeting(http:Request req) 
            returns http:Response|error? {
        // Create a new response.
        http:Response response = new;
        // Set the interceptor headers from request
        response.setHeader(interceptor_header1, 
                            check req.getHeader(interceptor_header1));
        response.setHeader(interceptor_header2, 
                            check req.getHeader(interceptor_header2));
        response.setTextPayload("Greetings!");
        return response;
    }
}

Request interceptor at listener level

The HTTP Listener supports intercepting requests in the request path. It is possible to define a RequestInterceptor service class with a resource function to execute custom logic and engage with an HTTP Listener. The request will go through the interceptor services before its dispatched to the actual resource in the target service. Interceptors engaged at listener level can only have default path. For more information, see the HTTP module.

import ballerina/http;
final string interceptor_header1 = "X-requestHeader1";
final string interceptor_header2 = "X-requestHeader2";

Header name to be set to the request in the request interceptor.

final string interceptor_header_value1 = "RequestInterceptor1";
final string interceptor_header_value2 = "RequestInterceptor2";

Header value to be set to the request in the request interceptor.

service class RequestInterceptor1 {
    *http:RequestInterceptor;

A Request Interceptor service class implementation. It intercepts the request and adds a header before it is dispatched to the target HTTP Resource. A Request Interceptor service class can have only one resource function.

    resource function 'default [string... path](http:RequestContext ctx, 
                            http:Request req) returns http:NextService|error? {

A default resource function, which will be executed for all requests. A RequestContext is used to share data between interceptors. Resource methods are only allowed to return an http:NextService|error?.

        req.setHeader(interceptor_header1, interceptor_header_value1);

Sets a header to the request inside the interceptor service.

        return ctx.next();
    }
}

Returns the next interceptor or the target service in the pipeline. An error is returned when the call fails.

RequestInterceptor1 requestInterceptor1 = new;

Creates a new Request Interceptor.

service class RequestInterceptor2 {
    *http:RequestInterceptor;

Another Request Interceptor service class.

    resource function get [string... path](http:RequestContext ctx, 
                            http:Request req) returns http:NextService|error? {
        req.setHeader(interceptor_header2, interceptor_header_value2);
        return ctx.next();
    }
}

This interceptor is only executed for GET requests with the default path.

RequestInterceptor2 requestInterceptor2 = new;

Creates another new Request Interceptor.

listener http:Listener interceptorListener = new http:Listener(9090, config = { 

Creates an HTTP Listener and assigns the interceptors as a config parameter. Interceptor services will be executed in the configured order.

    interceptors: [requestInterceptor1, requestInterceptor2] 
});

Interceptor pipeline. Only interceptors with default path can be engaged at listener level.

service / on interceptorListener {
    resource function get greeting(http:Request req) 
            returns http:Response|error? {
        http:Response response = new;

Create a new response.

        response.setHeader(interceptor_header1, 
                            check req.getHeader(interceptor_header1));
        response.setHeader(interceptor_header2, 
                            check req.getHeader(interceptor_header2));
        response.setTextPayload("Greetings!");
        return response;
    }
}

Set the interceptor headers from request

# Run the service
bal run http_request_interceptor_at_listener.bal
# Invoke the service.
curl -v http://localhost:9090/greeting
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9090 (#0)
> GET /greeting HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< X-requestHeader1: RequestInterceptor1
< X-requestHeader2: RequestInterceptor2
< content-type: text/plain
< content-length: 10
< server: ballerina
< date: Tue, 23 Nov 2021 17:16:16 +0530
< 
* Connection #0 to host localhost left intact
Greetings!* Closing connection 0