Back to Examples

HTTP service - Response interceptor

The http:ResponseInterceptor is used to intercept the response and execute custom logic. A ResponseInterceptor is a service object with a remote method called interceptResponse, which is executed before dispatching the response to the client. A ResponseInterceptor can be created from a service class, which includes the http:ResponseInterceptor service type.

This service object can be engaged at the service level by declaring an http:InterceptableService object. This accepts an interceptor service object or an array of interceptor service objects as an interceptor pipeline and the interceptors are executed in the order in which they are placed in the pipeline.

Use ResponseInterceptors to execute common logic such as logging, header manipulation, state publishing, etc., for all outbound responses.

import ballerina/http;

type Album readonly & record {|
    string title;
    string artist;
|};

table<Album> key(title) albums = table [
    {title: "Blue Train", artist: "John Coltrane"},
    {title: "Jeru", artist: "Gerry Mulligan"}
];

// A `ResponseInterceptor` service class implementation. It intercepts the response 
// and adds a header before it is dispatched to the client.
service class ResponseInterceptor {
    *http:ResponseInterceptor;

    // The `interceptResponse` remote method will be executed for all the
    // responses. A `RequestContext` is used to share data between interceptors.
    remote function interceptResponse(http:RequestContext ctx,
            http:Response res) returns http:NextService|error? {
        // Sets a header to the response inside the interceptor service.
        res.setHeader("x-api-version", "v2");
        // Returns the next interceptor in the pipeline or `nil` if there is no 
        // more interceptors to be returned. In case a `nil` value is returned, then,
        // the modified response will be returned to the client. In addition to these
        // return values, an error is returned when the call fails.
        return ctx.next();
    }
}

// Engage interceptors at the service level using an `http:InterceptableService`. The base path of the
// interceptor services is the same as the target service. Hence, they will be executed only for
// this particular service.
service http:InterceptableService / on new http:Listener(9090) {

    // Creates the interceptor pipeline. The function can return a single interceptor or an array of
    // interceptors as the interceptor pipeline. If the interceptor pipeline is an array, then, the
    // request interceptor services will be executed from head to tail.
    public function createInterceptors() returns ResponseInterceptor {
        return new ResponseInterceptor();
    }

    resource function get albums() returns Album[] {
        return albums.toArray();
    }
}

Run the service as follows.

$ bal run http_response_interceptor.bal

Invoke the service by executing the following cURL command in a new terminal.

$ curl -v http://localhost:9090/albums*   Trying 127.0.0.1:9090...* Connected to localhost (127.0.0.1) port 9090 (#0)> GET /albums HTTP/1.1> Host: localhost:9090> User-Agent: curl/7.79.1> Accept: */*> * Mark bundle as not supporting multiuse< HTTP/1.1 200 OK< content-type: application/json< x-api-version: v2< content-length: 95< server: ballerina< date: Wed, 14 Dec 2022 11:51:35 +0530< [{"title":"Blue Train", "artist":"John Coltrane"}, {"title":"Jeru", "artist":"Gerry Mulligan"}]

Tip: You can invoke the above service via the Send request/Receive response client.

Related links

PreviousRequest interceptor
NextError handling