Featured image of post REST APIs Error Handling

REST APIs Error Handling

Using Problem Details in REST Apis

Problem Details in C# .NET Core: Simplifying Error Handling

When building APIs, handling errors effectively is crucial for providing a good developer experience. One of the best ways to standardize error responses in your API is by using Problem Details. Problem Details is a standardized format for describing HTTP API errors based on the RFC 7807 specification.

What Are Problem Details?

Problem Details is a standardized way to describe errors in HTTP APIs. It provides a consistent structure for error responses, making it easier for clients to understand and handle errors. A typical Problem Details response looks like this:

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

Here’s what each field means:

  • type: A URI reference that identifies the problem type.
  • title: A short, human-readable summary of the problem.
  • status: The HTTP status code for the response.
  • detail: A human-readable explanation of the problem.
  • instance: A URI reference that identifies the specific occurrence of the problem.

Why Use Problem Details?

  1. Standardization: Problem Details follow a well-defined standard (RFC 7807), making it easier for clients to parse and handle errors consistently.
  2. Rich Error Information: It provides more context about errors, such as a detailed message and a link to documentation.
  3. Improved Developer Experience: Clients can programmatically handle errors and provide better feedback to end-users.

Using Problem Details in .NET Core

.NET Core makes it incredibly easy to use Problem Details. Here’s how you can implement it in your application:

1. Enable Problem Details Middleware

You can write your own middleware or use something like Hellang.Middleware.ProblemDetails to convert error into problem details.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;

var builder = WebApplication.CreateBuilder(args);

// Add Problem Details
builder.Services.AddProblemDetails(options => {
  options.IncludeExceptionDetails = (ctx, ex) => builder.Environment.IsDevelopment();
  options.Map<UserNotFoundException>(ex => new ProblemDetails
    {
        Title = "Could not find user",
        Status = StatusCodes.Status404NotFound,
        Detail = ex.Message,
    });
});

var app = builder.Build();

// Use Problem Details middleware
app.UseProblemDetails();

app.MapGet("/", () => "Hello, World!");

app.Run();

Using this approach, you can configure how errors are transformed into a structured problem format within your code.

2. Return Problem Details in Controllers

You can return Problem Details directly from your controllers using the Problem() method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class SampleController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        if (id < 1)
        {
            return Problem(
                title: "Invalid ID",
                detail: "The ID must be greater than 0.",
                statusCode: StatusCodes.Status400BadRequest
            );
        }

        return Ok(new { Message = "Valid ID" });
    }
}

In this example, if the id is less than 1, the API returns a Problem Details response with a 400 Bad Request status.

3. Customize Problem Details

You can customize the Problem Details response by extending the ProblemDetails class:

1
2
3
4
public class CustomProblemDetails : ProblemDetails
{
    public string CustomField { get; set; }
}

Then, return your custom Problem Details in your controller:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[HttpGet("custom-error")]
public IActionResult GetCustomError()
{
    var problem = new CustomProblemDetails
    {
        Title = "Custom Error",
        Detail = "This is a custom error response.",
        Status = StatusCodes.Status400BadRequest,
        CustomField = "Additional custom information"
    };

    return BadRequest(problem);
}

Problem Details provide a clean, standardized way to handle errors in your .NET Core APIs. By using the built-in support for Problem Details, you can ensure that your API responses are consistent, informative, and easy to understand for clients. Whether you’re handling validation errors, exceptions, or custom business logic errors, Problem Details can simplify your error-handling process and improve the overall quality of your API.

Built with Hugo
Theme Stack designed by Jimmy