This document will describe how to version a REST API in a semantic manner, providing predictable releases free of breaking changes. Some of the workflow may not line up with your individual needs, but the overall concepts should be widely applicable.
The semantic version pieces that we will be discussing include the major, minor,
and patch versions as well as prerelease tags. For these definitions, consider
the version v1.2.3-alpha.0
. All semantic versions in use must have a major,
minor, and patch version and may have a prerelease tag.
1
in our example, the left-most numeral. If this number changes it
indicates that the API has introduced breaking changes which may cause
consumers to break without making code changes of their own.2
in our example, the second left-most numeral. If this number
changes it indicates that new features have been added to the API. There will
not be breaking changes for consumers but new functionality will be exposed.3
in our example, the third left-most numeral. If this number
changes it indicates a bug-fix. There will not be breaking changes for
consumers but behavior may change based on the fix.Prerelease tag – alpha.0
in our example, anything following a -
in the
version string. These tags will be used prior
to a version of the API becoming stable. Consumers may request them but must
understand the different kinds of prerelease tags and what they mean:
alpha
– the most unstable prerelease tags. Changes between alphas may
introduce breaking changes but must not break any previously stable
features.
For example: renaming a field: newField
to newFields
between alpha.0
and alpha.1
is acceptable, but renaming oldField
to oldFields
between
1.2.2
and 1.2.3-alpha.0
is not acceptable.
beta
– a more stable development state. Breaking changes and new features
must not be introduced at this point. Only bug fixes and refinements on
existing features are allowed.rc
– the most stable development state. Breaking changes, new features,
and refinements must not be introduced at this point. Only bug fixes are
allowed.Development and unstable API releases will happen in dev
environments. After
confirmation of a feature set as “stable enough” a stable release candidate
will be promoted to a staging environment. After confirmation of the release
candidate, a stable version will be released to production. Conceptually this
might look like this:
v1.0.0-alpha.1
- needs more changes so...v1.0.0-alpha.2
- confirmed stable enough to move forwardv1.0.0-rc.1
- needs more changes so…v1.0.0-rc.2
- confirmed stable enough to move forwardv1.0.0
- locked version of previously most stable rc, i.e. v1.0.0-rc.2
If a beta
or rc
release is created the previously defined rules about feature
and fix inclusion must be adhered to, or the beta
or rc
in question must
be abandoned and officially unsupported.
For example: v1.2.3-alpha.5
introduces a new feature that is confirmed to be
stable enough to move forward so v1.2.3-beta.0
is cut. Later, it is decided
a breaking change to the new feature in v1.2.3-alpha.5
needs to be introduced
in v1.2.3
. At this point v1.2.3-beta.0
must be removed and v1.2.3-alpha.6
added.
Consumers should interact with the API using npm style semver ranges. This gives maximum flexibility to API consumers, allowing them to “play it safe” and lock to a given version of the API, or provide a semver range which will allow subsequent versions to be received without modifying the consumer code.
Consumers must not lock to a prerelease tag, e.g. v1.2.3-rc.0
. The requests
will be rejected as additional changes could be introduced before the API becomes
stable.
Consumers may request a prerelease tag with a range, e.g. ^v1.2.3-rc.0
. This
will resolve in the way described by npm, but has some important features that
are worth mentioning here:
Range requests against prerelease tags will receive the next prerelease or the next stable version that satisfies the range.
For example: a request for ^v1.2.3-alpha.1
will receive the following versions
when/if they are available:
v1.2.3-alpha.2
v1.2.3-beta.0
v1.2.3-rc.0
v1.2.3
v1.2.4
v1.3.0
The same request would not receive v1.3.0-alpha.0
, or any prereleases for that
matter, on versions outside of the major, minor, and patch versions defined by
the original prerelease range.
Consumers may lock to a stable version or request a range from a stable version,
e.g. v1.2.3
and ^v1.2.3
. While v1.2.3
is the latest stable version in the
v1
family, these two requests will resolve the same way. As soon as a new minor
or patch version is added the request for ^v1.2.3
would receive the new version.
Implementing servers should provide a meta
style attribute to all responses
that describes the version that the request resolved to. In JSON API with a
request for /^v1.0.0/authors
and a highest stable version of v1.2.3
this
would look like this:
{
“data”: [],
“meta” : {
“version”: “v1.2.3”
}
}
Implementing servers should enforce strict semantic version matching and
reject any request for an invalid version. This approach is preferable over
attempting to route invalid or partial versions (e.g. v1.2
) to the correct
and valid version.