|
2 | 2 | [](https://sonarcloud.io/dashboard?id=hrytsenko_json-data-spring-boot)
|
3 | 3 | [](https://jitpack.io/#hrytsenko/json-data-spring-boot)
|
4 | 4 |
|
5 |
| -# Summary |
| 5 | +# JSON data for Spring Boot |
6 | 6 |
|
7 |
| -This library enables [json-data] for [Spring Boot] including serialization, validation and error handling for HTTP requests and responses that use JSON entities. |
8 |
| - |
9 |
| -# Example |
10 |
| - |
11 |
| -The following example illustrates: |
12 |
| -* Use of JSON entities with [Spring Boot]. |
13 |
| -* Use of JSON entities with [Spring Feign]. |
14 |
| -* Use of JSON errors with [Spring Boot] and [Spring Sleuth]. |
| 7 | +This library enables [json-data] for [Spring Boot] including serialization, validation and error handling. |
| 8 | +The following example illustrates integration with [Spring Boot], [Spring Feign] and [Spring Sleuth]: |
15 | 9 |
|
16 | 10 | ```java
|
17 | 11 | @EnableFeignClients
|
18 | 12 | @SpringBootApplication
|
19 | 13 | class Application {
|
20 | 14 |
|
21 |
| - static class Request extends JsonEntity<Request> { |
22 |
| - String getOwner() { |
23 |
| - return getString("owner"); |
24 |
| - } |
| 15 | + static class Request extends JsonEntity<Request> { |
| 16 | + String getOwner() { |
| 17 | + return getString("owner"); |
25 | 18 | }
|
26 |
| - |
27 |
| - static class Response extends JsonEntity<Response> { |
| 19 | + } |
| 20 | + |
| 21 | + static class Response extends JsonEntity<Response> { |
| 22 | + } |
| 23 | + |
| 24 | + @RestController |
| 25 | + @AllArgsConstructor |
| 26 | + static class GithubController { |
| 27 | + |
| 28 | + static JsonMapper<Response> TO_RESPONSE = JsonMapper.create( |
| 29 | + JsonResources.readResource("/response-projection.json"), Response::new); |
| 30 | + |
| 31 | + GithubClient githubClient; |
| 32 | + |
| 33 | + @PostMapping( |
| 34 | + value = "/list-repositories", |
| 35 | + consumes = MediaType.APPLICATION_JSON_VALUE, |
| 36 | + produces = MediaType.APPLICATION_JSON_VALUE) |
| 37 | + @ValidateRequest("/request-schema.json") |
| 38 | + @ValidateResponse("/response-schema.json") |
| 39 | + @WrapErrors("CANNOT_LIST_REPOSITORIES") |
| 40 | + public Response listRepositories(@RequestBody Request request) { |
| 41 | + var repositories = githubClient.listRepositories(request.getOwner()); |
| 42 | + return TO_RESPONSE.map(repositories); |
28 | 43 | }
|
29 | 44 |
|
30 |
| - @RestController |
31 |
| - @AllArgsConstructor |
32 |
| - static class GithubController { |
33 |
| - |
34 |
| - static JsonMapper<Response> TO_RESPONSE = JsonMapper.create( |
35 |
| - JsonResources.readResource("/response-projection.json"), Response::new); |
36 |
| - |
37 |
| - GithubClient githubClient; |
38 |
| - |
39 |
| - @PostMapping( |
40 |
| - value = "/list-repositories", |
41 |
| - consumes = MediaType.APPLICATION_JSON_VALUE, |
42 |
| - produces = MediaType.APPLICATION_JSON_VALUE) |
43 |
| - @ValidateRequest("/request-schema.json") |
44 |
| - @ValidateResponse("/response-schema.json") |
45 |
| - @WrapErrors("CANNOT_LIST_REPOSITORIES") |
46 |
| - public Response listRepositories(@RequestBody Request request) { |
47 |
| - val repositories = githubClient.listRepositories(request.getOwner()); |
48 |
| - return TO_RESPONSE.map(repositories); |
49 |
| - } |
50 |
| - |
51 |
| - @FeignClient( |
52 |
| - name = "github-client", |
53 |
| - url = "${github.url}") |
54 |
| - interface GithubClient { |
55 |
| - @GetMapping( |
56 |
| - value = "/users/{owner}/repos", |
57 |
| - produces = MediaType.APPLICATION_JSON_VALUE) |
58 |
| - List<JsonBean> listRepositories(@PathVariable("owner") String owner); |
59 |
| - } |
60 |
| - |
| 45 | + @FeignClient(name = "github-client", url = "${github.url}") |
| 46 | + interface GithubClient { |
| 47 | + @GetMapping( |
| 48 | + value = "/users/{owner}/repos", |
| 49 | + produces = MediaType.APPLICATION_JSON_VALUE) |
| 50 | + List<JsonBean> listRepositories(@PathVariable("owner") String owner); |
61 | 51 | }
|
62 | 52 |
|
63 |
| - @Bean |
64 |
| - public CorrelationSource sleuthSource(Tracer tracer) { |
65 |
| - return () -> tracer.currentSpan().context().traceIdString(); |
66 |
| - } |
| 53 | + } |
67 | 54 |
|
68 |
| - public static void main(String[] args) { |
69 |
| - SpringApplication.run(Application.class, args); |
70 |
| - } |
| 55 | + @Bean |
| 56 | + CorrelationSource sleuthSource(Tracer tracer) { |
| 57 | + return () -> tracer.currentSpan().context().traceId(); |
| 58 | + } |
| 59 | + |
| 60 | + public static void main(String[] args) { |
| 61 | + SpringApplication.run(Application.class, args); |
| 62 | + } |
71 | 63 |
|
72 | 64 | }
|
73 | 65 | ```
|
74 | 66 |
|
75 |
| -# Usage |
76 |
| - |
77 |
| -Use JSON entities with Spring Web and Spring Feign. |
78 |
| - |
79 |
| -Use `ValidateRequest` to validate a JSON entity (the first argument) via JSON Schema. Use `ValidateResponse` to validate a JSON entity (the return value) via JSON Schema. |
80 |
| - |
81 |
| -Use `WrapErrors` to wrap all exceptions in `ServiceException.InternalError` with a given error code, except those that are `ServiceException`. |
| 67 | +Use `ValidateRequest` to validate an input JSON entity (the first argument). |
| 68 | +Use `ValidateResponse` to validate an output JSON entity (the return value). |
| 69 | +Provide `ValidatorSource` to configure a resource manager for validators. |
82 | 70 |
|
| 71 | +Use `WrapErrors` to wrap all unhandled exceptions into `ServiceException.InternalError`. |
83 | 72 | Provide `CorrelationSource` to enable correlations for error responses.
|
84 | 73 |
|
85 |
| -Provide `ValidatorSource` to configure a resource manager for validators. |
86 |
| - |
87 |
| -[json-data]: https://github.com/hrytsenko/json-data |
| 74 | +[json-data]: https://github.com/hrytsenko/json-data |
88 | 75 | [Spring Boot]: https://spring.io/projects/spring-boot
|
89 | 76 | [Spring Feign]: https://spring.io/projects/spring-cloud-openfeign
|
90 | 77 | [Spring Sleuth]: https://spring.io/projects/spring-cloud-sleuth
|
0 commit comments