SpringBoot/Kotlin 和通过内容协商进行版本控制:正确的方法?
SpringBoot/Kotlin and Versioning through Content Negotiation: correct approach?
我一直在尝试将内容协商作为我的 SpringBoot/Kotlin 应用程序的后端版本控制。我有以下内容:
@GetMapping("/user", produces = [MediaType.APPLICATION_JSON_VALUE])
fun getUsers() {
//some code here
}
我发现 this project 结合了 accept" header 和 "Accept-Version" 自定义 header。我想知道这是否是实施内容协商方法的正确方法,并且如果不能,我该如何解决?
@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
}
谢谢
是的,您可以通过指定的自定义 header 和 header 值使用内容协商实施 API 版本控制。但是,由于这不是标准 header,因此您可能需要自己处理其他情况,例如:
- header 不存在时的默认表示
- 作为 header.
的一部分传递无效媒体类型值时的异常情况
如果您只处理 json 响应,JSON API standard for content negotiation is to send the Accept
header with the value application/vnd.api+json
. Since Accept 是标准请求 header,最好使用它。如果您需要处理其他类型的响应,您仍然可以继续使用自定义 header。
您可以按如下方式实现内容协商:
@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
header.
的 GET /users
端点的 2 个版本
当使用 header 值的 v1 发出 curl 请求时,响应将根据 version v1
curl -L -X GET 'http://localhost:8080/users' \
-H 'Accept: application/vnd.v1+json'
[
{
"name": "Abraham Lincoln"
}
]
当使用 header 值的 v2 发出 curl 请求时,响应将根据 version v2
curl -L -X GET 'http://localhost:8080/users' \
-H 'Accept: application/vnd.v2+json'
[
{
"name": {
"firstName": "Abraham",
"lastName": "Lincoln"
}
}
]
当发送无效的 header 值时,它会以 406 Not Acceptable
响应
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
header时,它会返回默认版本,即v1这里
curl -L -X GET 'http://localhost:8080/users'
[
{
"name": "Abraham Lincoln"
}
]
甚至 GitHub 也以类似的方式通过内容协商实现了版本控制,您可以在他们的 documentation.[=22 中查看=]
我一直在尝试将内容协商作为我的 SpringBoot/Kotlin 应用程序的后端版本控制。我有以下内容:
@GetMapping("/user", produces = [MediaType.APPLICATION_JSON_VALUE])
fun getUsers() {
//some code here
}
我发现 this project 结合了 accept" header 和 "Accept-Version" 自定义 header。我想知道这是否是实施内容协商方法的正确方法,并且如果不能,我该如何解决?
@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
}
谢谢
是的,您可以通过指定的自定义 header 和 header 值使用内容协商实施 API 版本控制。但是,由于这不是标准 header,因此您可能需要自己处理其他情况,例如:
- header 不存在时的默认表示
- 作为 header. 的一部分传递无效媒体类型值时的异常情况
如果您只处理 json 响应,JSON API standard for content negotiation is to send the Accept
header with the value application/vnd.api+json
. Since Accept 是标准请求 header,最好使用它。如果您需要处理其他类型的响应,您仍然可以继续使用自定义 header。
您可以按如下方式实现内容协商:
@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
header.
GET /users
端点的 2 个版本
当使用 header 值的 v1 发出 curl 请求时,响应将根据 version v1
curl -L -X GET 'http://localhost:8080/users' \
-H 'Accept: application/vnd.v1+json'
[
{
"name": "Abraham Lincoln"
}
]
当使用 header 值的 v2 发出 curl 请求时,响应将根据 version v2
curl -L -X GET 'http://localhost:8080/users' \
-H 'Accept: application/vnd.v2+json'
[
{
"name": {
"firstName": "Abraham",
"lastName": "Lincoln"
}
}
]
当发送无效的 header 值时,它会以 406 Not Acceptable
响应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
header时,它会返回默认版本,即v1这里
curl -L -X GET 'http://localhost:8080/users'
[
{
"name": "Abraham Lincoln"
}
]
甚至 GitHub 也以类似的方式通过内容协商实现了版本控制,您可以在他们的 documentation.[=22 中查看=]