Quickstart
From empty project to your first standard error response in five minutes.
1. Add two dependencies
Maven:
<dependency>
<groupId>io.github.othmaneataallah</groupId>
<artifactId>problem-details-core</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>io.github.othmaneataallah</groupId>
<artifactId>problem-details-jackson</artifactId>
<version>0.1.0</version>
</dependency>
Gradle:
implementation "io.github.othmaneataallah:problem-details-core:0.1.0"
implementation "io.github.othmaneataallah:problem-details-jackson:0.1.0"
2. Describe an error
ProblemDetail problem = ProblemDetail.builder()
.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.")
.build();
Every field is optional. Skip type and it becomes about:blank — a blank problem with no special meaning, which is exactly what you want for one-off errors. What each field means →
3. Send it as JSON
JsonMapper mapper = JsonMapper.builder()
.addModule(new ProblemDetailsModule())
.build();
String json = mapper.writeValueAsString(problem);
Your client receives application/problem+json:
{
"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."
}
4. Throw it in a real app
throw new ProblemDetailException(problem);
In Spring, one registered advice turns that into the HTTP response. In Jakarta REST, two registered providers do the same. No message parsing anywhere — the structured error travels with the exception.
What next?
- Your errors carry extra data (balances, field errors)? Core concepts shows how to add typed fields.
- Reusing an error type instead of inventing one? Registry.
- XML instead of JSON? XML.
- Prefer learning by running? Demos.