Error Handling
Okapi provides a flexible error handling system with built-in support for standard JSON errors, custom error formats, and RFC 7807 Problem Details.
Quick Start
Use c.Abort* methods to immediately stop request processing and return an error response:
o := okapi.Default()
o.Post("/books", func(c okapi.C) error {
book := &Book{}
if err := c.Bind(book); err != nil {
return c.AbortBadRequest("Invalid request body", err)
}
// ... handle valid request
return c.Created(book)
})
Response:
{
"code": 400,
"message": "Invalid request body",
"details": "field Name is required",
"timestamp": "2026-02-09T21:34:17.290908+01:00"
}
Available Error Methods
Okapi provides convenience methods for common HTTP error codes:
| Method | Status Code | Use Case |
|---|---|---|
AbortBadRequest(msg, err) | 400 | Validation errors, malformed requests |
AbortUnauthorized(msg, err) | 401 | Missing or invalid authentication |
AbortForbidden(msg, err) | 403 | Insufficient permissions |
AbortNotFound(msg, err) | 404 | Resource not found |
AbortConflict(msg, err) | 409 | Resource conflicts |
AbortInternalServerError(msg, err) | 500 | Unexpected server errors |
| And more |
For other status codes, use the generic method:
return c.AbortWithError(http.StatusTeapot, err)
Custom Error Handlers
Override the default error format by providing a custom error handler:
o := okapi.Default().With(
okapi.WithErrorHandler(func(c *okapi.Context, code int, message string, err error) error {
return c.JSON(code, map[string]any{
"success": false,
"error": map[string]any{
"code": code,
"message": message,
"details": err.Error(),
},
})
}),
)
Response:
{
"success": false,
"error": {
"code": 400,
"message": "Invalid request body"
}
}
RFC 7807 Problem Details
For APIs requiring standards-compliant error responses, Okapi supports RFC 7807 Problem Details.
Basic Setup
o := okapi.Default()
o.WithSimpleProblemDetailErrorHandler()
Response (Content-Type: application/problem+json):
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "field Name is required",
"instance": "/books"
}
Advanced Configuration
Customize the Problem Details output with additional fields and options:
o := okapi.Default()
o.WithProblemDetailErrorHandler(&okapi.ErrorHandlerConfig{
Format: okapi.ErrorFormatProblemJSON,
TypePrefix: "https://api.example.com/errors/",
IncludeInstance: true,
IncludeTimestamp: true,
CustomFields: map[string]any{
"api_version": "v1.0.0",
"support_url": "https://support.example.com",
},
})
Response:
{
"type": "https://api.example.com/errors/bad-request",
"title": "Bad Request",
"status": 400,
"detail": "field Name is required",
"instance": "/books",
"timestamp": "2026-02-09T21:42:49+01:00",
"api_version": "v1.0.0",
"support_url": "https://support.example.com"
}
Configuration Options
| Option | Description |
|---|---|
Format | Response format (see below) |
TypePrefix | Base URL for error type URIs |
IncludeInstance | Include the request path in responses |
IncludeTimestamp | Add a timestamp to each error |
CustomFields | Additional fields to include in all error responses |
Supported Formats
| Format | Content-Type | Description |
|---|---|---|
ErrorFormatProblemJSON | application/problem+json | RFC 7807 JSON format (default) |
ErrorFormatProblemXML | application/problem+xml | RFC 7807 XML format |
Example with XML format:
o.WithProblemDetailErrorHandler(&okapi.ErrorHandlerConfig{
Format: okapi.ErrorFormatProblemXML,
})
Response (Content-Type: application/problem+xml):
<?xml version="1.0" encoding="UTF-8"?>
<problem xmlns="urn:ietf:rfc:7807">
<type>about:blank</type>
<title>Bad Request</title>
<status>400</status>
<detail>field Name is required</detail>
<instance>/books</instance>
</problem>