How to set an "Accept:" header on Spring RestTemplate request?
Asked Answered
S

6

266

I want to set the value of the Accept: in a request I am making using Spring's RestTemplate.

Here is my Spring request handling code

@RequestMapping(
    value= "/uom_matrix_save_or_edit", 
    method = RequestMethod.POST,
    produces="application/json"
)
public @ResponseBody ModelMap uomMatrixSaveOrEdit(
    ModelMap model,
    @RequestParam("parentId") String parentId
){
    model.addAttribute("attributeValues",parentId);
    return model;
}

and here is my Java REST client:

public void post(){
    MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
    params.add("parentId", "parentId");
    String result = rest.postForObject( url, params, String.class) ;
    System.out.println(result);
}

This works for me; I get a JSON string from the server side.

My question is: how can I specify the Accept: header (e.g. application/json,application/xml, ... ) and request method (e.g. GET,POST, ... ) when I use RestTemplate?

Sustentacular answered 8/10, 2013 at 3:45 Comment(0)
M
482

I suggest using one of the exchange methods that accepts an HttpEntity for which you can also set the HttpHeaders. (You can also specify the HTTP method you want to use.)

For example,

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

HttpEntity<String> entity = new HttpEntity<>("body", headers);

restTemplate.exchange(url, HttpMethod.POST, entity, String.class);

I prefer this solution because it's strongly typed, ie. exchange expects an HttpEntity.

However, you can also pass that HttpEntity as a request argument to postForObject.

HttpEntity<String> entity = new HttpEntity<>("body", headers);
restTemplate.postForObject(url, entity, String.class); 

This is mentioned in the RestTemplate#postForObject Javadoc.

The request parameter can be a HttpEntity in order to add additional HTTP headers to the request.

Macomber answered 8/10, 2013 at 4:19 Comment(0)
C
157

You could set an interceptor "ClientHttpRequestInterceptor" in your RestTemplate to avoid setting the header every time you send a request.

public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {

        private final String headerName;

        private final String headerValue;

        public HeaderRequestInterceptor(String headerName, String headerValue) {
            this.headerName = headerName;
            this.headerValue = headerValue;
        }

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            request.getHeaders().set(headerName, headerValue);
            return execution.execute(request, body);
        }
    }

Then

List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new HeaderRequestInterceptor("Accept", MediaType.APPLICATION_JSON_VALUE));

RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(interceptors);
Carbineer answered 6/2, 2015 at 10:31 Comment(4)
Spring Boot 1.3 has a HttpHeaderInterceptor, so we don't need to create our own implementation of ClientHttpRequestInterceptor.Mahogany
For some reason, HttpHeaderInterceptor is only in spring-boot-devtools. So we still have to implement ClientHttpRequestInterceptor ourselves. I think it should be moved into spring-web.Mahogany
Is it better to add default headers to ClientHttpRequestFactory set to the rest template instead of adding interceptors? P.S. you should add your answer in a separate question since this deals with default headers. Had to look for a while to reach here!Wurster
if there are two services that use two diff id /pass that we have to call, this interceptor at resttemplate level is too high level right? you need this at request level - generally RestTemplate is a @Bean in spring boot configMormon
P
37

If, like me, you struggled to find an example that uses headers with basic authentication and the rest template exchange API, this is what I finally worked out...

private HttpHeaders createHttpHeaders(String user, String password)
{
    String notEncoded = user + ":" + password;
    String encodedAuth = Base64.getEncoder().encodeToString(notEncoded.getBytes());
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.add("Authorization", "Basic " + encodedAuth);
    return headers;
}

private void doYourThing() 
{
    String theUrl = "http://blah.blah.com:8080/rest/api/blah";
    RestTemplate restTemplate = new RestTemplate();
    try {
        HttpHeaders headers = createHttpHeaders("fred","1234");
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, String.class);
        System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
    }
    catch (Exception eek) {
        System.out.println("** Exception: "+ eek.getMessage());
    }
}
Puente answered 24/4, 2017 at 14:11 Comment(0)
Y
20

