java-restify
1.0.0
1.0.0
  • Visão geral
  • Início
    • Instalação
    • Início rápido
  • Anotações
    • Anotações padrão
    • Extensões
      • JAX-RS
      • Spring Framework
  • Tipos de conteúdo
    • Serialização e deserialização
    • Formatos
      • wildcard
      • application/json
        • Jackson
        • Gson
        • JSON-B
        • JSON-P
      • application/xml
        • JAX-B
      • application/x-www-form-urlencoded
        • Map
        • Parameters
        • @Form
      • multipart/form-data
        • MultipartFile
        • Map
        • MultipartParameters
        • @MultipartForm
      • text/plain
      • text/html
      • application/octet-stream
  • Tipos de retorno de método
    • Visão geral
    • Objetos suportados
    • Extensões
      • Guava
      • Jsoup
      • Frameworks reativos
      • Vavr
      • Spring Framework
  • Requisições assíncronas
    • Visão geral
    • Extensões
      • Apache Async HTTP Client
      • OkHtp
      • Netty
  • Programação reativa
    • Frameworks suportados
      • RxJava (1.x)
      • RxJava (2.x)
      • Project Reactor
  • Manipulação de erros
    • Manipulação de erros
  • Retry
    • Retry
  • Clientes HTTP
    • Visão geral
      • Requisições assíncronas
    • Extensões
      • Jersey HTTP Client
      • Apache HTTP Client
      • Apache Async HTTP Client
      • OkHtp
      • Netty
  • Netflix OSS
    • Hystrix
    • Ribbon
  • Spring Framework
    • Anotações
    • Retornos de método
    • RestTemplate
    • Spring Boot
  • Autenticação
    • Basic
    • OAuth 2
  • Lista de artefatos
    • Artefatos
Powered by GitBook
On this page
  • Requisições assíncronas
  • Recuperação de respostas de erro
  • EndpointResponse

Was this helpful?

  1. Manipulação de erros

Manipulação de erros

O java-restify oferece diferentes abordagens para manipulação e recuperação de erros.

Além dos erros de I/O (comunicação, rede, streams, etc) que podem ocorrer durante a requisiçao HTTP, o java-restify converte respostas HTTP 4xx (client error) e 5xx (server error) para exceções. Esse é o comportamento padrão, mas pode ser customizado para atender diferentes necessidades.

Todas as exceções do java-restify extendem com.github.ljtfreitas.restify.http.client.HttpException. Exceções ocorridas durante a execução do método ou durante a requisição HTTP sempre serão encapsuladas e propagadas em uma exceção do tipo HttpException.

Existem duas especializações dessa exceção:

  • HttpClientException, que representa erros de I/O

  • HttpMessageException, para exceções durante a manipulação da requisição e da resposta.

HttpMessageException possui uma subclasse chamada EndpointResponseException, que representa uma resposta HTTP de erro (status code 4xx ou 5xx). Essa classe possui várias sub-exceções, cada uma representando um status de erro HTTP específico. Isso permite implementar um controle fino para situações específicas:

public interface MyApi {

    @Path("/customers/{id}") @Get
    Customer getCustomerById(@PathParameter String id);
}

MyApi myApi = new RestifyProxyBuilder()
    .target(MyApi.class)
        .build();

try {
    Customer customer = myApi.getCustomerById("abc123");

} catch (EndpointResponseNotFoundException e) {
    // 404 Not Found

} catch (EndpointResponseUnauthorizedException e) {
    // 401 Unauthorized

} catch (EndpointResponseNotAcceptableException e) {
    // 406 Not Acceptable

} catch (EndpointResponseException e) {
    // qualquer outra resposta de erro HTTP

} catch (HttpClientException e) {
    // erros de I/O

}

Requisições assíncronas

Caso a requisição seja assíncrona, o tratamento de falhas deve ser implementado usando o próprio objeto de retorno ou com o uso de callbacks.

Por exemplo, caso o retorno seja um CompletableFuture:

public interface MyApi {

    @Path("/customers/{id}") @Get
    CompletableFuture<Customer> getCustomerById(@PathParameter String id);
}

MyApi myApi = new RestifyProxyBuilder()
    .target(MyApi.class)
        .build();

myApi.getCustomerById("abc123")
        .whenComplete((customer, exception) -> {
            // lógica de falha ou sucesso
        });

Ou utilizando callbacks:

public interface MyApi {

    @Path("/customers/{id}") @Get
    void getCustomerById(@PathParameter String id, @CallbackParameter EndpointCallSuccessCallback<Customer> success, @CallbackParameter EndpointCallFailureCallback failure);
}

MyApi myApi = new RestifyProxyBuilder()
    .target(MyApi.class)
        .build();

myApi.getCustomerById("abc123", 
        customer -> { /* lógica de sucesso */},
        exception -> { /*lógica de falha */});

A interface EndpointCallFailureCallback (representada acima como uma expressão lambda) tem um único método, onFailure, que recebe um Throwable como parâmetro, permitindo o tratamento de qualquer exceção; existe uma especialização chamada EndpointResponseFailureCallback específica para respostas de erro, que permite uma manipulação fina de cada cenário de erro:

public interface MyApi {

    @Path("/customers/{id}") @Get
    void getCustomerById(@PathParameter String id, @CallbackParameter EndpointCallSuccessCallback<Customer> success, @CallbackParameter EndpointResponseFailureCallback failure);
}

