Overview

As part of the effort for SM-6972 - Getting issue details... STATUS , this is a proposal for implementing a unified global error handling strategy for all SaFi REST APIs.

Types of Exceptions

Any errors resulted from executing controller code will result in an exception being thrown. These exceptions will be handled based on the exception type. At a minimum, we’ll have two levels of exception handling:

  • domain-specific exceptions , like expected business errors or other errors specific (unique) to a domain/microservice

  • generic exceptions, which are common to the entire BE

Domain-specific exceptions will be handled by their respective owning microservice. The generic exceptions will be handled in a global handler, in common/utils and used by all microservices.

Error Codes

All error codes will be documented here: Proposal: Error Codes

For each error, an appropriate HTTP error code must also be used. This document should be well-understood by the FE side, to be able to account for each error code and report it appropriately to the end users. The codes can be used as keys when implementing localization, to uniquely fetch a localized error message to be sent to the end user.

Error Response Format

A unified error response format should be used. Below are two options presented - do not use both in parallel, but instead decide on using a single one, based on the complexity of the errors being caught.

Option 1 - Simple error format, single error returned in response

This option should be enough if errors are kept simple and multi-level errors (composite errors) are not a thing.

{
    "message": "Validation failed",
    "status": 400,
    "code": "VALIDATION_FAILED",
    "path": "/api/v1/my-endpoint?param1=val1",
    "timestamp": "2022-07-14T12:00:00Z",
}

Option 2 - Multiple errors being returned in a single response

This option is necessary when returning errors from a Validation API or when erroring out from batch processing. In other cases, this might be overkill, so this should be used only if this more complex format is needed.

The error response will be in JSON format:

{
    "message": "Validation failed",
    "status": 400,
    "code": "VALIDATION_FAILED",
    "path": "/api/v1/my-endpoint?param1=val1",
    "timestamp": "2022-07-14T12:00:00Z",
    "errors": [
        {
            "code": "VALIDATION_FAILED",
            "message": "Validation failed for parameter param1",
            "parameter": "param1"
        },
        {
            "code": "VALIDATION_FAILED",
            "message": "Validation failed for object='exampleRequestBody'. Error count: 2",
            "fieldErrors": [
                {
                    "code": "INVALID_SIZE",
                    "field": "name",
                    "message": "size must be between 10 and 2147483647",
                    "rejectedValue": ""
                },
                {
                    "code": "REQUIRED_NOT_BLANK",
                    "field": "favoriteMovie",
                    "message": "must not be blank",
                    "rejectedValue": null
                }
            ]
        },
        {
            "code": "GENERIC_ERROR",
            "message": "Something went wrong",
            "stacktrace": "Filtered stacktrace enabled by a flag only for debugging purposes"
        }
    ]
}

More info about error formats can be found here: Proposal: Global Error Handling

In order to support the error response structure above and also keep it extendable, the following class hierarchy is proposed, where new error formats can be added:

Altering the error response format based on environment

This can be done by using environment variables (or values fetched from HC Vault) and alter the format to be returned. For example, the stacktrace can be hidden from the response sent to FE, if the environment is PROD or STAGE.

Logging

All exceptions must be properly logged in the exception handler, in the same unified JSON format. For debugging purposes, be as verbose as possible. Avoid logging PII data in higher environments (can be filtered based on env variable value).

Implementation Guideline