import ballerina/http;

// A `ResponseErrorInterceptor` service class implementation. It allows you
// to intercept the errors and handle them accordingly. A `ResponseErrorInterceptor`
// service can only have one remote function: `interceptResponseError`.
service class ResponseErrorInterceptor {
    *http:ResponseErrorInterceptor;

    // The error occurred in the request-response path can be accessed by the 
    // mandatory argument : `error`. The remote function can return a response,
    // which will overwrite the existing error response.
    remote function interceptResponseError(error err) 
            returns http:InternalServerError {
        // In this case, all of the errors are sent as HTTP 500 internal server 
        // errors with a customized media type and body. Moreover, you can send different
        // responses according to the error type.        
        return {
            mediaType: "application/org+json",
            body: { message : err.message() }
        };
    }
}

// Creates a new `ResponseErrorInterceptor`.
ResponseErrorInterceptor responseErrorInterceptor = new;

// A `ResponseErrorInterceptor` can be configured at the listener level or 
// service level. Listener-level error interceptors can handle any error associated 
// with the listener, whereas, service-level error interceptors can only handle
// errors occurred during the service execution.
listener http:Listener interceptorListener = new http:Listener(9090, config = { 
    // To handle all of the errors, the `ResponseErrorInterceptor` is added as a first
    // interceptor as it has to be executed last.
    interceptors: [responseErrorInterceptor] 
});

service / on interceptorListener {

    // If the request does not include a `checkHeader`, then, this will return an error
    // and the execution will jump to the nearest `ResponseErrorInterceptor`.
    resource function get greeting(@http:Header string checkHeader) 
            returns http:Ok {
        return {
            headers: {
                "checkedHeader" : checkHeader
            },
            mediaType: "application/org+json",
            body: { message : "Greetings!" }
        };
    }
}

Error handling

Error handling is an integral part of any network program. Errors can be returned by many components such as interceptors, dispatcher, data-binder, security handlers, etc. These errors are often handled by a default handler and sent back as error responses with an entity-body. With the introduction of error interceptors, you can intercept these errors and handle them as you wish. These error interceptors can be placed anywhere in the interceptor pipeline. When there is an error, the execution jumps to the closest error interceptor. For more information, see the HTTP module.

import ballerina/http;
service class ResponseErrorInterceptor {
    *http:ResponseErrorInterceptor;

A ResponseErrorInterceptor service class implementation. It allows you to intercept the errors and handle them accordingly. A ResponseErrorInterceptor service can only have one remote function: interceptResponseError.

    remote function interceptResponseError(error err) 
            returns http:InternalServerError {

The error occurred in the request-response path can be accessed by the mandatory argument : error. The remote function can return a response, which will overwrite the existing error response.

        return {
            mediaType: "application/org+json",
            body: { message : err.message() }
        };
    }
}

In this case, all of the errors are sent as HTTP 500 internal server errors with a customized media type and body. Moreover, you can send different responses according to the error type.

ResponseErrorInterceptor responseErrorInterceptor = new;

Creates a new ResponseErrorInterceptor.

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

A ResponseErrorInterceptor can be configured at the listener level or service level. Listener-level error interceptors can handle any error associated with the listener, whereas, service-level error interceptors can only handle errors occurred during the service execution.

    interceptors: [responseErrorInterceptor] 
});

To handle all of the errors, the ResponseErrorInterceptor is added as a first interceptor as it has to be executed last.

service / on interceptorListener {
    resource function get greeting(@http:Header string checkHeader) 
            returns http:Ok {
        return {
            headers: {
                "checkedHeader" : checkHeader
            },
            mediaType: "application/org+json",
            body: { message : "Greetings!" }
        };
    }
}

If the request does not include a checkHeader, then, this will return an error and the execution will jump to the nearest ResponseErrorInterceptor.

# Run the service.
bal run http_error_handling.bal
# Invoke the service.
curl -v http://localhost:9090/greeting
*   Trying ::1:9090...
* Connected to localhost (::1) port 9090 (#0)
> GET /greeting HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.77.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse.
< HTTP/1.1 500 Internal Server Error
< content-type: application/org+json
< content-length: 53
< server: ballerina
< date: Tue, 19 Apr 2022 10:51:11 +0530
< 
* Connection #0 to host localhost left intact
{"message":"no header value found for 'checkHeader'"}