代码之家  ›  专栏  ›  技术社区  ›  Mike Pone

如何版本REST URI

  •  103
  • Mike Pone  · 技术社区  · 15 年前

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

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

    对于此表示的版本4。

    版本是否属于查询字符串?IE.

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

    或者版本控制是以另一种方式完成的?

    11 回复  |  直到 6 年前
        1
  •  30
  •   Zef Hemel    15 年前

    我想说让它成为URI本身的一部分(选项1)是最好的,因为v4标识的是与v3不同的资源。第二个选项中的查询参数最好用于传递与 请求 而不是 资源 .

        2
  •  191
  •   Matt Hamilton    13 年前

    不要版本URL,因为…

    • 你打破了永久性
    • URL更改将像疾病一样通过接口传播。对于未更改但指向已更改的表示,您将如何处理这些表示?如果更改URL,则会破坏旧客户机。如果离开URL,新客户机可能无法工作。
    • 版本控制媒体类型是一个更灵活的解决方案。

    假设您的资源返回了application/vnd.yourcompany.user+xml的一些变体,那么您所需要做的就是为新的application/vnd.yourcompany.user v2+xml媒体类型创建支持,并且通过内容协商的魔力,v1和v2客户机可以和平共存。

    在一个RESTful接口中,与契约最接近的是在客户机和服务器之间交换的媒体类型的定义。

    客户端用来与服务器交互的URL应该由嵌入在先前检索的表示中的服务器提供。客户机需要知道的唯一URL是接口的根URL。仅当您在客户机上构造URL时,向URL添加版本号才有价值,而这不应该与RESTful接口有关。

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

    对于那些现在说如果我使用application/xml和application/json作为媒体类型,这是没有意义的。我们该如何修改这些版本?你不是。对于RESTful接口来说,这些媒体类型几乎是无用的,除非您使用代码下载来解析它们,此时版本控制是一个无意义的问题。

        3
  •  21
  •   Ruben Bartelink    8 年前

    啊,我又戴上了我的旧帽子。

    从休息的角度来看,这一点都不重要。不是香肠。

    客户机接收一个它想要遵循的URI,并将其视为一个不透明的字符串。把你想要的放进去,客户已经 对它上面的版本标识符之类的知识。

    客户知道它可以处理媒体类型,我建议遵循Darrel的建议。此外,我个人认为,4次更改RESTful体系结构中使用的格式应该会带来巨大的警告信号,表明您正在做严重错误的事情,完全不需要设计用于更改的媒体类型。

    但是无论哪种方式,客户机都只能处理具有它可以理解的格式的文档,并跟踪其中的链接。它应该知道链接关系(转换)。所以URI中的内容完全不相关。

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

    一个完全有效的标识符,它将阻止任何进一步的客户端开发人员或接触系统的人质疑是否应该将v4放在URI的开头或结尾(从服务器的角度来看,我建议您不应该有4个版本,而应该有4个媒体类型)。

        4
  •  11
  •   Community Michael Schmitz    7 年前

    您不应该将版本放在URL中,应该将版本放在请求的接受头中-请参阅我在该线程上的文章:

    Best practices for API versioning?

    如果您开始在URL中粘贴版本,则会得到如下愚蠢的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
  •  5
  •   Community Michael Schmitz    7 年前

    这些(不太具体)使得有关RESTAPI版本控制的问题可能会有所帮助:

        6
  •  2
  •   UberSteve    11 年前

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

    不幸的是,此解决方案仅适用于基于身份验证的API。但是,它确实将版本排除在URI之外。

        7
  •  2
  •   Asma Zubair    11 年前

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

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

    在“我希望对我的API进行版本控制”一节中有一小部分。我发现它简单易懂。关键是使用头中的accept字段来传递版本信息。

        8
  •  1
  •   Paul Morgan    15 年前

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

        9
  •  1
  •   inf3rno    10 年前

    如果使用uri进行版本控制,那么版本号应该在api根的uri中,因此每个资源标识符都可以包含它。

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

    自定义mime类型和mime类型版本控制没有帮助,因为将相关的元数据和表示结构放入短字符串中不起作用。办公室。元数据和结构经常会改变,所以版本号也会改变…

    所以回答你的问题,最好的方法就是用发声来注释你的请求和回答。( Hydra , linked data )忘记版本控制,或者只通过不向后兼容的vocab更改来使用它(例如,如果您想用另一个vocab替换一个vocab)。

        10
  •  0
  •   Yarco    7 年前

    我投票赞成在mime类型而不是url中这样做。 但原因和其他人不同。

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

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

        11
  •  0
  •   Javier C. Issac Balaji    6 年前

    有4种不同的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网关来实现这一点。