SkillAgentSearch skills...

ConsistentApiResponseErrors

A .NET Core middleware that centralizes the handling of input-validation errors, application exceptions and unhandled exceptions.

Install / Use

/learn @ikyriak/ConsistentApiResponseErrors
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Consistent API Response Errors (CARE) <sup>BETA</sup>

Introduction

Designing APIs is an important and complex process with many decisions involved that organizes and hides the complexity of software [.NET Nakama (2020, August)]. Τhis is accomplished by applying the principle of information hiding, which is the process of hiding the complexity of a piece of software (that is most likely to change) into modules of functionality. This will protect other parts of the software from extensive modifications. The following two important practices (among others) can be followed when designing Web APIs:

  • Make its users (i.e. API consumers) and us happy. We have to understand the challenges of the API consumers (e.g. their limitations, specific needs, etc.) and try to help them by providing a user-friendly API.
  • Design APIs with consistent behavior (e.g. consistent use of the HTTP verbs in REST, consistent Error Handling with useful information, etc.).

APIs with consistent behavior can simplify the consumers implementation and make them happy for using our APIs. Using the HTTP error statuses (such as 4xx Client Errors and 5xx Server Errors) is a good start, but sometimes this is not sufficient to describe the different Web APIs errors. So, additional data that contains information about the problem details are needed (such as, an error-code, the data field that produced the error, etc.).

Let’s have a minute and think if we, as API designers, are really trying to understand our API consumer’s needs regarding error responses. They may be using different libraries or programming languages (they may even use JavaScript 😛). Also, let’s think about what we, as API consumers, would like from an API regarding error responses. What would make us happy?

For me, consistent and structured response-bodies on errors would make me happy because I could build and maintain usable and predictable APIs and consumers. For that reason, I started an effort to create the Consistent API Response Errors (CARE) open-source NuGet library, which handles all errors and provide consistent error responses by using an alternative "problem detail" definition with useful information.

Let's start by investigating the RFC7807, which defines a "problem detail" as a way to carry machine-readable details of errors in an HTTP response. Then, we will see details about the CARE code and how to use the CARE library in an ASP.NET Core API project.

RFC7807 - The Problem Details Response Format

The RFC7807 of the Internet Engineering Task Force (IETF) defines a standard format for the "problem detail" as a way to carry machine-readable details of errors in an HTTP response to avoid the need to define new error response formats for HTTP APIs.

ASP.NET Core supports by default the RFC7807 to specify errors in HTTP API responses, by using the ProblemDetails class.

The RFC7807 defines two document formats for the problem detail as JSON or XML. Depending on the selected problem detail format, the following media types are represented as a Content-Type header:

The main problem details object can have the following members:

  • type (string): A URI reference that identifies the problem type. This URI should return human-readable documentation for the problem type (e.g. using HTML).
  • title (string): A short, human-readable summary of the problem type.
  • detail (string): A longer, human-readable explanation specific to this occurrence of the problem.
  • instance (string): A URI reference of the specific instance that the problem has occurred.
  • status (number): The actual HTTP status code response as it is generated by the origin server for this occurrence of the problem.

The following code example shows a possible error by using the main RFC7807 error format, for a scenario in which the user’s account doesn't have enough credit.

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
    "type": "https://example.com/probs/out-of-credit",
    "title": "You do not have enough credit.",
    "detail": "Your current balance is 30, but that costs 50.",
    "instance": "/account/12345/msgs/abc",
    "status": 403,
}

The main problem details object can be extended with additional members for a specific problem. So, these extended members are not pre-defined and can be any data that are related to a specific error. For example, the previous error can be extended to include the account's “balance” and a list of URI accounts to deposit. The following code example shows an RFC7807 error with the two aforementioned extensions.

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
    "type": "https://example.com/probs/out-of-credit",
    "title": "You do not have enough credit.",
    "detail": "Your current balance is 30, but that costs 50.",
    "instance": "/account/12345/msgs/abc",
    "balance": 30,
    "accounts": [
        "/account/12345",
        "/account/67890"
    ]
}

The extensions are commonly used for specific client needs (for example, show the remaining balance). The clients (i.e. API consumers) should ignore any extensions that they don't recognize. One of these needs is the validation errors details about the input request. The following code shows an example of such a case.

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Content-Language: en

{
    "type": "https://example.net/validation-error",
    "title": "Your request parameters didn't validate.",
    "invalid-params": [
        {
            "name": "age",
            "reason": "must be a positive integer"
        },
        {
            "name": "color",
            "reason": "must be 'green', 'red' or 'blue'"
        }
    ]
}

Consistent API Response Errors (CARE)

The RFC7807 provides a very good definition of the problem details and by using extensions it can be adapted for different API consumer’s needs. It is created to avoid the need of defining new error response formats for HTTP APIs. From my perspective, the issues of RFC7807 are that it is too generic (even for many common error cases such as validation errors) and doesn’t contain much useful information for the API consumers.

The Consistent API Response Errors (CARE), which is inspired from the RFC7807, is an effort to provide even more standardized problem details responses (for example, for validation errors) by creating an open-source NuGet library to:

  • Centralize the handling of the following error types (see Table 1 for details):
    • Validation errors,
    • Application exceptions and
    • Unhandled exceptions.
  • Return consistent and useful error information.
  • Simplify the API controllers by containing only the calls for the appropriate business-logic services (without the need of boilerplate input-validators and try-catch).

Table 1. - The type of errors that are handled by the CARE library.

| Error Type | Description | | :--------------------: | ------------------------------------------------------------ | | Validation Errors | It is providing details about the validation errors of the input request. The FluentValidation library can be used to define the validation rules. | | Application Exceptions | Dev-defined exceptions that are thrown to provide details about application-specific or business logic issues. | | Unhandled Exceptions | Exceptions are thrown when a non-recoverable error has occurred. These are common exceptions that are thrown by the .NET Common Language Runtime. |

The aforementioned error types are handled by CARE providing the following two problem details response formats, which we will examine in the following sections.

  • General Response Error Format.
  • Validation Response Errors Format.

General Response Error Format

The CARE library provides the ApiBaseException class to handle the Application API exceptions, which can be used to map an HTTP status code per application exception. The HTTP status code of the Unhandled exceptions is set by default to 500 (Internal Server Error). The following table presents the fields of the error response format for the Application and Unhandled exceptions when using the CARE library.

| Field | Type | Description | | ------------- | -------- | ------------------------------------------------------------ | | statusCode | Integer | The HTTP status code. The StatusCode and StatusMessage fields would come in handy when someone is testing the API via browser. | | statusMessage | String | The HTTP status message. | | traceId | String | A Unique Id that can be used to trace the error in your logging system for additional information (e.g. to see the Stack-Trace). | | errorMessage | String | A short human-readable string that describes the error. |

The following example presents the general error format for application and unhandled exceptions:

Related Skills

View on GitHub
GitHub Stars29
CategoryDevelopment
Updated1y ago
Forks7

Languages

C#

Security Score

75/100

Audited on Jan 11, 2025

No findings