REST Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Introduction

In this quick tutorial, we're going to look at how to access HTTP Headers in a Spring Rest Controller.

First, we'll be using the @RequestHeader annotation to read headers individually as well as all together.

After that, we'll take a deeper look at the @RequestHeader‘s attributes.

2. Accessing HTTP Headers

2.1. Individually

If we need access to a specific header, we can configure @RequestHeader with the header name:

@GetMapping("/greeting")
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {
    // code that uses the language variable
    return new ResponseEntity<String>(greeting, HttpStatus.OK);
}

Then, we can access the value using the variable passed into our method. If a header named accept-language isn't found in the request, the method returns a “400 Bad Request” error.

Our headers don't have to be strings. For example, if we know our header is a number, we can declare our variable as a numeric type:

@GetMapping("/double")
public ResponseEntity<String> doubleNumber(@RequestHeader("my-number") int myNumber) {
    return new ResponseEntity<String>(String.format("%d * 2 = %d", 
      myNumber, (myNumber * 2)), HttpStatus.OK);
}

2.2. All at Once

If we're not sure which headers will be present, or we need more of them than we want in our method's signature, we can use the @RequestHeader annotation without a specific name.

We have a few choices for our variable type: a Map, a MultiValueMap or a HttpHeaders object.

First, let's get the request headers as a Map:

@GetMapping("/listHeaders")
public ResponseEntity<String> listAllHeaders(@RequestHeader Map<String, String> headers) {
    headers.forEach((key, value) -> {
        LOG.info(String.format("Header '%s' = %s", key, value));
    });

    return new ResponseEntity<String>(String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}

If we use a Map and one of the headers has more than one value, we'll get only the first value.  This is the equivalent of using the getFirst method on a MultiValueMap.

If our headers may have multiple values, we can get them as a MultiValueMap:

@GetMapping("/multiValue")
public ResponseEntity<String> multiValue(@RequestHeader MultiValueMap<String, String> headers) {
    headers.forEach((key, value) -> {
        LOG.info(String.format("Header '%s' = %s", key, value.stream().collect(Collectors.joining("|"))));
    });
        
    return new ResponseEntity<String>(String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}

We can also get our headers as an HttpHeaders object:

@GetMapping("/getBaseUrl")
public ResponseEntity<String> getBaseUrl(@RequestHeader HttpHeaders headers) {
    InetSocketAddress host = headers.getHost();
    String url = "http://" + host.getHostName() + ":" + host.getPort();
    return new ResponseEntity<String>(String.format("Base URL = %s", url), HttpStatus.OK);
}

The HttpHeaders object has accessors for common application headers.

When we access a header by name from a Map, MultiValueMap or the HttpHeaders object, we'll get a null if it isn't present.

3. @RequestHeader Attributes

Now that we've gone over the basics of accessing request headers with the @RequestHeader annotation, let's take a closer look at its attributes.

We've already used the name or value attributes implicitly when we've specifically named our header:

public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {}

We can accomplish the same thing by using the name attribute:

public ResponseEntity<String> greeting(@RequestHeader(name = "accept-language") String language) {}

Next, let's use the value attribute exactly the same way:

public ResponseEntity<String> greeting(@RequestHeader(value = "accept-language") String language) {}

When we name a header specifically, the header is required by default. If the header isn't found in the request, the controller returns a 400 error.

Let's use the required attribute to indicate that our header isn't required:

@GetMapping("/nonRequiredHeader")
public ResponseEntity<String> evaluateNonRequiredHeader(
  @RequestHeader(value = "optional-header", required = false) String optionalHeader) {
    return new ResponseEntity<String>(
      String.format("Was the optional header present? %s!", (optionalHeader == null ? "No" : "Yes")), 
      HttpStatus.OK);
}

Since our variable will be null if the header isn't present in the request, we need to be sure to do the appropriate null checking.

Let's use the defaultValue attribute to provide a default value for our header:

@GetMapping("/default")
public ResponseEntity<String> evaluateDefaultHeaderValue(
  @RequestHeader(value = "optional-header", defaultValue = "3600") int optionalHeader) {
    return new ResponseEntity<String>(String.format("Optional Header is %d", optionalHeader), 
    HttpStatus.OK);
}

4. Conclusion

In this short tutorial, we learned how to access request headers in Spring REST controllers. First, we used the @RequestHeader annotation to supply request headers to our controller methods.

After a look a the basics, we took a detailed look at the attributes for the @RequestHeader annotation.

The example code is available over on GitHub.

REST bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!