🏠Spring BootContent negotiation with Spring Boot

Content negotiation with Spring Boot

In this post we will see how to implement content negotiation in a Spring Boot application.

Introduction

You may have written RESTful API endpoints where the client sends JSON request and the server sends back a JSON response. However, What would you do if the client can only understand XML? Obviously, You need to write extra logic for XML representation of the same Resource. This is where the content negotiation comes in to picture.

What is Content Negotiation?

Content negotiation is a concept that is used for serving different formats of a web resource at the same URI, so that the client can suggest which is best suited for its consumption.

When implemented right, The client can suggest which format it can handle so that the server can provide the resource appropriately. In Spring Boot there is rich support for content negotiation.

Here I have typical rest endpoint that returns an Item object.

@GetMapping("/item") public Item item() { return new Item(1, "Item 1", BigDecimal.valueOf(10.9d)); }
Code language: PHP (php)

How Spring Boot implements Content Negotiation?

By default, Spring Boot uses JSON implementation of HttpMessageConverter from jackson libraries. So the response even without any Accept header looks like the below.

$ curl -X GET "http://localhost:8080/item" -i HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Wed, 16 Sep 2020 12:35:20 GMT { "id" : 1, "name" : "Item 1", "price" : 10.9 }
Code language: JavaScript (javascript)

Now, Let’s request spring boot for XML response. As we understood from earlier, We just need to pass an Accept header to the request. Let’s see how this turns out.

$ curl -X GET http://localhost:8080/item -H "Accept: application/xml" -i HTTP/1.1 406 Content-Length: 0 Date: Wed, 16 Sep 2020 12:40:29 GMT
Code language: JavaScript (javascript)

Here, You can clearly see that we didn’t get a response. Also the response code is 406. In the HTTP specification, this status code means that the request is Not Acceptable. Spring-Boot returns this response because it can’t produce an XML response yet. If you have enabled DEBUG logs, this behaviour can be clearly seen.

DEBUG : o.s.web.servlet.DispatcherServlet : GET "/item", parameters={} DEBUG : s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.springhow.examples.springboot.contentnegotiation.controllers.SampleController#item() WARN : .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation] DEBUG : o.s.web.servlet.DispatcherServlet : Completed 406 NOT_ACCEPTABLE DEBUG : o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={} DEBUG : s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest) DEBUG : .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#mediaTypeNotAcceptable(HttpServletRequest) DEBUG : o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/xml', given [application/xml] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json] DEBUG : o.s.w.s.m.m.a.HttpEntityMethodProcessor : Nothing to write: null body DEBUG : .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation] DEBUG : o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 406
Code language: PHP (php)

Make a note of the log that is printed from HttpEntityMethodProcessor. Here, the supported content types are only [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]. This tells us that there is no support for application/xml.

XML responses for RESTFul Web services

So how to enable XML support for my spring boot rest service? It is very simple. Spring boot uses a HttpMessageConverter from the jackson parsing library for the request processing. And by default it supports JSON out of the box. But if we want to, we can add appropriate jackson-dataformat library. In our case we have to include the xml extension for jackson called jackson-dataformat-xml as dependency to our project. So let’s do that.

<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
Code language: HTML, XML (xml)

Note that I am not specifying any version for this maven dependency. Spring Boot already takes care of this.

Testing Content Negotiation in Spring Boot

After adding the dependency and rebuilding the application, let’s check the same request.

$ curl -X GET http://localhost:8080/item -H "Accept: application/xml" -i HTTP/1.1 200 Content-Type: application/xml;charset=UTF-8 Transfer-Encoding: chunked Date: Wed, 16 Sep 2020 13:41:38 GMT <Item> <id>1</id> <name>Item 1</name> <price>10.9</price> </Item>
Code language: HTML, XML (xml)

Here the response is clearly in the form of XML. And the Content-Type response header reflects the same as well. Let us check the logs as we did before.

DEBUG : o.s.web.servlet.DispatcherServlet : GET "/item", parameters={} DEBUG : s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.springhow.examples.springboot.contentnegotiation.controllers.SampleController#item() DEBUG : m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json, application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/*+xml;charset=UTF-8, application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/*+xml;charset=UTF-8] DEBUG : m.m.a.RequestResponseBodyMethodProcessor : Writing [com.springhow.examples.springboot.contentnegotiation.pojo.Item@74a56c27] DEBUG : o.s.web.servlet.DispatcherServlet : Completed 200 OK
Code language: PHP (php)

If you take a closer look, now the XML content types are also listed as supported types.

Conclusion

So that is all for content negotiation for now. To conclude, We learned how to provide support for different response formats using content negotiation in Spring Boot.

Related

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *