How To Read HTTP Request Header in Spring MVC

This short tutorial is about how to read the HTTP request header in the spring framework.

While refactoring a REST service, I came across code duplicates.

There were 5 similar methods, whereby only the RequestBody and the Return method differed minimally.

In this case, it’s a GET request which serializes an RDF record into different formats on request.

Now I wanted to convert these 5 methods into a single method.
With the @RequestHeader annotation, this is no problem.

 
 @RequestMapping(value = {"/rest/**"},
        method = RequestMethod.GET)
    public @ResponseBody ResponseEntity getContainer(@RequestHeader(value="Accept") String acceptHeader, HttpServletRequest request) {

        log.debug("Request to get container: {} in format: {}", path, acceptHeader);

        // dummy code to get path
        String path = "";

        // return rdf in requested format
        return new ResponseEntity<>(containerService.find(path).toString(acceptHeader), HttpStatus.OK);
    }

How to resolve slashes in path variable in Spring MVC

Today I stumbled across a problem where a slash can occur in a path variable.

The contents of the path variable can look like this:
1/53879d5c-b07b-44f2-9a77-b99f67bb8481 or even 1/2/53879d5c-b07b-44f2-9a77-b99f67bb8481

At the backend, I need the full path in a variable because the path can contain several slashes but does not have to.

Let’s have a look at this as a code example to make it clear.

@GetMapping("/rest/{path}")
public @ResponseBody ResponseEntity<Container> getContainerByPath(@PathVariable String path) {

  return containerService.getByPath(path);

}

The path /1/53879d5c-b07b-44f2-9a77-b99f67bb8481 will not work.

The solution is HttpServletRequest.

// /rest/1/53879d5c-b07b-44f2-9a77-b99f67bb8481
@GetMapping("/rest/**")
public @ResponseBody ResponseEntity<Container> getContainerByPath(HttpServletRequest request) {

  String path = extractPath(request);

  return containerService.getByPath(path);

}
private String extractPath(HttpServletRequest request) {

  String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
  String matchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); // /rest/**

  return new AntPathMatcher().extractPathWithinPattern(matchPattern, path); // 1/53879d5c-b07b-44f2-9a77-b99f67bb8481
}

 

 

 

HATEOAS And HAL – And Why You Should Use It For Your REST API

Let’s face it, we all love REST. As data models grow and functionality increases, REST APIs can quickly become complex.

For the design and documentation of an API, I use Swagger.

In the screenshot, you can see an example API as shown by the Swagger UI.

There is no logical link between individual resources.

 

HATEOAS/HAL extends REST by the possibility to guide a user/client through.

HATEOAS is a concept of application architecture. It defines the way in which a clients application interact with the server, by navigating hypermedia links they find inside resource models returned by the server.

Since HATEOAS is only a concept, we need some standard to describe the resources, that contain hypermedia information (links to related resources).
HAL is one of such standards. It is a specific format of resource presentation, that can be used to implement HATEOAS.

For example, an answer without HATEOAS might look like this:

{
  "id": 1,
  "city:" "Vienna"
}

A client without knowledge of the possibilities of the API does not know now that he may change or delete the entry.

Let’s assume you want to tell the client that it can edit and delete this entry. With REST this is not possible.

Let’s look at the same example with implementing HATEOAS using HAL to describe the links:

URI: http://localhost:8080/api/v1/cities/1

{
  "id": 1,
  "city": "Vienna",
  "_links": {
    "self": {
      "href": "http://localhost:8080/api/v1/cities/1"
   }
 }
}

The first link assigned to a resource is called a self-link. It is the self-relationship – the canonical place where the resource is accessible.

This link is of course not very helpful. Let’s have a look at a more complex example: a client should change the entry “Vienna” and confirm afterwards.

The first case is simple, and CRUD provides us with the operation PUT, which usually refers to the self-link. However, how do we determine the confirmation link?
We use an additional link which we label with the label “accept”.

The client that implements the API has to check in the list of links if there is a function “accept” and follow the link.

URI: http://localhost:8080/api/v1/cities/1

{
  "id": 1,
  "city": "Vienna",
  "_links": {
    "self": {
      "href": "http://localhost:8080/api/v1/cities/1"
    },
    "accept": {
      "href": "http://localhost:8080/api/v1/cities/1"
    }
  }
}