Backend Development 10 min read

Master Spring Boot 3 API Versioning with Headers, Params, and Consumes

This article demonstrates how to implement multi‑version REST APIs in Spring Boot 3 by leveraging @RequestMapping attributes such as headers, params, and consumes, providing complete code examples, request screenshots, and a custom HttpMessageConverter for Content‑Type based versioning.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Boot 3 API Versioning with Headers, Params, and Consumes

1. Introduction

Spring MVC’s annotation‑driven controller model already supports rich attributes on @RequestMapping‑derived annotations. By using

headers

,

params

, and

consumes

you can implement clean, maintainable API version control without extra complexity.

2. Practical Cases

2.1 Annotation Overview

The core attributes of

@RequestMapping

relevant to versioning are listed below.

<code>public @interface RequestMapping {
    /**
     * Limit mapping by request parameters, e.g. "myParam=myValue" or "myParam!=myValue".
     */
    String[] params() default {};

    /**
     * Limit mapping by request headers, e.g. "MyHeader=myValue" or "MyHeader!=myValue".
     */
    String[] headers() default {};

    /**
     * Limit mapping by consumed media types, e.g. "text/plain" or "application/*".
     */
    String[] consumes() default {};
}</code>

2.2 Using headers attribute

Define two methods with the same path but different required header values.

<code>@RestController("userController2")
@RequestMapping("/users2")
public class UserController {
    @GetMapping(value = "", headers = {"X-API-Version=v1"})
    public Object v1() { return "User Header v1"; }

    @GetMapping(value = "", headers = {"X-API-Version=v2"})
    public Object v2() { return "User Header v2"; }
}</code>

Only requests that contain the matching

X-API-Version

header are routed to the corresponding method.

2.3 Using params attribute

<code>@GetMapping(value = "", params = {"v=v1"})
public Object v1() { return "User Param v1"; }

@GetMapping(value = "", params = {"v=v2"})
public Object v2() { return "User Param v2"; }</code>

The request must contain a query parameter

v

with value

v1

or

v2

to match the appropriate method.

2.4 Using consumes attribute

For GET requests the attribute works similarly, but for POST requests with a body you must provide a suitable

HttpMessageConverter

for the custom media type.

<code>@GetMapping(value = "", consumes = {"pack/v1"})
public Object v1() { return "User ContentType v1"; }

@GetMapping(value = "", consumes = {"pack/v2"})
public Object v2() { return "User ContentType v2"; }</code>

When the same endpoints are changed to POST with a request body, the default

MappingJackson2HttpMessageConverter

only supports

application/json

. Because the request uses

Content‑Type: pack/v1

, Spring throws

HttpMediaTypeNotSupportedException

.

<code>@PostMapping(value = "", consumes = {"pack/v1"})
public Object v1(@RequestBody User user) {
    user.setName(user.getName() + " - V1");
    return user;
}

@PostMapping(value = "", consumes = {"pack/v2"})
public Object v2(@RequestBody User user) {
    user.setName(user.getName() + " - V2");
    return user;
}</code>

Both calls initially return 415. To support the custom media type we register a converter that declares

pack/*

as supported.

<code>@Component
public class MultiVersion2Config implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        List<MediaType> supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(new MediaType("pack", "*"));
        messageConverter.setSupportedMediaTypes(supportedMediaTypes);
        converters.add(messageConverter);
    }
}</code>

After adding the custom converter, POST requests with

Content‑Type: pack/v1

or

pack/v2

are processed correctly.

Thus, using

headers

,

params

, and

consumes

together with a custom

HttpMessageConverter

enables clean multi‑version API control in Spring Boot 3.

API versioningSpring BootHeadersRequestMappingHttpMessageConverterConsumesParams
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.