MyApi myApi = new RestifyProxyBuilder()
    .target(MyApi.class)
        .build();

EndpointResponseFailureCallback failure = new EndpointResponseFailureCallback() { // classe abstrata

    // sobrescreva os métodos para cada resposta de erro que deseje manipular

    @Override
    protected void onNotFound(EndpointResponse<String> response) {
        // 404 Not Found
    }

    @Override
    protected void onUnauthorized(EndpointResponse<String> response) {
        // 404 Not Found
    }

    @Override
    protected void onNotAcceptable(EndpointResponse<String> response) {
        // 404 Not Found
    }

    protected void onFailure(EndpointResponse<String> response) {
        // qualquer outra resposta de erro HTTP
    }

    protected void onException(Throwable throwable) {
        // qualquer outra exceção, incluindo erros de I/O
    }
};

myApi.getCustomerById("abc123", 
        customer -> { /* lógica de sucesso */},
        failure);

Recuperação de respostas de erro

Além da captura da exceção, através de try/catch ou callback de falha, outra abordagem possível é implementar estratégias para recuperação de respostas de erro.

O objeto EndpointResponseErrorFallback é responsável pela manipulação de respostas 4xx e 5xx, podendo eventualmente retornar outra resposta. A implementação padrão é o comportamento demonstrado acima: a propagação de exceções específicas por tipo de resposta.

Mas implementações dessa interface podem implementar qualquer comportamento sobre respostas de erro. Por exemplo, um caso especial é o status code 404 (Not Found); respostas com esse status podem ser tratadas como uma resposta de corpo vazio, ao invés de uma exceção.

public interface MyApi {

    // a API devolve 404, caso não encontre um Customer com o id
    @Path("/customers/{id}") @Get
    Customer getCustomerById(@PathParameter String id);
}

MyApi myApi = new RestifyProxyBuilder()
    .error()
        .emptyOnNotFound() // respostas 404 serão consideradas como uma resposta sem corpo
    .target(MyApi.class)
        .build();

// se a resposta for 404, o retorno do método será null
Customer customer = myApi.getCustomerById("xyz123");

Uma solução elegante para a situação acima seria utilizar um Optional como retorno de método, representando uma resposta potencialmente vazia:

public interface MyApi {

    // a API devolve 404, caso não encontre um Customer com o id
    @Path("/customers/{id}") @Get
    Optional<Customer> getCustomerById(@PathParameter String id);
}

MyApi myApi = new RestifyProxyBuilder()
    .error()
        .emptyOnNotFound() // respostas 404 serão consideradas como uma resposta sem corpo
    .target(MyApi.class)
        .build();

// se a resposta for 404, o retorno do método será um Optional vazio
Optional<Customer> customer = myApi.getCustomerById("xyz123");

Também é possível implementar qualquer outra lógica para recuperação de respostas 4xx ou 5xx:

class MyResponseErrorFallback implements EndpointResponseErrorFallback {

    @Override
    public <T> EndpointResponse<T> onError(HttpResponseMessage response, JavaType responseType) {
        /* 
            HttpResponseMessage é um objeto de nível mais baixo, que fornece acesso à resposta HTTP "crua".
            O segundo parâmetro representa o tipo de retorno do método.
            Implemente sua lógica de recuperação para retornar um EndpointResponse compatível com o tipo de retorno esperado, ou lançe uma exceção mais adequada ao seu domínio.
        */
    }
}

MyApi myApi = new RestifyProxyBuilder()
    .error(new MyResponseErrorFallback())
    .target(MyApi.class)
        .build();

// ou

MyApi myApi = new RestifyProxyBuilder()
    .error()
        .using(new MyResponseErrorFallback())
    .target(MyApi.class)
        .build();

EndpointResponse

Esse objeto possui alguns métodos que permitem implementar uma lógica de recuperação de falhas, em caso de respostas 4xx ou 5xx.

public interface MyApi {

    @Path("/customers/{id}") @Get
    EndpointResponse<Customer> getCustomerById(@PathParameter String id);
}

MyApi myApi = new RestifyProxyBuilder()
  .target(MyApi.class)
    .build();

EndpointResponse<Customer> response = myApi.getCustomerById("abc123");

// o método recover recebe o tipo de exceção que deve ser manipulada, e uma funcão que retorna uma nova resposta
Customer customer = response.recover(EndpointResponseNotFoundException.class, e -> EndpointResponse.empty(StatusCode.ok()));

O EndpointResponse deve ser manipulado com cuidado; ao tentar acessar o corpo, em caso de respostas de erro, será lançada a exceção correspondente ao status code:

public interface MyApi {

    @Path("/customers/{id}") @Get
    EndpointResponse<Customer> getCustomerById(@PathParameter String id);
}

MyApi myApi = new RestifyProxyBuilder()
  .target(MyApi.class)
    .build();

// digamos que a resposta desse request foi 500 (Internal Server Error)
EndpointResponse<Customer> response = myApi.getCustomerById("abc123");

Customer customer = response.body(); // será lançada uma exceção do tipo EndpointResponseInternalServerErrorException
PreviousProject ReactorNextRetry

Last updated 6 years ago

Was this helpful?

Conforme discutido na , o objeto EndpointResponse representa a resposta HTTP completa, e pode ser utilizado como retorno de método.

documentação sobre tipos de retorno