# Versionary

Add versioning to your Elixir Plug and Phoenix built API's

[![Coverage Status](](

## Installation

The package can be installed by adding `versionary` to your list of dependencies
in `mix.exs`:

def deps do
  [{:versionary, "~> 0.3"}]

## Usage

def MyAPI.Router do
  use Plug.Router

  plug Versionary.Plug.VerifyHeader, versions: ["application/"]

  plug Versionary.Plug.EnsureVersion, handler: MyAPI.MyErrorHandler

  plug :match
  plug :dispatch

## MIME Support

It's possible to verify versions against configured MIME types. If multiple MIME
types are passed and at least one matches the version will be considered valid.

config :mime, :types, %{
  "application/" => [:v1],
  "application/" => [:v2]

plug Versionary.Plug.VerifyHeader, accepts: [:v1, :v2]

Please note that whenever you change media type configurations you must
recompile the `mime` library.

To force `mime` to recompile run `mix deps.clean --build mime`.

## Identifying Versions

When a version has been verified `:version` and `:raw_version` private keys will
be added to the conn. These keys will contain version that has been verified.

The `:version` key may contain either the string version provided by the
request or, if configured, the MIME extension. The `:raw_version` key will
always contain the string version provided by the request.

## Phoenix

Versionary is just a plug. That means Versionary works with Phoenix out of the
box. However, if you'd like Versionary to render a Phoenix error view when
verification fails use `Versionary.Plug.PhoenixErrorHandler`.

defmodule MyAPI.Router do
  use MyAPI.Web, :router

  pipeline :api do
    plug Versionary.Plug.VerifyHeader, accepts: [:v1, :v2]

    plug Versionary.Plug.EnsureVersion, handler: Versionary.Plug.PhoenixErrorHandler

  scope "/", MyAPI do
    pipe_through :api

    get "/my_controllers", MyController, :index

### Handling Multiple Versions

You can pattern match which version of a controller action to run based on the
`:version` (or `:raw_version`) private key provided by the conn.

defmodule MyAPI.MyController do
  use MyAPI, :controller

  def index(%{private: %{version: [:v1]}} = conn, _params) do
    render(conn, "index.v1.json", %{})

  def index(%{private: %{version: [:v2]}} = conn, _params) do
    render(conn, "index.v2.json", %{})

## Plug API

### [Versionary.Plug.VerifyHeader](

Verify that the version passed in to the request as a header is valid. If the
version is not valid then the request will be flagged.

This plug will not handle an invalid version. If you would like to halt the
request and handle an invalid version please see

#### Options

`accepts` - a list of strings or atoms representing versions registered as
MIME types. If at least one of the registered versions is valid then the
request is considered valid.

`versions` - a list of strings representing valid versions. If at least one of
the provided versions is valid then the request is considered valid.

`header` - the header used to provide the requested version (Default: `Accept`)

### [Versionary.Plug.EnsureVersion](

Checks to see if the request has been flagged with a valid version. If the
version is valid, the request continues, otherwise the request will halt and the
handler will be called to process the request.

#### Options

`handler` - the module used to handle a request with an invalid version
(Default: [Versionary.Plug.ErrorHandler](

### [Versionary.Plug.Handler](

Behaviour for handling requests with invalid versions. You can create your own
custom handler with this behaviour.