SpringBoot/Kotlin和通过内容协商进行版本控制:正确的方法



我一直在尝试将内容协商作为SpringBoot/Kotlin应用程序的后端版本控制。我有以下内容:

@GetMapping("/user", produces = [MediaType.APPLICATION_JSON_VALUE])
fun getUsers() {
//some code here
}

我发现这个项目结合了accept"标头和accept Version"自定义标头。我想知道这是否是实现内容协商方法的正确方式,如果不是,我该如何修复它?

@GetMapping("/user", produces = [MediaType.APPLICATION_JSON_VALUE], headers = ["Accept-Version=$CUSTOM_ACCEPT_HEADER"])
fun getUsers() {
//some code here
}
object VersioningUtility {
const val CUSTOM_ACCEPT_HEADER = "vnd.sample.com-v1+json"
//here more constants as each controller can be versioned independently
}

谢谢

是的,您可以使用内容协商实现API版本控制,方法是根据您指定的自定义头和头值。然而,由于这不是一个标准的标头,您可能需要自己处理其他场景,例如:

  • 标头不存在时的默认表示
  • 作为标头的一部分传递无效媒体类型值时的异常情况

如果只使用json响应,则用于内容协商的json API标准是发送值为application/vnd.api+jsonAccept头。由于Accept是一个标准的请求头,因此最好使用它。如果您需要处理其他类型的响应,您仍然可以使用自定义标头。

您可以实现如下内容协商:

@RestController
class UserController {
@GetMapping("/users", headers = ["Accept=${VersioningUtility.VERSION_1_HEADER}"])
fun getUser(): ResponseEntity<Any> {
return ResponseEntity(listOf(User("Abraham Lincoln")), HttpStatus.OK)
}
@GetMapping("/users", headers = ["Accept=${VersioningUtility.VERSION_2_HEADER}"])
fun getNewUser(): ResponseEntity<Any> {
return ResponseEntity(listOf(NewUser(Name("Abraham", "Lincoln"))), HttpStatus.OK)
}
}
data class User(val name: String)
data class NewUser(val name: Name)
data class Name(val firstName: String, val lastName: String)
object VersioningUtility {
const val VERSION_1_HEADER = "application/vnd.v1+json"
const val VERSION_2_HEADER = "application/vnd.v2+json"
}

上面的使您能够拥有两个版本的具有Accept标头的GET /users端点。

当curl请求使用头值的v1时,响应将根据版本v1

curl -L -X GET 'http://localhost:8080/users' 
-H 'Accept: application/vnd.v1+json'
[
{
"name": "Abraham Lincoln"
}
]

当curl请求使用头值的v2时,响应将根据版本v2

curl -L -X GET 'http://localhost:8080/users' 
-H 'Accept: application/vnd.v2+json'
[
{
"name": {
"firstName": "Abraham",
"lastName": "Lincoln"
}
}
]

发送无效标头值时,它将以406不可接受响应

curl -L -X GET 'http://localhost:8080/users' 
-H 'Accept: application/vnd.abc+json'
{
"timestamp": "2020-04-01T18:33:16.393+0000",
"status": 406,
"error": "Not Acceptable",
"message": "Could not find acceptable representation",
"path": "/users"
}

当没有发送Accept标头时,它将使用默认版本进行响应,即v1此处为

curl -L -X GET 'http://localhost:8080/users'
[
{
"name": "Abraham Lincoln"
}
]

甚至GitHub也以类似的方式通过内容协商实现了版本控制,您可以在他们的文档中看到这一点。

最新更新