Pages

Footer Pages

Spring Boot

Java String API

Java Conversions

Kotlin Programs

Kotlin Conversions

Java Threads Tutorial

Java 8 Tutorial

Thursday, April 16, 2020

How to Read HTTP Headers in Spring REST Controllers

1. Introduction


In this tutorial, We'll learn different ways to read HTTP headers in spring boot rest controllers.

In this article, first, we'll be using @RequestHeader a notion to access the HTTP headers individually and all together at once. At last, We'll look at the next level to read HTTP Headers using the @RequestHeader attribute.

2. Accessing HTTP Headers


2.1 One at a time (Individually)

To access a specific header, Just use the @RequstHeader annotation at the method argument and specify which header value should be retrieved. In the below example, we are trying to get the locale value that passed as part of the header.


Always we should be mapped to a String value. Or even you can assign it to List<String> or Set<String> and which stores the given header value into List or Set. But this collection will have only one value in it.

@GetMapping("individual")
public ResponseEntity<String> getHeaderFromLocale(@RequestHeader("locale") String locale) {
 logger.info("getmapping for request hreaders : " + locale);

 String country = "USA is leading country in the world.";
 if (locale.equals("IN")) {
  country = "India";
 } else if (locale.equals("UK")) {
  country = "United Kingdom";
 } else if (locale.equals("AUS")) {
  country = "Australia";
 } else if (locale.equals("IT")) {
  country = "Italiy";
 }

 String response = "Country for the given locale " + locale + " is " + country;
 if (locale.trim().length() == 0) {
  response = country;
 }

 return new ResponseEntity<String>(response, HttpStatus.OK);
}

Testing:

When sending the request, we have passed two HTTP headers but we retrieved only one by providing the name in annotation @RequestHeader.


Accessing HTTP Headers One at a time (Individually)


If the given header name "locale" is not present in the request then it will throw 400 - bad request. below is the sample for non-matching header response.

{
    "timestamp": "2020-04-16T07:34:36.000+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "Missing request header 'locale' for method parameter of type List",
    "path": "/request/headers/individual"
}

Getting Long values as numbers


Below is to get the phone number from the header and can be type cast to Long as we needed. If the number is present in the header then that can be casted to any numeric type as below.

@GetMapping("individual/phonenumnber")
public ResponseEntity<String> getHeaderNumberValue(@RequestHeader("phone-number") long phoneNumber) {
 logger.info("getmapping for request hreaders : " + phoneNumber);
 boolean isValidNumber = false;
 if (String.valueOf(phoneNumber).length() == 10) {
  isValidNumber = true;
 }

 String response = "Given phone number " + phoneNumber + " is " + (isValidNumber ? "valid" : "invalid");

 return new ResponseEntity<String>(response, HttpStatus.OK);
}

Output:

Getting Long values as numbers from HTTP header



2.2 Accessing All Headers At Once


If you do not know the header field names or want to get multiple headers at once and want to use them as part of the method signature.

Yes, We can still use the same annotation @RequestHeader with a specific name.

We can cast to a type which can store key-value pair such as Map, MultiValueMap and HttpHeaders objects.

Let us see the examples on each of these how the headers can be retrieved.

@RequestHeader Map Example:


@GetMapping("allheaders/map")
 public ResponseEntity<String> getAllHeadersAsMap(@RequestHeader Map<String, String> allHeaders) {

  logger.info("All headers are");
  Set<Entry<String, String>> entrySet = allHeaders.entrySet();

  StringBuffer buffer = new StringBuffer();
  buffer.append("header count " + allHeaders.size() + " \n");
  for (Entry<String, String> e : entrySet) {
   logger.info("Header " + e.getKey() + "= " + e.getValue());
   buffer.append("Header " + e.getKey() + "= " + e.getValue() + " \n");
  }

  return new ResponseEntity<String>(buffer.toString(), HttpStatus.OK);
 }


Output:

postman response

