Skip to content

Exception Handling ​

WiRL provides a robust mechanism for handling exceptions in your web applications. This guide will walk you through the various ways you can manage and customize error responses.

DEMO

You can find a demo demonstrating how to customize exception handling in the demo\20.Exceptions folder.

Default Exception Handling ​

By default, when an exception is raised in a WiRL application, it generates a 500 HTTP status code. The response body will be a JSON object with the following structure:

json
{
  "status": 500,
  "exception": "EDivByZero",
  "message": "Division by zero"
}

The exception field contains the name of the exception class, while the message field contains the exception message.

Custom Exception Responses ​

EWiRLWebApplicationException ​

For more control over the error response, you can use the EWiRLWebApplicationException class. This allows you to specify a custom message and HTTP status code. For example:

pascal
function TDemoResource.GetError: string;
begin
  raise EWiRLWebApplicationException.Create('Invalid input', 400);
end;

This will produce the following JSON response:

json
{
  "status": 400,
  "exception": "EWiRLWebApplicationException",
  "message": "Invalid input"
}

Adding Additional Data ​

EWiRLWebApplicationException also allows you to include additional data in the response. You can do this either by providing a JSON object or by using the fluent ExceptionValue syntax:

pascal
function TDemoResource.GetError: string;
begin
  raise EWiRLWebApplicationException.Create('Invalid input', 400,
    TValuesUtil.MakeValueArray(
      Pair.S('unit', 'Test.pas'), // String value
      Pair.N('Line', 150)         // Numeric value
    )
  );
end;

This will generate the following response:

json
{
  "status": 400,
  "exception": "EWiRLWebApplicationException",
  "message": "Invalid input",
  "data": {
    "unit": "Test.pas",
    "Line": 150
  }
}

The Pair object supports various data types:

  • S for strings
  • N for numeric values
  • D for TDateTime
  • B for boolean values

Pre-defined Exception Classes ​

WiRL provides several pre-defined exception classes that derive from EWiRLWebApplicationException. These classes automatically set the appropriate HTTP status code:

Client Errors ​

  • EWiRLBadRequestException: 400
  • EWiRLNotAuthorizedException: 401
  • EWiRLNotFoundException: 404
  • EWiRLNotAcceptableException: 406
  • EWiRLUnsupportedMediaTypeException: 415

Server Errors ​

  • EWiRLServerException: 500
  • EWiRLNotImplementedException: 501

Exception Mappers ​

In some cases, you might want to associate a specific HTTP error code and response with a particular exception, including standard or third-party exceptions. For instance, you might want to map a dataset's "required field" exception to a 400-series error instead of the default 500.

To achieve this, you can use an exception mapper. Here's how to create and use one:

  1. Create a class that inherits from TWiRLExceptionMapper and implement the HandleException method:
pascal
TFieldRequiredErrorMapper = class(TWiRLExceptionMapper)
public
  procedure HandleException(AExceptionContext: TWiRLExceptionContext); override;
end;

procedure TFieldRequiredErrorMapper.HandleException(
  AExceptionContext: TWiRLExceptionContext);
const
  StatusCode = 400;
var
  MyException: EFieldRequiredError;
  LJSON: TJSONObject;
begin
  inherited;
  MyException := AExceptionContext.Error as EFieldRequiredError;
  LJSON := TJSONObject.Create;
  try
    EWiRLWebApplicationException.ExceptionToJSON(MyException, StatusCode, LJSON);
    LJSON.AddPair(TJSONPair.Create('ErrorCode', TJSONNumber.Create(MyException.ErrorCode)));
    AExceptionContext.Response.StatusCode := StatusCode;
    AExceptionContext.Response.ContentType := 'application/json';
    AExceptionContext.Response.Content := TJSONHelper.ToJSON(LJSON);
  finally
    LJSON.Free;
  end;
end;
  1. Register the exception mapper:
pascal
TWiRLExceptionMapperRegistry.Instance.RegisterExceptionMapper<TFieldRequiredErrorMapper, EFieldRequiredError>();

By using exception mappers, you can customize how WiRL handles specific exceptions, providing more meaningful and appropriate responses to your API clients.

Global exception mapper ​

By registering an exception mapper for the Exception class, you're providing a catch-all handler for any exception that doesn't have a more specific mapper. This allows you to completely customize how WiRL generates error responses for all exceptions. This approach is particularly useful when you want to:

  • Ensure a consistent error response format across your entire application.
  • Add additional debugging information to all error responses.
  • Implement logging or error tracking for all exceptions.
  • Mask internal error details in production environments.