如何版本REST URI

问题描述 投票:104回答:11

版本REST URI的最佳方法是什么?目前我们在URI本身有一个版本#,即。

http://example.com/users/v4/1234/

对于此表示的第4版。

该版本是否属于queryString?即。

http://example.com/users/1234?version=4

或者版本控制最好的另一种方式?

rest versioning clean-urls
11个回答
30
投票

我想说它是URI本身(选项1)的一部分是最好的,因为v4识别的资源不同于v3。像第二个选项中的查询参数最好用于传入与请求相关的附加(查询)信息,而不是资源。


1
投票

有两种不同的API版本化方法:

  • 将版本添加到URI路径: http://example.com/api/v1/foo http://example.com/api/v2/foo 如果您有更改,您必须增加版本,如:v1,v2,v3 ... 您可以在代码中实现一个控制器,如下所示: @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")); }
  • 请求参数版本控制: http://example.com/api/v2/foo/param?version=1 http://example.com/api/v2/foo/param?version=2 版本参数可以是可选的,也可以是必需的,具体取决于您希望如何使用API​​。 实现可以类似于: @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")); }
  • 传递自定义标头: http://localhost:8080/foo/produces 带标题: headers[Accept=application/vnd.company.app-v1+json] 要么: headers[Accept=application/vnd.company.app-v2+json] 这种方案的最大优点主要是语义:您不会因为与版本控制有任何关系而使URI混乱。 可能的实施: @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")); }
  • 更改主机名或使用API​​网关: 从本质上讲,您将API从一个主机名移动到另一个主机名。您甚至可以将此构建称为相同资源的新API。 此外,您可以使用API​​网关执行此操作。

0
投票

我投票支持在mime类型中执行此操作,但不在URL中。但原因与其他人不一样。

我认为URL应该是唯一的(除了那些重定向),用于定位唯一资源。那么,如果你在URL中接受/v2.0,为什么它不是/ver2.0/v2//v2.0.0?甚至-alpha-beta? (然后它完全成为semver的概念)

因此,mime类型的版本比URL更容易接受。


191
投票

不要版本URL,因为......

  • 你打破固定链接
  • 网址更改将通过您的界面像疾病一样传播。你如何处理没有改变的表示但指向具有的表示?如果您更改了网址,则会破坏旧客户端。如果您离开网址,您的新客户可能无法使用。
  • 版本化媒体类型是一种更灵活的解决方案。

假设您的资源正在返回application / vnd.yourcompany.user + xml的一些变体,您需要做的就是创建对新应用程序/ vnd.yourcompany.userV2 + xml媒体类型的支持,并通过内容协商的魔力来实现v1和v2客户可以和平共处。

在RESTful接口中,与合同最接近的是客户端和服务器之间交换的媒体类型的定义。

客户端用于与服务器交互的URL应由嵌入在先前检索的表示中的服务器提供。客户端需要知道的唯一URL是接口的根URL。如果在客户端上构建URL,则仅向URL添加版本号具有价值,您不应该使用RESTful接口。

如果您需要更改将破坏现有客户的媒体类型,请创建一个新客户并保留您的网址!

对于那些目前认为如果我使用application / xml和application / json作为媒体类型而言毫无意义的读者。我们该怎么做那些版本?你不是。这些媒体类型对RESTful接口来说几乎没用,除非你使用代码下载解析它们,此时版本控制是一个没有实际意义的点。


21
投票

啊,我又把旧的脾气暴躁的帽子放了。

从ReST的角度来看,它根本不重要。不是香肠。

客户端接收它想要遵循的URI,并将其视为不透明字符串。把你想要的东西放在里面,客户端就不知道它上面有版本标识符这样的东西。

客户知道它可以处理媒体类型,我建议遵循Darrel的建议。另外,我个人觉得需要4次更改静态架构中使用的格式应该会带来巨大的警告信号,表明您正在做一些严重错误的事情,并且完全绕过了设计媒体类型以获得更改的重要性。

但无论哪种方式,客户端只能处理其可以理解的格式的文档,并遵循其中的链接。它应该知道链接关系(转换)。那么URI中的内容完全无关紧要。

我个人会投票给http://localhost/3f3405d5-5984-4683-bf26-aca186d21c04

一个完全有效的标识符,可以防止任何进一步的客户端开发人员或触摸系统的人询问是否应该将v4放在URI的开头或末尾(我建议,从服务器的角度来看,你不应该有4个版本,但有4种媒体类型)。


11
投票

你不应该把版本放在URL中,你应该把版本放在请求的Accept Header中 - 请看我在这个帖子上的帖子:

Best practices for API versioning?

如果你开始在URL中粘贴版本,你最终会得到如下的愚蠢网址: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


5
投票

关于REST API版本控制的这些(不太具体的)SO问题可能会有所帮助:


2
投票

如果REST服务在使用前需要身份验证,您可以轻松地将API密钥/令牌与API版本相关联,并在内部进行路由。要使用新版本的API,可能需要新的API密钥,并链接到该版本。

不幸的是,此解决方案仅适用于基于身份验证的API。但是,它确实保留了URI的版本。


2
投票

我想创建版本化的API,我发现这篇文章非常有用:

http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http

有一小部分关于“我希望我的API可以进行版本化”。我发现它简单易懂。关键是在标题中使用Accept字段来传递版本信息。


1
投票

我将该版本作为可选值包含在URI的末尾。这可能是像/ V4这样的后缀或者你所描述的查询参数。您甚至可以将/ V4重定向到查询参数,以便支持这两种变体。


1
投票

如果使用URI进行版本控制,则版本号应位于API根目录的URI中,因此每个资源标识符都可以包含它。

从技术上讲,REST API不会因URL更改而中断(统一接口约束的结果)。只有当相关语义(例如API特定的RDF词汇)以非向后兼容的方式(罕见)发生变化时,它才会中断。目前很多人不使用链接进行导航(HATEOAS约束)和词汇来注释他们的REST响应(自我描述性消息约束),这就是他们的客户中断的原因。

自定义MIME类型和MIME类型版本控制没有帮助,因为将相关元数据和表示结构放入一个短字符串不起作用。 OFC。元数据和结构会经常变化,所以版本号也是......

因此,回答您的问题是使用词汇(Hydralinked data)注释您的请求和响应的最佳方式,忘记版本控制或仅使用非向后兼容的词汇更改(例如,如果您想要用另一个词汇替换词汇)。

© www.soinside.com 2019 - 2024. All rights reserved.