header count 8 
Header locale= IT 
Header phone-number= 9912345678 
Header user-agent= PostmanRuntime/7.24.1 
Header accept= */* 
Header postman-token= 4ff38436-e935-497f-bd34-06740c254905 
Header host= localhost:8080 
Header accept-encoding= gzip, deflate, br 
Header connection= keep-alive 

@RequestHeader Map Example


@RequestHeader MultiValueMap Example


MultiValueMap is most useful if any header is repeated more than once. If you use the Map approach as above that will give only the first value and remaining values will be ignored.

Take a look at the below code and observe the output.

@GetMapping("allheaders/multimap")
public ResponseEntity<String> getAllHeadersAsMultiMap(@RequestHeader MultiValueMap<String, String> allHeaders) {

 logger.info("All headers with MultiValueMap");

 allHeaders
   .forEach((k, v) -> logger.info(" key " + k + " = value = " + v.stream().collect(Collectors.toList())));

 return new ResponseEntity<String>("MultiValueMap Example", HttpStatus.OK);
}

Output:

We have sent the "locale" header 3 times and MultiValueMap will retrieve all repeated from the header.

Repeated header : [IT, USA, IN]

@RequestHeader MultiValueMap Example with repated header

@RequestHeader HttpHeaders Example:


HttpHeaders also can be used similar to the MultiValueMap but this is case sensitive. And also this has lots of methods utility methods as below.

getFirst(String) returns the first value associated with a given header name
add(String, String) adds a header value to the list of values for a header name
set(String, String) sets the header value to a single string value

as well we can get the host details.

 @GetMapping("allheaders/httpheaders")
 public ResponseEntity<String> getAllHeadersAsHttpHeaders(@RequestHeader HttpHeaders allHttpHeaders) {

  logger.info("All headers with MultiValueMap");
  StringBuffer httpBuffer = new StringBuffer();

  String firstValue = allHttpHeaders.getFirst("locale");

  String hostName = allHttpHeaders.getHost().getHostName();

  int port = allHttpHeaders.getHost().getPort();

  httpBuffer.append(" first value of locale : " + firstValue).append("\nhost name : " + hostName)
    .append("\nport : " + port);

  return new ResponseEntity<String>("HttpHeaders response: " + httpBuffer.toString(), HttpStatus.OK);
 }

Output:

HttpHeaders response:  first value of locale : IT
host name : localhost
port : 8080

RequestHeader HttpHeaders Example

3. @RequestHeader Attributes


All the attributes for this annotation are optional. But, we can use any of these at a time and multiple can be used.

As of now, we have seen how to get the header values using @RequestHeader annotation using various ways.

Now, let us go through attributes of @RequestHeader annotation.

First, We'll see name and value attributes.

3.1 Name Attribute


Need to pass the name attribute before the header name as below.

public ResponseEntity<String> getHeaderFromLocale(@RequestHeader(name = "locale") String locale) { }

If you observe properly, we have already used this in the previous examples and which is equal to the below.

public ResponseEntity<String> getHeaderFromLocale(@RequestHeader("locale") String locale) { }

3.2 Value Attribute


Value attribute works similar to the name attribute and which is called as an alias for name.

public ResponseEntity<String> getHeaderFromLocale(@RequestHeader(value = "locale") String locale) { }

3.3 Required Attribute


If we want to make always a specific header should be available then need to use required annotation. If the value is true, then it is mandatory else optional.

@GetMapping("individual/requried")
 public ResponseEntity<String> mandateHeader(@RequestHeader(value = "locale", required = true) String locale) {

  return new ResponseEntity<String>(locale, HttpStatus.OK);
 }


We are expecting always locale should be present in the header, if it is missing then it will throw 400 bad error.

Output:

{
    "timestamp": "2020-04-16T15:52:59.845+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "Missing request header 'locale' for method parameter of type String",
    "path": "/request/headers/individual/requried"
}

Note: If required = true then this will become by default header.

3.4 defaultValue Attribue


If we are expecting a specific header but it is not a mandatory header. In this case, We have another attribute that can assign the default value if it is missing.


@GetMapping("individual/default")
 public ResponseEntity<String> Header(@RequestHeader(value = "locale", defaultValue = "USA") String locale) {

  return new ResponseEntity<String>(locale, HttpStatus.OK);
 }

Output:

USA

defaultValue Attribue

4. Conclusion


In this article, We've seen how to read header values from spring boot applications. This can be done using reading one at a time and all at once.

And also shown all attributes of RequestHeader annotation.

All Examples shown in this article are over GitHub

GitHub Controller Code

RequestHeader API

Ref HttpHeaders


No comments:

Post a Comment

Please do not add any spam links in the comments section.