Panoramica
In questo tutorial, illustreremo la vasta gamma di operazioni in cui il client Spring REST – RestTemplate – può essere usato, e usato bene.
Per il lato API di tutti gli esempi, eseguiremo il servizio RESTful da qui.
Altre letture:
Autenticazione di base con il RestTemplate
RestTemplate con autenticazione Digest
Esplorando il TestRestTemplate di Spring Boot
Avviso di cancellazione
A partire da Spring Framework 5, insieme allo stack WebFlux, Spring ha introdotto un nuovo client HTTP chiamato WebClient.
WebClient è un moderno client HTTP alternativo a RestTemplate. Non solo fornisce una tradizionale API sincrona, ma supporta anche un efficiente approccio non bloccante e asincrono.
Detto questo, se stiamo sviluppando nuove applicazioni o migrando una vecchia, è una buona idea usare WebClient. Andando avanti, RestTemplate sarà deprecato nelle versioni future.
Usa GET per recuperare risorse
3.1. Ottenere Plain JSON
Iniziamo in modo semplice e parliamo delle richieste GET, con un rapido esempio usando l’API getForEntity():
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));
Nota che abbiamo pieno accesso alla risposta HTTP, quindi possiamo fare cose come controllare il codice di stato per assicurarci che l’operazione abbia avuto successo o lavorare con il corpo effettivo della risposta:
ObjectMapper mapper = new ObjectMapper();JsonNode root = mapper.readTree(response.getBody());JsonNode name = root.path("name");assertThat(name.asText(), notNullValue());
Stiamo lavorando con il corpo della risposta come una stringa standard e usando Jackson (e la struttura dei nodi JSON che Jackson fornisce) per verificare alcuni dettagli.
3.2. Recuperare POJO invece di JSON
Possiamo anche mappare la risposta direttamente su un Resource DTO:
public class Foo implements Serializable { private long id; private String name; // standard getters and setters}
Ora possiamo semplicemente usare l’API getForObject nel template:
Foo foo = restTemplate .getForObject(fooResourceUrl + "/1", Foo.class);assertThat(foo.getName(), notNullValue());assertThat(foo.getId(), is(1L));
Utilizzare HEAD per recuperare le intestazioni
Diamo ora una rapida occhiata all’utilizzo di HEAD prima di passare ai metodi più comuni.
Useremo l’API headForHeaders() qui:
HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
Usare POST per creare una risorsa
Per creare una nuova risorsa nelle API, possiamo fare buon uso delle API postForLocation(), postForObject() o postForEntity().
La prima restituisce l’URI della risorsa appena creata, mentre la seconda restituisce la risorsa stessa.
5.1. L’API postForObject()
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. Il postForLocation() API
Similmente, diamo un’occhiata all’operazione che invece di restituire la Risorsa completa, restituisce solo la Posizione della Risorsa appena creata:
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));URI location = restTemplate .postForLocation(fooResourceUrl, request);assertThat(location, notNullValue());
5.3. Lo scambio() API
Diamo un’occhiata a come fare un POST con il più generico scambio API:
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. Inviare i dati del modulo
Prossimo, vediamo come inviare un modulo usando il metodo POST.
Prima di tutto, dobbiamo impostare l’intestazione Content-Type su application/x-www-form-urlencoded.
Questo fa sì che una grande stringa di query possa essere inviata al server, contenente coppie nome/valore separate da &:
HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
Possiamo avvolgere le variabili del modulo in una LinkedMultiValueMap:
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();map.add("id", "1");
In seguito, costruiamo la richiesta usando un’istanza di HttpEntity:
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
Infine, possiamo connetterci al servizio REST chiamando restTemplate.postForEntity() sull’endpoint: /foos/form
ResponseEntity<String> response = restTemplate.postForEntity( fooResourceUrl+"/form", request , String.class); assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
Utilizzare OPTIONS per ottenere le operazioni consentite
Prossimamente, daremo una rapida occhiata all’utilizzo di una richiesta OPTIONS ed esploreremo le operazioni consentite su un URI specifico utilizzando questo tipo di richiesta; l’API è optionsForAllow:
Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);HttpMethod supportedMethods = {HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE};assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));
Utilizzare PUT per aggiornare una risorsa
Prossimo, inizieremo a guardare PUT e più specificamente l’API exchange() per questa operazione, dato che l’API template.put è piuttosto semplice.
7.1. Simple PUT With exchange()
Iniziamo con una semplice operazione PUT contro l’API – e teniamo presente che l’operazione non restituisce un corpo al client:
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 con exchange() e una Request Callback
Prossimamente, useremo una request callback per emettere un PUT.
Assicuriamoci di preparare il callback, dove possiamo impostare tutte le intestazioni di cui abbiamo bisogno e il corpo della richiesta:
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()); };}
In seguito, creiamo la risorsa con una richiesta POST:
ResponseEntity<Foo> response = restTemplate .exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
E poi aggiorniamo la Risorsa:
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);
Utilizziamo DELETE per rimuovere una Risorsa
Per rimuovere una Risorsa esistente, useremo velocemente l’API delete():
String entityUrl = fooResourceUrl + "/" + existingResource.getId();restTemplate.delete(entityUrl);
Configurare il timeout
Possiamo configurare RestTemplate per il time out semplicemente usando ClientHttpRequestFactory:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());private ClientHttpRequestFactory getClientHttpRequestFactory() { int timeout = 5000; HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); clientHttpRequestFactory.setConnectTimeout(timeout); return clientHttpRequestFactory;}
E possiamo usare HttpClient per ulteriori opzioni di configurazione:
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);}
Conclusione
In questo articolo, siamo andati oltre i principali verbi HTTP, usando RestTemplate per orchestrare le richieste utilizzando tutti questi.
Se volete approfondire come fare l’autenticazione con il template, date un’occhiata al nostro articolo su Basic Auth with RestTemplate.
L’implementazione di tutti questi esempi e frammenti di codice può essere trovata su GitHub.
Inizia con Spring 5 e Spring Boot 2, attraverso il corso Learn Spring:
>> CHECK OUT THE COURSE