Overview
Neste tutorial, vamos ilustrar a vasta gama de operações onde o Cliente Spring REST – RestTemplate – pode ser utilizado, e bem utilizado.
Para o lado API de todos os exemplos, vamos executar o serviço RESTful a partir daqui.
Outra leitura:
Autenticação Básica com o RestTemplate de Primavera
RestTemplate with Digest Authentication
Explorar o Spring Boot TestRestTemplate
Notificação de Depreciação
As of Spring Framework 5, juntamente com a pilha WebFlux, Spring introduziu um novo cliente HTTP chamado WebClient.
WebClient é um cliente HTTP moderno e alternativo ao RestTemplate. Não só fornece uma API tradicional síncrona, como também suporta uma abordagem eficiente de não bloqueio e assíncrona.
P>Dito isto, se estamos a desenvolver novas aplicações ou a migrar uma antiga, é uma boa ideia utilizar o Cliente Web. Avançando, RestTemplate será depreciado em versões futuras.
Utilizar GET para Recuperar Recursos
h3>3.1. Get Plain JSON
Let’s start simple and talk about GET requests, with a quick example using the getForEntity() API:
RestTemplate restTemplate = new RestTemplate();String fooResourceUrl = "http://localhost:8080/spring-rest/foos";ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
Notificação de que temos acesso total à resposta HTTP, para que possamos fazer coisas como verificar o código de estado para garantir que a operação foi bem sucedida ou trabalhar com o corpo real da resposta:
ObjectMapper mapper = new ObjectMapper();JsonNode root = mapper.readTree(response.getBody());JsonNode name = root.path("name");assertThat(name.asText(), notNullValue());
Estamos a trabalhar com o corpo da resposta como uma String padrão e a utilizar Jackson (e a estrutura do nó JSON que Jackson fornece) para verificar alguns detalhes.
3.2. Recuperando POJO em vez de JSON
Podemos também mapear a resposta directamente a um recurso DTO:
public class Foo implements Serializable { private long id; private String name; // standard getters and setters}
Agora podemos simplesmente usar o getForObject API no modelo:
Foo foo = restTemplate .getForObject(fooResourceUrl + "/1", Foo.class);assertThat(foo.getName(), notNullValue());assertThat(foo.getId(), is(1L));
Utilizar HEAD para Recuperar Cabeçalhos
Vejamos agora a utilização de HEAD antes de passarmos aos métodos mais comuns.
Vamos utilizar a API headForHeaders() aqui:
HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
Utilizar POST para Criar um Recurso
A fim de criar um novo Recurso na API, podemos fazer bom uso das APIs postForLocation(), postForObject() ou postForEntity().
A primeira devolve o URI do novo Recurso criado, enquanto a segunda devolve o próprio Recurso.
5.1. O postForObject() API
RestTemplate restTemplate = new RestTemplate();HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);assertThat(foo, notNullValue());assertThat(foo.getName(), is("bar"));
5.2. O postForLocation() API
Simplesmente, vamos dar uma vista de olhos à operação que, em vez de devolver o Recurso completo, apenas devolve a Localização daquele Recurso recentemente criado:
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));URI location = restTemplate .postForLocation(fooResourceUrl, request);assertThat(location, notNullValue());
5.3. A troca() API
Vejamos como fazer um POST com a API de troca mais genérica:
RestTemplate restTemplate = new RestTemplate();HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));ResponseEntity<Foo> response = restTemplate .exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); Foo foo = response.getBody(); assertThat(foo, notNullValue());assertThat(foo.getName(), is("bar"));
5.4. Submeter dados do formulário
Next, vamos ver como submeter um formulário usando o método POST.
P>Primeiro, precisamos de definir o cabeçalho Content-Type para aplicação/x-www-form-urlencoded.
Esta acção assegura que uma grande cadeia de consulta pode ser enviada para o servidor, contendo pares nome/valor separados por &:
HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
Podemos envolver as variáveis do formulário num LinkedMultiValueMap:
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();map.add("id", "1");
Next, construímos o Pedido utilizando uma instância HttpEntity:
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
Finalmente, podemos ligar ao serviço REST chamando o RestTemplate.postForEntity() no Endpoint: /foos/form
ResponseEntity<String> response = restTemplate.postForEntity( fooResourceUrl+"/form", request , String.class); assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
Utilizar OPÇÕES para obter operações permitidas
P>Próximo, vamos dar uma vista de olhos rápida ao utilizar um pedido de OPÇÕES e explorar as operações permitidas num URI específico utilizando este tipo de pedido; a API é opçõesForAllow:
Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);HttpMethod supportedMethods = {HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE};assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));
Utilizar PUT para Actualizar um Recurso
P>Próximo, vamos começar a analisar o PUT e mais especificamente a troca() API para esta operação, desde o modelo.colocar API é bastante simples.
7.1. PUT simples Com troca()
Começaremos com uma simples operação PUT contra o API – e tenhamos em mente que a operação não está a devolver um corpo ao cliente:
Foo updatedInstance = new Foo("newName");updatedInstance.setId(createResponse.getBody().getId());String resourceUrl = fooResourceUrl + '/' + createResponse.getBody().getId();HttpEntity<Foo> requestUpdate = new HttpEntity<>(updatedInstance, headers);template.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Void.class);
7.2. PUT Com troca() e um Request Callback
Next, vamos utilizar um Request Callback para emitir um PUT.
Vamo-nos certificar de que preparamos o retorno de chamada, onde podemos definir todos os cabeçalhos de que precisamos, bem como um corpo de pedido:
RequestCallback requestCallback(final Foo updatedInstance) { return clientHttpRequest -> { ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(clientHttpRequest.getBody(), updatedInstance); clientHttpRequest.getHeaders().add( HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); clientHttpRequest.getHeaders().add( HttpHeaders.AUTHORIZATION, "Basic " + getBase64EncodedLogPass()); };}
P>Próximo, criamos o Recurso com um pedido de retorno de chamada:
ResponseEntity<Foo> response = restTemplate .exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
E depois actualizamos o Recurso:
Foo updatedInstance = new Foo("newName");updatedInstance.setId(response.getBody().getId());String resourceUrl =fooResourceUrl + '/' + response.getBody().getId();restTemplate.execute( resourceUrl, HttpMethod.PUT, requestCallback(updatedInstance), clientHttpResponse -> null);
Utilizar DELETE para Remover um Recurso
Para remover um Recurso existente, faremos rápido uso da API delete():
String entityUrl = fooResourceUrl + "/" + existingResource.getId();restTemplate.delete(entityUrl);
Configure Timeout
Podemos configurar o RestTemplate para o time out simplesmente usando ClientHttpRequestFactory:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());private ClientHttpRequestFactory getClientHttpRequestFactory() { int timeout = 5000; HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); clientHttpRequestFactory.setConnectTimeout(timeout); return clientHttpRequestFactory;}
E podemos usar o HttpClient para outras opções de configuração:
private ClientHttpRequestFactory getClientHttpRequestFactory() { int timeout = 5000; RequestConfig config = RequestConfig.custom() .setConnectTimeout(timeout) .setConnectionRequestTimeout(timeout) .setSocketTimeout(timeout) .build(); CloseableHttpClient client = HttpClientBuilder .create() .setDefaultRequestConfig(config) .build(); return new HttpComponentsClientHttpRequestFactory(client);}
Conclusion
Neste artigo, revimos os principais Verbos HTTP, usando RestTemplate para orquestrar pedidos usando todos estes.
Se quiseres pesquisar como fazer autenticação com o modelo, consulta o nosso artigo sobre Auth Básico com RestTemplate.
A implementação de todos estes exemplos e trechos de código pode ser encontrada no GitHub.
Comece com Spring 5 e Spring Boot 2, através do curso Learn Spring:
>> VERIFIQUE O CURSO