如何最好地对 REST URI 进行版本控制?目前我们在 URI 本身中使用版本号,例如:
http://example.com/users/v4/1234/
适用于此表示形式的版本4。
版本号是否应该包含在查询字符串中?也就是说:
http://example.com/users/1234?version=4
或者说,版本控制最好通过其他方式来完成吗?
如何最好地对 REST URI 进行版本控制?目前我们在 URI 本身中使用版本号,例如:
http://example.com/users/v4/1234/
适用于此表示形式的版本4。
版本号是否应该包含在查询字符串中?也就是说:
http://example.com/users/1234?version=4
或者说,版本控制最好通过其他方式来完成吗?
不要对URL进行版本控制,因为...
假设你的资源返回的是应用程序/vnd.yourcompany.user+xml的某个变体,那么你所需要做的就是创建一个新的application/vnd.yourcompany.userV2+xml媒体类型的支持,并通过内容协商的神奇机制使v1和v2客户端可以和平共存。
在RESTful接口中,你拥有的与契约最接近的东西是在客户端和服务器之间交换的媒体类型的定义。
客户端用于与服务器交互的URL应该由服务器在先前检索到的表示形式中嵌入提供。客户端唯一需要知道的URL是接口的根URL。将版本号添加到URL中只有在客户端构造URL时才有价值,而这在RESTful接口中是不应该做的。
如果你需要对可能破坏现有客户端的媒体类型进行更改,那么就创建一个新的并保留你的URL!
对于那些当前正在使用application/xml和application/json作为媒体类型的读者来说,他们可能会认为这没有任何意义。我们应该如何对它们进行版本控制?不需要做版本控制。除非你使用代码下载来解析它们,否则这些媒体类型对于RESTful接口来说几乎无用,此时版本控制是无意义的。
我认为将其作为URI本身的一部分(选项1)是最好的选择,因为v4标识的是与v3不同的资源。像您第二个选项中的查询参数可以最好地用于传递与请求相关的其他(查询)信息,而不是资源。
啊,我又戴上了我的老脾气帽子。
从ReST的角度来看,这一点都不重要。毫无意义。
客户端接收到一个它想要跟随的URI,并将其视为不透明的字符串。在其中放置任何你想要的内容,客户端对版本标识符一无所知。
客户端知道的是它可以处理媒体类型,我会建议遵循达雷尔的建议。而且我个人认为,在restful架构中需要4次更改使用的格式,应该引起巨大的警示,你正在做一些非常错误的事情,并完全绕过了为变化弹性设计你的媒体类型的需求。
但无论哪种方式,客户端只能处理它可以理解的格式的文档,并在其中跟随链接。它应该知道链接关系(转换)。因此,URI中的内容完全无关紧要。
我个人会投票支持http://localhost/3f3405d5-5984-4683-bf26-aca186d21c04
这是一个完全有效的标识符,将防止任何进一步的客户端开发人员或操作此系统的人质疑是否应该在URI的开头或末尾放置v4(我建议从服务器的角度来看,你不应该有4个版本,而应该有4个媒体类型)。
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/
还会出现一堆其他问题-请参阅我的博客:http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html
API的版本控制有四种不同的方法:
Adding version to the URI path:
http://example.com/api/v1/foo
http://example.com/api/v2/foo
When you have breaking change, you must increment the version like: v1, v2, v3...
You can implement a controller in you code like this:
@RestController
public class FooVersioningController {
@GetMapping("v1/foo")
public FooV1 fooV1() {
return new FooV1("firstname lastname");
}
@GetMapping("v2/foo")
public FooV2 fooV2() {
return new FooV2(new Name("firstname", "lastname"));
}
Request parameter versioning:
http://example.com/api/v2/foo/param?version=1
http://example.com/api/v2/foo/param?version=2
The version parameter can be optional or required depending on how you want the API to be used.
The implementation can be similar to this:
@GetMapping(value = "/foo/param", params = "version=1")
public FooV1 paramV1() {
return new FooV1("firstname lastname");
}
@GetMapping(value = "/foo/param", params = "version=2")
public FooV2 paramV2() {
return new FooV2(new Name("firstname", "lastname"));
}
Passing a custom header:
http://localhost:8080/foo/produces
With header:
headers[Accept=application/vnd.company.app-v1+json]
or:
headers[Accept=application/vnd.company.app-v2+json]
Largest advantage of this scheme is mostly semantics: You aren’t cluttering the URI with anything to do with the versioning.
Possible implementation:
@GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v1+json")
public FooV1 producesV1() {
return new FooV1("firstname lastname");
}
@GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v2+json")
public FooV2 producesV2() {
return new FooV2(new Name("firstname", "lastname"));
}
Changing Hostnames or using API Gateways:
Essentially, you’re moving the API from one hostname to another. You might even just call this building a new API to the same resources.
Also,you can do this using API Gateways.
我想创建版本化的API,发现这篇文章非常有用:
http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http
有一个关于“我希望我的API有版本控制”的小节。我发现它简单易懂。关键在于使用头部中的Accept字段传递版本信息。