Handling API Errors Gracefully: Problem JSON (RFC 7807) + Spring Boot
- 4.3/5
- 89
- Jul 12, 2025
What is Problem JSON?
Problem is a standardized format for expressing HTTP API errors, defined in RFC 7807. It allows APIs to return consistent, machine-readable error responses with meaningful human context.
Instead of inventing your own structure every time your API throws an error, Problem JSON gives you a consistent format like:
HTTP Example
This shows how a server responds using standard HTTP headers when an error occurs.
HTTP/1.1 400 Content-Type: application/problem+json Transfer-Encoding: chunked Date: Sat, 12 Jul 2025 08:47:50 GMT Connection: close
JSON Example
This is the actual body of the error response returned by the API.
{
"type": "https://example.com/invalid-employee-id",
"title": "Bad Request",
"status": 400,
"detail": "Employee ID must be a positive number.",
"instance": "/api/employees/-5"
}
Why Use Problem JSON?
When designing APIs, consistency and clarity in error handling are just as important as the successful responses. Problem JSON helps you standardize how errors are communicated between your backend and frontend systems.
Below are the key reasons why adopting Problem JSON can improve your API's robustness and developer experience.
- Standardized – Follows RFC 7807, ensuring interoperability across services.
- Machine-readable + human-friendly – Developers and UIs can both understand it clearly.
- Easily extended with custom fields – Add extra context like
balance
,invalid-params
, etc. - Improves API consistency – One format across all your error responses.
- Works well with frontend frameworks – Frontend tools (like React, Angular) can parse it easily.
Problem JSON Fields
The table below outlines the standard fields defined by RFC 7807 for Problem JSON responses. While the core fields are standardized, you're free to include additional custom fields to provide extra context—like validation errors, user roles, or account balances.
Field | Type | Description |
---|---|---|
type |
URI | A URI identifier for the error type. Can point to documentation. |
title |
string | Short, human-readable summary of the problem. |
status |
number | HTTP status code. |
detail |
string | Detailed human-readable message. |
instance |
URI | A URI that identifies the specific request instance. |
(custom) | any | You can add custom fields freely (e.g., balance , invalid-params ). |
Spring Boot Implementation with Problem JSON
We'll build a REST API that uses Problem JSON to return standard and custom Problem JSON responses in a Spring Boot application.
HTTP Status | Scenario |
---|---|
200 OK |
Successfully fetched employee details |
400 Bad Request |
Invalid input format |
404 Not Found |
Employee ID not found |
422 Unprocessable Entity |
Business rule violation (e.g., duplicate email) |
500 Internal Server Error |
Unexpected server-side error |
Zalando’s problem-spring-web
is a library that allows Spring Boot applications to produce standardized error responses using RFC 7807.
It automatically converts exceptions to
application/problem+json
format and gives your APIs predictable and extensible error responses.
1. Add Dependencies
<dependency> <groupId>org.zalando</groupId> <artifactId>problem-spring-web</artifactId> <version>0.29.1</version> </dependency> <dependency> <groupId>org.zalando</groupId> <artifactId>jackson-datatype-problem</artifactId> <version>0.27.1</version> </dependency>
2. Create Global Exception Handler
This will automatically handle Spring exceptions like validation errors, not found, access denied, etc., using Problem JSON format.
3. Sample Controller
This example demonstrates how to use problem-spring-web
to handle various HTTP responses (200, 400, 404, 422, 500) in a standardized Problem JSON (RFC 7807) format.
4. Testing
This guide shows how to test different responses from the /api/employees
endpoint using curl, Postman, JUnit + MockMvc, and Swagger UI.
1. Using curl
# ✅ 200 OK
curl -i http://localhost:8080/api/employees/1
HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Sat, 12 Jul 2025 08:38:57 GMT {"id":1,"name":"John Doe"}
# ❌ 400 Bad Request
curl -i http://localhost:8080/api/employees/-5
HTTP/1.1 400 Content-Type: application/problem+json Transfer-Encoding: chunked Date: Sat, 12 Jul 2025 08:47:50 GMT Connection: close {"type":"https://example.com/invalid-employee-id","title":"Bad Request","status":400,"detail":"Employee ID must be a positive number.","instance":"/api/employees/-5"}
# ❌ 404 Not Found
curl -i http://localhost:8080/api/employees/99
HTTP/1.1 404 Content-Type: application/problem+json Transfer-Encoding: chunked Date: Sat, 12 Jul 2025 08:49:00 GMT {"type":"https://example.com/employee-not-found","title":"Employee Not Found","status":404,"detail":"No employee exists with ID: 99","instance":"/api/employees/99"}
# ❌ 422 Unprocessable Entity
curl -i -X POST -H "Content-Type: application/json" \ -d '{"email":"existing@example.com"}' \ http://localhost:8080/api/employees
HTTP/1.1 422 Content-Type: application/problem+json Transfer-Encoding: chunked Date: Sat, 12 Jul 2025 08:49:30 GMT {"type":"https://example.com/email-already-registered","title":"Email Already Registered","status":422,"detail":"The email 'existing@example.com' is already used by another employee.","instance":"/api/employees"}%
# ❌ 500 Internal Server Error
curl -i -X POST -H "Content-Type: application/json" \ -d '{"email":"trigger500@example.com"}' \ http://localhost:8080/api/employees
HTTP/1.1 500 Content-Type: application/problem+json Transfer-Encoding: chunked Date: Sat, 12 Jul 2025 08:50:01 GMT Connection: close {"title":"Internal Server Error","status":500,"detail":"Simulated internal error."}
2. Using JUnit + MockMvc
3. Using Swagger UI
If you've added Swagger/OpenAPI via springdoc-openapi
, you can test endpoints visually:
- Ensure you have this dependency:
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.1.0</version> </dependency>
- Run your app and open: http://localhost:8080/swagger-ui.html
- Try out
GET /api/employees/{id}
andPOST /api/employees
- Swagger will show you both success and error responses with full JSON bodies.
Conclusion
The problem-spring-web
library is the easiest and most robust way to integrate RFC 7807 Problem JSON error responses in Spring Boot. It keeps your API consistent, descriptive, and frontend-friendly — without repetitive boilerplate code.
Source Code: GitHub