Elixir package that allows to add compatibility layers via API gateways.
This plug helps to manage multiple API versions based on request and response gateways. This is an awesome practice to hide your backward compatibility. It allows to have your code in a latest possible version, without duplicating controllers or models. We use it in production.
Inspired by Stripe API. Read more at MOVE FAST, DON'T BREAK YOUR API or API versioning.
Multiverse allows you to use a custom adapter which can, for eg.:
v1
, v2
);Default adapter works with ISO-8601 date from x-api-version
header (configurable). For malformed versions it would log a warning and fallback to the default date (configured via :default_version
setting):
:first
- apply all gates by default. This option is useful when you integrate Multiverse in existing project and API consumers are not ready to accept latest changes by default;:latest
- user current date as default version. This option is useful when there are no legacy clients or there was no breaking changes before those clients started to send API version.ISO date adapter allows API clients to use channel name instead of date:
latest
channel would fallback to the current date;edge
channel would disable all changes altogether.Channels allow you to plan version releases upfront and test them without affecting users,
just set future date for a change and pass it explicitly or use edge
channel to test latest
application version.
The package (take look at hex.pm) can be installed as:
multiverse
to your list of dependencies in mix.exs
:def deps do
[{:multiverse, "~> 2.0.0"}]
end
multiverse
is available at runtime in your production:def application do
[applications: [:multiverse]]
end
router.ex
):pipeline :api do
plug :accepts, ["json"]
plug :put_secure_browser_headers
plug Multiverse, default_version: :latest
end
defmodule AccountTypeChange do
@behaviour Multiverse.Change
def handle_request(%Plug.Conn{} = conn) do
# Mutate your request here
IO.inspect "AccountTypeChange.handle_request applied to request"
conn
end
def handle_response(%Plug.Conn{} = conn) do
# Mutate your response here
IO.inspect "AccountTypeChange.handle_response applied to response"
conn
end
end
pipeline :api do
plug :accepts, ["json"]
plug :put_secure_browser_headers
plug Multiverse,
default_version: :latest,
gates: %{
~D[2016-07-21] => [AccountTypeChange]
}
end
X-API-Version
header with version lower or equal to 2016-07-20
.You can use any version headers by passing option to Multiverse:
pipeline :api do
plug :accepts, ["json"]
plug :put_secure_browser_headers
plug Multiverse,
default_version: :latest,
version_header: "x-my-version-header",
gates: %{
~D[2016-07-21] => [AccountTypeChange]
}
end
You can use your own adapter which implements Multiverse.Adapter
behaviour:
pipeline :api do
plug :accepts, ["json"]
plug :put_secure_browser_headers
plug Multiverse,
default_version: :latest,
adapter: MyApp.SmartMultiverseAdapter,
gates: %{
~D[2016-07-21] => [AccountTypeChange]
}
end
$ ls -l test/acceptance
total 0
drwxr-xr-x 2 andrew staff 68 Aug 1 19:23 AccountTypeChange
drwxr-xr-x 2 andrew staff 68 Aug 1 19:24 OlderChange
config.ex
:use Mix.Config
config :my_app, MyApp.Endpoint,
default_version: :latest,
gates: %{
~D[2016-07-21] => [AccountTypeChange]
}
plug Multiverse, otp_app: :my_app, endpoint: __MODULE__
Generate API documentation from changes @moduledoc
's.
Other awesome stuff. Open an issue and tell me about it! :).
See LICENSE.md.