Spring Boot API multi-version quick start Demo

HBLOG
3 min readApr 17, 2024

--

1.Background introduction

When developing Restful interfaces with Spring Boot, due to changes in modules, systems and other businesses, different versions of parameter implementations need to be provided for the same interface (old interfaces are still used by modules or systems and cannot be changed directly, so different versions are required). How to implement multi-version interfaces more elegantly? There are many ways to customize version annotations on the Internet, but I don’t recommend doing so because of hard coding and increased system maintenance costs. Moreover, springboot itself supports multiple versions very well, so there is no need to reinvent the wheel.

2.Code Project

pomx.ml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api-version</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

controller

package com.et.api.version.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/users")
public class HelloWorldController {
//@GetMapping(params = "version=1")
//@GetMapping(produces = "application/vnd.company.app-v1+json")
@GetMapping(headers = "API-Version=1")
public Map<String, Object> showHelloWorldone(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld1");
return map;
}
//@GetMapping(params = "version=2")
//@GetMapping(produces = "application/vnd.company.app-v2+json")
@GetMapping(headers = "API-Version=2")
public Map<String, Object> showHelloWorldtwo(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld2");
return map;
}

}
package com.et.api.version.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/v1/users")
public class HelloWorldOneController {
@RequestMapping("/hello")
public Map<String, Object> showHelloWorld(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld1吖");
return map;
}

}
package com.et.api.version.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/v2/users")
public class HelloWorldTwoController {
@RequestMapping("/hello")
public Map<String, Object> showHelloWorld(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld2");
return map;
}

}

DemoApplication.java

package com.et.api.version;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

application.yaml

server:
port: 8088

above it’s just some key codes,for all codes, you can see it in the code repository below

Code Repository

3.Test

1.url path

set multi path on the different class,for example

@RequestMapping("/v1/users")
public class HelloWorldOneController {
}
@RequestMapping("/v2/users")
public class HelloWorldTwoController {
}

2.params detectd

@GetMapping(params = "version=1")
public Map<String, Object> showHelloWorldone(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld1");
return map;
}
@GetMapping(params = "version=2")
public Map<String, Object> showHelloWorldtwo(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld2");
return map;
}

3.header detected

@GetMapping(headers = "API-Version=1")
public Map<String, Object> showHelloWorldone(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld1");
return map;
}

@GetMapping(headers = "API-Version=2")
public Map<String, Object> showHelloWorldtwo(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld2");
return map;
}

4.Media Type detectd

@GetMapping(produces = "application/vnd.company.app-v1+json")
public Map<String, Object> showHelloWorldone(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld1");
return map;
}
@GetMapping(produces = "application/vnd.company.app-v2+json")
public Map<String, Object> showHelloWorldtwo(){
Map<String, Object> map = new HashMap<>();
map.put("msg", "HelloWorld2");
return map;
}

4.reference

--

--