Calling a RESTful API using RestTemplate

Example 1:

RestTemplate restTemplate = new RestTemplate();
// Add the Jackson message converter
restTemplate.getMessageConverters()
                .add(new MappingJackson2HttpMessageConverter());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic XXXXXXXXXXXXXXXX=");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
restTemplate.getInterceptors()
                .add(new BasicAuthorizationInterceptor(USERID, PWORD));
String requestJson = getRequetJson(Code, emailAddr, firstName, lastName);
response = restTemplate.postForObject(URL, requestJson, MYObject.class);
        

Example 2:

RestTemplate restTemplate = new RestTemplate();
String requestJson = getRequetJson(code, emil, name, lastName);
HttpHeaders headers = new HttpHeaders();
String userPass = USERID + ":" + PWORD;
String authHeader =
    "Basic " + Base64.getEncoder().encodeToString(userPass.getBytes());
headers.set(HttpHeaders.AUTHORIZATION, authHeader);
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> request = new HttpEntity<String>(requestJson, headers);
ResponseEntity<MyObject> responseEntity;
responseEntity =
    this.restTemplate.exchange(URI, HttpMethod.POST, request, Object.class);
responseEntity.getBody()

The getRequestJson method creates a JSON Object:

private String getRequetJson(String Code, String emailAddr, String name) {
    ObjectMapper mapper = new ObjectMapper();
    JsonNode rootNode = mapper.createObjectNode();
    ((ObjectNode) rootNode).put("code", Code);
    ((ObjectNode) rootNode).put("email", emailAdd);
    ((ObjectNode) rootNode).put("firstName", name);
    String jsonString = null;
    try {
        jsonString = mapper.writerWithDefaultPrettyPrinter()
                               .writeValueAsString(rootNode);
    }
    catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    return jsonString;
}
Yucca answered 16/8, 2018 at 20:13 Comment(0)
H
11

Short solution without HttpHeaders creating:

RequestEntity<Void> request = RequestEntity.post(URI.create(url))
                .accept(MediaType.APPLICATION_JSON)
                .contentType(MediaType.APPLICATION_JSON)
                // any other headers
                .header("PRIVATE-TOKEN", "token")
                .build();

ResponseEntity<String> response = restTemplate.exchange(request, String.class);
return response.getBody();

UPDATE: but in case specific headers HttpHeaders become simple:

RequestEntity.post(URI.create(AMOCRM_URL + url))
            .contentType(MediaType.APPLICATION_JSON)
            .headers(
                    new HttpHeaders() {{
                        setBearerAuth(getAccessToken());
                    }})
            .body(...)
Hypsometry answered 29/5, 2021 at 14:53 Comment(1)
I do not understand why adding working headers in your local environment needs to be such a PIA, this, like all other methods I've seen on the web just doesn't work...Beaston
M
5

Here is a simple answer. Hope it helps someone.

import org.springframework.boot.devtools.remote.client.HttpHeaderInterceptor;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;


public String post(SomeRequest someRequest) {
    // create a list the headers 
    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(new HttpHeaderInterceptor("Accept", MediaType.APPLICATION_JSON_VALUE));
    interceptors.add(new HttpHeaderInterceptor("ContentType", MediaType.APPLICATION_JSON_VALUE));
    interceptors.add(new HttpHeaderInterceptor("username", "user123"));
    interceptors.add(new HttpHeaderInterceptor("customHeader1", "c1"));
    interceptors.add(new HttpHeaderInterceptor("customHeader2", "c2"));
    // initialize RestTemplate
    RestTemplate restTemplate = new RestTemplate();
    // set header interceptors here
    restTemplate.setInterceptors(interceptors);
    // post the request. The response should be JSON string
    String response = restTemplate.postForObject(Url, someRequest, String.class);
    return response;
}
Metastasize answered 18/7, 2018 at 14:46 Comment(1)
Your code will use Spring Devtools as a production dependency (by importing org.springframework.boot.devtools.remote.client.HttpHeaderInterceptor)...Miniaturist

© 2022 - 2024 — McMap. All rights reserved.