Skip to content

Commit 49d2a80

Browse files
committed
chore: clean codes
1 parent e2bb07b commit 49d2a80

File tree

2 files changed

+46
-9
lines changed

2 files changed

+46
-9
lines changed

docs/problem-detail.md

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# An Introduction to Spring ProblemDetails Support
2-
When building REST API backend applications, developers often create custom wrappers, such as `ApiResult` or `ErrorResponse`, to standardize response formats within their projects. However, these solutions are not portable across different systems. As a developer, I find it frustrating to handle various response formats when integrating with other third-party APIs.
32

4-
[Spring HATEOAS](https://spring.io/projects/spring-hateoas) adopts the [VndError draft proposal](https://github.com/blongden/vnd.error) to represent REST response messages. While Spring HATEOAS is mainly focused on building hypermedia-driven APIs, it also helps applications reach the Richardson Maturity Model Level 3.
3+
When building REST API backends, developers often create custom wrappers, such as `ApiResult` or `ErrorResponse` to standardize response formats within their projects. However, these solutions are rarely portable across different systems. As a developer, I find it frustrating to handle various response formats when integrating with third-party APIs.
54

6-
Another widely accepted format is Problem Details, standardized by the IETF as [RFC9457](https://www.rfc-editor.org/rfc/rfc9457.html). Problem Details for HTTP APIs (also known as Problem Details) defines a consistent, machine-readable structure for representing error conditions in HTTP responses. This specification enables clients to interpret and handle errors uniformly, simplifying integration and improving interoperability across different systems.
5+
[Spring HATEOAS](https://spring.io/projects/spring-hateoas) adopts the [VndError draft proposal](https://github.com/blongden/vnd.error) to represent REST response messages. While Spring HATEOAS primarily focuses on building hypermedia-driven APIs, it also helps applications reach Level 3 of the Richardson Maturity Model.
76

8-
Building on these industry standards, Spring 6 has introduced native support for ProblemDetails, making it easier for developers to adopt this consistent error format in their applications.
7+
Another widely accepted format is Problem Details, standardized by the IETF as [RFC9457](https://www.rfc-editor.org/rfc/rfc9457.html). Problem Details for HTTP APIs defines a consistent, human being friendly and readable structure for representing error conditions in HTTP responses. This specification enables clients to interpret and handle errors uniformly, simplifying integration and improving interoperability across different systems.
98

10-
Let's take a closer look at the new [`ProblemDetail`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ProblemDetail.html) class that was introduced in Spring 6, which is just a POJO and includes several fields defined by RFC 9457:
9+
Finally Spring 6 adds native support for ProblemDetails, making it easier for developers to adopt this consistent error format in their applications.
10+
11+
Let’s take a closer look at the new [`ProblemDetail`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ProblemDetail.html) class introduced in Spring 6. This POJO includes several fields defined by RFC 9457:
1112

1213
* `type` – A URI identifying the problem type
1314
* `status` – The HTTP status code
@@ -18,7 +19,7 @@ Let's take a closer look at the new [`ProblemDetail`](https://docs.spring.io/spr
1819

1920
The `ProblemDetail` class provides two convenient factory methods: `forStatus(HttpStatus status)` and `forStatusAndDetail(HttpStatusCode status, String detail)`, making it easy to create ProblemDetail objects.
2021

21-
In a Spring WebMvc or WebFlux project, you can assemble error responses using `@ExceptionHandler` methods in a `@ControllerAdvice/@RestControllerAdvice` bean, update the method returns a `ResponseEntity<ProblemDetail>` or `ProblemDetail`.
22+
In a Spring WebMvc or WebFlux project, you can assemble error responses using `@ExceptionHandler` methods in a `@ControllerAdvice` or `@RestControllerAdvice` bean. These methods can return either a `ResponseEntity<ProblemDetail>` or a `ProblemDetail` directly:
2223

2324
```java
2425
@RestControllerAdvice
@@ -50,6 +51,33 @@ When an exception is handled, the response is rendered with the content type `ap
5051
"instance": "/api/posts/xxxx"
5152
}
5253
```
54+
55+
When using the Jackson library, custom properties added to the `properties` map are serialized as top-level JSON fields, thanks to the `ProblemDetailJacksonMixin`. For example, if you set custom properties via `setProperty("errors", obj)`:
56+
57+
```java
58+
detail.setProperty("errors",
59+
List.of(
60+
Map.of("path", "title", "detail", "Cannot be empty")
61+
)
62+
);
63+
```
64+
65+
The resulting response will include the custom `errors` field at the top level:
66+
67+
```json
68+
{
69+
// ...
70+
"status": 400,
71+
"instance": "/api/posts/xxxx",
72+
"errors": [
73+
{
74+
"path": "title",
75+
"detail": "Cannot be empty"
76+
}
77+
]
78+
}
79+
```
80+
5381
You can explore the complete [sample code](https://github.com/hantsy/spring6-sandbox/tree/master/problem-details) on GitHub.
5482

5583
To enable ProblemDetails support in a Spring Boot project, add the following properties to your *application.properties* file:
@@ -62,12 +90,12 @@ spring.mvc.problemdetails.enabled=true
6290
spring.webflux.problemdetails.enabled=true
6391
```
6492

65-
Once enabled, you can use ProblemDetails as demonstrated above. Additionally, Spring Boot's built-in error handling will also return errors in the ProblemDetails format.
93+
Once enabled, you can use ProblemDetails as demonstrated above. Additionally, Spring Boots built-in error handling will also return errors in the ProblemDetails format.
6694

6795
Before the introduction of native support in Spring 6, developers who wanted to adopt the Problem Details format often turned to [Zalando Problem](https://github.com/zalando/problem). This library, along with its [Spring Web integration](https://github.com/zalando/problem-spring-web), provides comprehensive support for both WebMvc and WebFlux applications.
6896

6997
> [!NOTE]
70-
> Zalando's Problem library and its Spring integration module offer more extensive integration with the Spring ecosystem than the current built-in support in Spring Boot. For instance, it can automatically handle security-related exceptions and Jakarta Validation errors, among other advanced features.
98+
> Zalandos Problem library and its Spring integration module offer more extensive integration with the Spring ecosystem than the current built-in support in Spring Boot. For instance, it can automatically handle security-related exceptions and Jakarta Validation errors, among other advanced features.
7199
72100
---
73101

problem-details/src/main/java/com/example/demo/web/RestExceptionHandler.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import org.springframework.web.bind.annotation.RestControllerAdvice;
99
import org.springframework.web.reactive.result.method.annotation.ResponseEntityExceptionHandler;
1010

11+
import java.util.List;
12+
import java.util.Map;
13+
1114
@RestControllerAdvice
1215
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
1316

@@ -22,6 +25,12 @@ public ResponseEntity<ProblemDetail> handleNotFoundException(PostNotFoundExcepti
2225

2326
@ExceptionHandler(IllegalArgumentException.class)
2427
public ProblemDetail handleIllegalArgumentException(IllegalArgumentException exception) {
25-
return ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, exception.getMessage());
28+
ProblemDetail detail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, exception.getMessage());
29+
detail.setProperty("errors",
30+
List.of(
31+
Map.of("path", "title", "details", "Can not be empty")
32+
)
33+
);
34+
return detail;
2635
}
2736
}

0 commit comments

Comments
 (0)