7.1.7 Bind Errors

Often you want to consume an endpoint and bind to a POJO if the request is successful or bind to a different POJO if an error occurs. The following example shows how to invoke exchange with a success and error type.

  1. @Controller("/books")
  2. public class BooksController {
  3. @Get("/{isbn}")
  4. public HttpResponse find(String isbn) {
  5. if (isbn.equals("1680502395")) {
  6. Map<String, Object> m = new HashMap<>();
  7. m.put("status", 401);
  8. m.put("error", "Unauthorized");
  9. m.put("message", "No message available");
  10. m.put("path", "/books/"+isbn);
  11. return HttpResponse.status(HttpStatus.UNAUTHORIZED).body(m);
  12. }
  13. return HttpResponse.ok(new Book("1491950358", "Building Microservices"));
  14. }
  15. }
  1. @Controller("/books")
  2. class BooksController {
  3. @Get("/{isbn}")
  4. HttpResponse find(String isbn) {
  5. if (isbn == "1680502395") {
  6. Map<String, Object> m = new HashMap<>()
  7. m.put("status", 401)
  8. m.put("error", "Unauthorized")
  9. m.put("message", "No message available")
  10. m.put("path", "/books/"+isbn)
  11. return HttpResponse.status(HttpStatus.UNAUTHORIZED).body(m)
  12. }
  13. return HttpResponse.ok(new Book("1491950358", "Building Microservices"))
  14. }
  15. }
  1. @Controller("/books")
  2. class BooksController {
  3. @Get("/{isbn}")
  4. fun find(isbn: String): HttpResponse<*> {
  5. if (isbn == "1680502395") {
  6. val m = HashMap<String, Any>()
  7. m["status"] = 401
  8. m["error"] = "Unauthorized"
  9. m["message"] = "No message available"
  10. m["path"] = "/books/$isbn"
  11. return HttpResponse.status<Any>(HttpStatus.UNAUTHORIZED).body(m)
  12. }
  13. return HttpResponse.ok(Book("1491950358", "Building Microservices"))
  14. }
  15. }

  1. @Test
  2. public void afterAnHttpClientExceptionTheResponseBodyCanBeBoundToAPOJO() {
  3. try {
  4. client.toBlocking().exchange(HttpRequest.GET("/books/1680502395"),
  5. Argument.of(Book.class), (1)
  6. Argument.of(CustomError.class)); (2)
  7. } catch (HttpClientResponseException e) {
  8. assertEquals(HttpStatus.UNAUTHORIZED, e.getResponse().getStatus());
  9. Optional<CustomError> jsonError = e.getResponse().getBody(CustomError.class);
  10. assertTrue(jsonError.isPresent());
  11. assertEquals(401, jsonError.get().status);
  12. assertEquals("Unauthorized", jsonError.get().error);
  13. assertEquals("No message available", jsonError.get().message);
  14. assertEquals("/books/1680502395", jsonError.get().path);
  15. }
  16. }
  1. def "after an HttpClientException the response body can be bound to a POJO"() {
  2. when:
  3. client.toBlocking().exchange(HttpRequest.GET("/books/1680502395"),
  4. Argument.of(Book), (1)
  5. Argument.of(CustomError)) (2)
  6. then:
  7. def e = thrown(HttpClientResponseException)
  8. e.response.status == HttpStatus.UNAUTHORIZED
  9. when:
  10. Optional<CustomError> jsonError = e.response.getBody(CustomError)
  11. then:
  12. jsonError.isPresent()
  13. jsonError.get().status == 401
  14. jsonError.get().error == 'Unauthorized'
  15. jsonError.get().message == 'No message available'
  16. jsonError.get().path == '/books/1680502395'
  17. }
  1. "after an httpclient exception the response body can be bound to a POJO" {
  2. try {
  3. client.toBlocking().exchange(HttpRequest.GET<Any>("/books/1680502395"),
  4. Argument.of(Book::class.java), (1)
  5. Argument.of(CustomError::class.java)) (2)
  6. } catch (e: HttpClientResponseException) {
  7. e.response.status shouldBe HttpStatus.UNAUTHORIZED
  8. }
  9. }
1Success Type
2Error Type