Как отправить HttpStatus из использованного сервиса REST из другого сервиса REST - PullRequest
0 голосов
/ 09 мая 2019

Проблема:

Мое REST-приложение использует другое REST-приложение, поскольку оно является "хабом" для нескольких других приложений.

Когда запрос к этому "концентратору" создает HttpClientErrorException в одном из других приложений REST, которыми он управляет, я хочу, чтобы StatusCode (с сообщением) был представлен пользователю моего "концентратора", а не просто ошибка стандартного внутреннего сервера 500 ...

Как это можно сделать?

Я использую Spring-Boot 2.1.4 для моего REST-приложения "хаб", которое отправляет запросы другим REST-приложениям ...

Простой тестовый пример с пружинной загрузкой:

@Test
@SuppressWarnings("unchecked")
@DisplayName("should use original rest exception")
void shouldUseRestException() {
  when(restTemplateMock.exchange(anyString(), any(), any(), any(ParameterizedTypeReference.class)))
      .thenThrow(new HttpClientErrorException(HttpStatus.I_AM_A_TEAPOT, "holy crap!"));

  assertThatExceptionOfType(RestClientException.class).isThrownBy(() -> testRestTemplate.exchange(
      url("/1001"), HttpMethod.GET, null, listOfMyGenericTypes()
  )).withMessage("Http client says: holy crap!");
}

Мой RestControllerAdvice:

@RestControllerAdvice
public class HubControllerAdvice {

  @ResponseBody
  @ExceptionHandler
  public ResponseEntity<Object> handleHttClientErrorException(HttpClientErrorException httpClientErrorException) {
    throw new HttpClientErrorException(httpClientErrorException.getStatusCode(), "Http client says: " + httpClientErrorException.getMessage());
  }
}

Ошибка JUnit:

org.opentest4j.AssertionFailedError: 
Expecting message:
 <"Http client says: holy crap!">
but was:
 <"Error while extracting response for type [java.util.List<MyGenericType>] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
 at [Source: (PushbackInputStream); line: 1, column: 1]">

У меня есть рабочее решение, но это изменит поведение службы, и я бы очень хотел этого избежать. Это фактически возвращает объект ответа с кодом состояния исключения в качестве заголовка в моем API ... хотя это работает (см. Ниже), требуется, чтобы пользователи моего концентратора изменили свои ожидания относительно того, как он работает:

Мой RestControllerAdvice:

@RestControllerAdvice
public class BidragDokumentRestControllerAdvice {

  @ResponseBody
  @ExceptionHandler
  public ResponseEntity<Object> handleHttClientErrorException(HttpClientErrorException httpClientErrorException) {
    return ResponseEntity
        .status(httpClientErrorException.getStatusCode())
        .header(HttpHeaders.WARNING, "Http client says: " + httpClientErrorException.getMessage())
        .build();
  }
}

Мой теперь работающий тест JUnit:

@Test
@SuppressWarnings("unchecked")
@DisplayName("should return empty response with original exception warning")
void shouldReturnEmptyResponseWithOriginalExceptionWarning() {
  when(restTemplateMock.exchange(anyString(), any(), any(), any(ParameterizedTypeReference.class)))
      .thenThrow(new HttpClientErrorException(HttpStatus.I_AM_A_TEAPOT, "holy crap!"));

  var errorResponser = testRestTemplate.exchange(
      url("/1001"), HttpMethod.GET, null, listOfMyGenericTypes()
  );
  assertThat(Optional.of(errorResponse)).hasValueSatisfying(responseEntity -> assertAll(
      () -> assertThat(responseEntity.getStatusCode()).as("status").isEqualTo(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED),
      () -> assertThat(responseEntity.getBody()).as("body").isNull(),
      () -> {
        HttpHeaders httpHeaders = errorResponse.getHeaders();

        assertAll(
            () -> assertThat(httpHeaders.get(HttpHeaders.WARNING)).as("warning header").isNotNull(),
            () -> assertThat(httpHeaders.get(HttpHeaders.WARNING)).as("header value").isEqualTo(List.of("Http client says: 509 holy crap!"))
        );
      }
  ));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...