Commit 7d795c62 by Larry Ullman

First pass of edits

parent ce6f33af
Versioning Versioning
========== ==========
Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side A good API is *versioned*: changes and new features are implemented in new versions of the API instead of continually altering just one version. Unlike Web applications, with which you have full control of both the client-side and server-side
code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward code, APIs are meant to be used by clients beyond your control. For this reason, backward
compatibility (BC) of the APIs should be maintained whenever possible, and if some BC-breaking changes must be compatibility (BC) of the APIs should be maintained whenever possible. If a change that may break BC is necessary, you should introduce it in new version of the API, and bump up the version number. Existing clients can continue to use the old, working version of the API; and new or upgraded clients can get the new functionality in the new API version.
introduced to the APIs, you should bump up the version number. You may refer to [Semantic Versioning](http://semver.org/)
for more information about designing the version numbers of your APIs.
Regarding how to implement API versioning, a common practice is to embed the version number in the API URLs. > Tip: Refer to [Semantic Versioning](http://semver.org/)
For example, `http://example.com/v1/users` stands for `/users` API of version 1. Another method of API versioning for more information on designing API version numbers.
which gains momentum recently is to put version numbers in the HTTP request headers, typically through the `Accept` header,
like the following: One common way to implement API versioning is to embed the version number in the API URLs.
For example, `http://example.com/v1/users` stands for the `/users` endpoint of API version 1.
Another method of API versioning,
which has gained momentum recently, is to put the version number in the HTTP request headers. This is typically done through the `Accept` header:
``` ```
// via a parameter // via a parameter
...@@ -19,16 +21,16 @@ Accept: application/json; version=v1 ...@@ -19,16 +21,16 @@ Accept: application/json; version=v1
Accept: application/vnd.company.myapp-v1+json Accept: application/vnd.company.myapp-v1+json
``` ```
Both methods have pros and cons, and there are a lot of debates about them. Below we describe a practical strategy Both methods have their pros and cons, and there are a lot of debates about each approach. Below you'll see a practical strategy
of API versioning that is kind of a mix of these two methods: for API versioning that is a mix of these two methods:
* Put each major version of API implementation in a separate module whose ID is the major version number (e.g. `v1`, `v2`). * Put each major version of API implementation in a separate module whose ID is the major version number (e.g. `v1`, `v2`).
Naturally, the API URLs will contain major version numbers. Naturally, the API URLs will contain major version numbers.
* Within each major version (and thus within the corresponding module), use the `Accept` HTTP request header * Within each major version (and thus within the corresponding module), use the `Accept` HTTP request header
to determine the minor version number and write conditional code to respond to the minor versions accordingly. to determine the minor version number and write conditional code to respond to the minor versions accordingly.
For each module serving a major version, it should include the resource classes and the controller classes For each module serving a major version, the module should include the resource and controller classes
serving for that specific version. To better separate code responsibility, you may keep a common set of serving that specific version. To better separate code responsibility, you may keep a common set of
base resource and controller classes, and subclass them in each individual version module. Within the subclasses, base resource and controller classes, and subclass them in each individual version module. Within the subclasses,
implement the concrete code such as `Model::fields()`. implement the concrete code such as `Model::fields()`.
...@@ -86,11 +88,11 @@ return [ ...@@ -86,11 +88,11 @@ return [
]; ];
``` ```
As a result, `http://example.com/v1/users` will return the list of users in version 1, while As a result of the above code, `http://example.com/v1/users` will return the list of users in version 1, while
`http://example.com/v2/users` will return version 2 users. `http://example.com/v2/users` will return version 2 users.
Using modules, code for different major versions can be well isolated. And it is still possible Thanks to modules, the code for different major versions can be well isolated. But modules make it still possible
to reuse code across modules via common base classes and other shared classes. to reuse code across the modules via common base classes and other shared resources.
To deal with minor version numbers, you may take advantage of the content negotiation To deal with minor version numbers, you may take advantage of the content negotiation
feature provided by the [[yii\filters\ContentNegotiator|contentNegotiator]] behavior. The `contentNegotiator` feature provided by the [[yii\filters\ContentNegotiator|contentNegotiator]] behavior. The `contentNegotiator`
...@@ -101,7 +103,7 @@ For example, if a request is sent with the HTTP header `Accept: application/json ...@@ -101,7 +103,7 @@ For example, if a request is sent with the HTTP header `Accept: application/json
after content negotiation, [[yii\web\Response::acceptParams]] will contain the value `['version' => 'v1']`. after content negotiation, [[yii\web\Response::acceptParams]] will contain the value `['version' => 'v1']`.
Based on the version information in `acceptParams`, you may write conditional code in places Based on the version information in `acceptParams`, you may write conditional code in places
such as actions, resource classes, serializers, etc. such as actions, resource classes, serializers, etc. to provide the appropriate functionality.
Since minor versions require maintaining backward compatibility, hopefully there are not much Since minor versions by definition require maintaining backward compatibility, hopefully there would not be many
version checks in your code. Otherwise, chances are that you may need to create a new major version. version checks in your code. Otherwise, chances are that you may need to create a new major version.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment