English 中文(简体)
正在版本 REST API
原标题:Versioning REST API
  • 时间:2012-05-24 17:39:28
  •  标签:
  • rest

在阅读了很多关于REST版本的材料之后,我正在考虑改用电话而不是API。例如:

http://api.mydomain.com/callfoo/v2.0/param1/param2/param3
http://api.mydomain.com/verifyfoo/v1.0/param1/param2

而不是第一次拥有

http://api.mydomain.com/v1.0/callfoo/param1/param2
http://api.mydomain.com/v1.0/verifyfoo/param1/param2

然后开始

http://api.mydomain.com/v2.0/callfoo/param1/param2/param3
http://api.mydomain.com/v2.0/verifyfoo/param1/param2

我看到的好处是:

  • When the calls change, I do not have to rewrite my entire client - only the parts that are affected by the changed calls.
  • Those parts of the client that work can continue as is (we have a lot of testing hours invested to ensure both the client and the server sides are stable.)
  • I can use permanent or non-permanent redirects for calls that have changed.
  • Backward compatibility would be a breeze as I can leave older call versions as is.

我错过什么了吗?

最佳回答

需要 HTTP 信头 。

Version: 1

http://www.w3.org/href="http://www.w3.org/processions/HTTP/Object_headers.html#z13" rel=“nofollow norefererr" >Version header临时注册在>RFC 4229 ,以及避免使用X前缀或特定使用URI的一些合理理由。

X-API-Version: 1

在任一情况下,如果页眉丢失或与服务器能够提供的内容不匹配,请发送一个 < enger> > 412 先决条件失败 < /strong > 响应代码以及失败原因。这要求客户端指定他们每次支持的版本,但强制执行客户端和服务器之间一致的响应。 (可选择支持 < code>?version* /code> 查询参数会给客户额外一点灵活性。 )

这种办法简单易行,易于执行,符合标准。

Alternatives

我知道,一些非常聪明、用意良好的人已经建议了 URL 版本和内容谈判。 在某些案例中,以及在某些他们通常提出的形式上,两者都存在重大问题。

URL Versioning

如果您控制了所有服务器和客户端, 端点/ 服务 URL 版本将有效 。 否则, 您需要处理更新的客户端, 回到旧服务器上, 最后会使用定制的 HTTP 信头, 因为安装在您控制范围外的不同服务器上的服务器软件的系统管理员可以做各种事情来破坏您认为很容易解析的 URL, 如果您使用“ 坚固” 302 移动临时

Content Negotiation

通过 Accept heaker 进行的内容谈判有效,如果您对遵守 HTTP 标准非常关切,但同时也想忽略 HTTP/1.1 标准文档实际上说的是什么。您所看到的提议的 MIME 类型是窗体 < code> application/vnd.example.v1+json 。 有几个问题:

  1. There are cases where the vendor extensions are actually appropriate, of course, but slightly different communication behaviors between client and server doesn t really fit the definition of a new media type . Also, RFC 2616 (HTTP/1.1) reads, "Media-type values are registered with the Internet Assigned Number Authority. The media type registration process is outlined in RFC 1590. Use of non-registered media types is discouraged." I don t want to see a separate media type for every version of every software product that has a REST API.
  2. Any subtype ranges (e.g., application/*) don t make sense. For REST APIs that return structured data to clients for processing and formatting, what good is accepting */* ?
  3. The Accept header takes some effort to parse correctly. There s both an implied and explicit precedence that should be followed to minimize the back-and-forth required to actually do content negotiation correctly. If you re concerned about implementing this standard correctly, this is important to get right.
  4. RFC 2616 (HTTP/1.1) describes the behavior for any client that does not include an Accept header: "If no Accept header field is present, then it is assumed that the client accepts all media types." So, for clients you don t write yourself (where you have the least control), the most correct thing to do would be to respond to requests using the newest, most prone-to-breaking-old-versions version that the server knows about. In other words, you could have not implemented versioning at all and those clients would still be breaking in exactly the same way.

<强度 > 编辑,2014 :

我读过许多其他答案和大家深思熟虑的评论;

  1. Don t use an X- prefix. I think Accept-Version is probably more meaningful in 2014, and there are some valid concerns about the semantics of re-using Version raised in the comments. There s overlap with defined headers like Content-Version and the relative opaqueness of the URI for sure, and I try to be careful about confusing the two with variations on content negotiation, which the Version header effectively is. The third version of the URL https://example.com/api/212315c2-668d-11e4-80c7-20c9d048772b is wholly different than the second , regardless of whether it contains data or a document.
  2. Regarding what I said above about URL versioning (endpoints like https://example.com/v1/users, for instance) the converse probably holds more truth: if you control all servers and clients, URL/URI versioning is probably what you want. For a large-scale service that could publish a single service URL, I would go with a different endpoint for every version, like most do. My particular take is heavily influenced by the fact that the implementation as described above is most commonly deployed on lots of different servers by lots of different organizations, and, perhaps most importantly, on servers I don t control. I always want a canonical service URL, and if a site is still running the v3 version of the API, I definitely don t want a request to https://example.com/v4/ to come back with their web server s 404 Not Found page (or even worse, 200 OK that returns their homepage as 500k of HTML over cellular data back to an iPhone app.)
  3. If you want very simple /client/ implementations (and wider adoption), it s very hard to argue that requiring a custom header in the HTTP request is as simple for client authors as GET-ting a vanilla URL. (Although authentication often requires your token or credentials to be passed in the headers, anyway. Using Version or Accept-Version as a secret handshake along with an actual secret handshake fits pretty well.)
  4. Content negotiation using the Accept header is good for getting different MIME types for the same content (e.g., XML vs. JSON vs. Adobe PDF), but not defined for versions of those things (Dublin Core 1.1 vs. JSONP vs. PDF/A). If you want to support the Accept header because it s important to respect industry standards, then you won t want a made-up MIME Type interfering with the media type negotiation you might need to use in your requests. A bespoke API version header is guaranteed not to interfere with the heavily-used, oft-cited Accept, whereas conflating them into the same usage will just be confusing for both server and client. That said, namespacing what you expect into a named profile per 2013 s RFC6906 is preferable to a separate header for lots of reasons. This is pretty clever, and I think people should seriously consider this approach.
  5. Adding a header for every request is one particular downside to working within a stateless protocol.
  6. Malicious proxy servers can do almost anything to destroy HTTP requests and responses. They shouldn t, and while I don t talk about the Cache-Control or Vary headers in this context, all service creators should carefully consider how their content is consumed in lots of different environments.
问题回答

这是一个意见问题;在这里,我还有意见背后的动机。

  1. include the version in the URL.
    For those who say, it belongs in the HTTP header, I say: maybe. But putting in the URL is the accepted way to do it according to the early leaders in the field. (Google, yahoo, twitter, and more). This is what developers expect and doing what developers expect, in other words acting in accordance with the principle of least astonishment, is probably a good idea. It absolutely does not make it "harder for clients to upgrade". If the change in URL somehow represents an obstacle to the developer of a consuming application, as suggested in a different answer here, that developer needs to be fired.

  2. Skip the minor version
    There are plenty of integers. You re not gonna run out. You don t need the decimal in there. Any change from 1.0 to 1.1 of your API shouldn t break existing clients anyway. So just use the natural numbers. If you like to use separation to imply larger changes, you can start at v100 and do v200 and so on, but even there I think YAGNI and it s overkill.

  3. Put the version leftmost in the URI
    Presumably there are going to be multiple resources in your model. They all need to be versioned in synchrony. You can t have people using v1 of resource X, and v2 of resource Y. It s going to break something. If you try to support that it will create a maintenance nightmare as you add versions, and there s no value add for the developer anyway. So, http://api.mydomain.com/v1/Resource/12345 , where Resource is the type of resource, and 12345 gets replaced by the resource id.

你没有问,但是...

  1. Omit verbs from your URL path
    REST is resource oriented. You have things like "CallFoo" in your URL path, which looks suspiciously like a verb, and unlike a noun. This is wrong. Use the Force, Luke. Use the verbs that are part of REST: GET PUT POST DELETE and so on. If you want to get the verification on a resource, then do GET http://domain/v1/Foo/12345/verification. If you want to update it, do POST /v1/Foo/12345.

  2. Put optional params as a query param or payload
    The optional params should not be in the URL path (before the first question mark) unless you are suggesting that those optional params constitute a self-standing resource. So, POST /v1/Foo/12345?action=partialUpdate&param1=123&param2=abc.

不要做任何那些事情, 因为它们将版本推入 URI 结构, 而这将对您的客户端应用程序有不利之处。 这将使他们更难升级, 以利用您应用程序中的新功能 。

相反, 您应该版本您的媒体类型, 而不是您的 URI 。 这将给予您最大的灵活性和进化能力 。 更多信息, 请参见 < a href=" https:// stackoverflow. com/ questions/ 8993467/ rest- vs- soap- vollable8995061# 8995061> > 我给另一个问题的答复 < / a > 。

它取决于您在 API 中如何调用版本, 如果您将版本调用到实体的不同表达形式( xml, json 等), 那么您应该使用接受信头或自定义信头。 这是 http 设计用于与表达方式合作的方式 。 它是 REST 的, 因为如果我同时调用同一资源但要求不同的表达方式, 被退回的实体将拥有完全相同的信息和属性结构, 但格式不同, 这种版本是整形的 。

在另一方面,如果你将版本理解为实体结构的变化,例如给用户实体添加一个字段年龄。然后,你应该从资源的角度来看待这个问题,我认为这种观点是“再入门”的方法。正如Roy Fielding在其解析中描述的那样......REST资源是从识别符到一组实体的绘图......因此,在改变一个实体的结构时,你需要有一个指向该版本的适当资源。这种版本是结构性的。

我在以下网站发表了类似的评论:http://codebetter.com/howardddierking/2012/11/09/versioning-restful-services/

使用 url 版本版本时, 版本应较晚更新, 而不是更早在 url 中 :

GET/DELETE/PUT onlinemall.com/grocery-store/customer/v1/{id}
POST onlinemall.com/grocery-store/customer/v1

另一种以更清洁的方式这样做的方式,但在实施时可能会有问题:

GET/DELETE/PUT onlinemall.com/grocery-store/customer.v1/{id}
POST onlinemall.com/grocery-store/customer.v1

这样做可以让客户具体要求他们想要哪些资源来绘制他们需要的实体的地图,而不必乱用标题和定制媒体类型,因为这些类型在生产环境中实施时确实存在问题。

此外,在URL晚期还使用URL,使客户在具体选择他们需要的资源时,即使在方法层面上,也能够拥有更多的颗粒性。

但从开发者的角度来说,最重要的事情是,你不需要维持每个版本的所有资源和方法的整个绘图(路径 ) 。 当你拥有大量子资源( 集合资源 ) 时, 这非常有价值。

从执行的角度来看,从资源水平来看,执行起来确实容易,例如,如果使用泽西岛/JAX-RS:

@Path("/customer")
public class CustomerResource {
    ...
    @GET
    @Path("/v{version}/{id}")
    public IDto getCustomer(@PathParam("version") String version, @PathParam("id") String id) {
         return locateVersion(version, customerService.findCustomer(id));
    }
    ...
    @POST
    @Path("/v1")
    @Consumes(MediaType.APPLICATION_JSON)
    public IDto insertCustomerV1(CustomerV1Dto customer) {
         return customerService.createCustomer(customer);
    }

    @POST
    @Path("/v2")
    @Consumes(MediaType.APPLICATION_JSON)
    public IDto insertCustomerV2(CustomerV2Dto customer) {
         return customerService.createCustomer(customer);
    }
...
}

IDto 只是一个返回多色对象的界面, CopenV1 和 CopenV2 执行该界面 。

Facebook 是否 verisoning < a href=" https://www.google.com/url?q= https% 3A% 2F% 2Fblog.apigee.com%2Fdetail%2Frestful_apil_deign_tips_for_version&sa=D&sntz=1&usg=AFQjCNEdjV_8IoRvgzK-qLTUWC0nN3neA" rel=“no follow” > in url 。 我觉得 url 版本更清洁,在真实世界中更容易维持。

. Net 使得这种版本非常容易:

[HttpPost]
[Route("{version}/someCall/{id}")]
public HttpResponseMessage someCall(string version, int id))




相关问题
Allow RESTful DELETE method in asp.net mvc?

im currently setting up asp.net to accept DELETE http verb in the application. However, when i send "DELETE /posts/delete/1" i always get a 405 Method not allow error. I tried to take a look at ...

Most appropriate API for URL shortening service

I ve just finished an online service for shortening URLs (in php5 with Zend Framework); you can enter an URL and you get an short URL (like tinyurl and such sites). I m thinking about the API for ...

Use HTTPClient or HttpUrlConnection? [closed]

We re implementing a REST client on JRE 1.4. Seems two good options for a client REST framework are HttpClient and HttpUrlConnection. Is there a reason to use HttpClient over the JRE s ...

Why can t I find the truststore for an SSL handshake?

I m using the Spring RESTTemplate on the client side to make calls to a REST endpoint. The client in this case is a Spring app and Tomcat is the servlet container. I m running into issues making a ...

Which Http redirects status code to use?

friendfeed.com uses 302. bit.ly uses 301. I had decided to use 303. Do they behave differently in terms of support by browsers ?

Three Step Buyonline The RESTful way

We are re-developing our buyonline functionality and we are doing it the RESTful way. The process is a three step one and the customer is asked to enter data at each step. Let s say the three URL s ...

热门标签