{"id":13508009,"url":"https://github.com/Nebo15/multiverse","last_synced_at":"2025-03-30T09:33:16.733Z","repository":{"id":62429947,"uuid":"64608881","full_name":"Nebo15/multiverse","owner":"Nebo15","description":"Elixir package that allows to add compatibility layers via API gateways.","archived":false,"fork":false,"pushed_at":"2019-08-23T14:39:47.000Z","size":96,"stargazers_count":94,"open_issues_count":6,"forks_count":11,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-24T09:05:30.348Z","etag":null,"topics":["api","elixir","elixir-lang","gateways","hex","plug","versioning"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/multiverse","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nebo15.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-31T18:29:55.000Z","updated_at":"2025-02-14T16:04:59.000Z","dependencies_parsed_at":"2022-11-01T19:47:28.322Z","dependency_job_id":null,"html_url":"https://github.com/Nebo15/multiverse","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nebo15%2Fmultiverse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nebo15%2Fmultiverse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nebo15%2Fmultiverse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nebo15%2Fmultiverse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nebo15","download_url":"https://codeload.github.com/Nebo15/multiverse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246301963,"owners_count":20755512,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","elixir","elixir-lang","gateways","hex","plug","versioning"],"created_at":"2024-08-01T02:00:45.374Z","updated_at":"2025-03-30T09:33:16.413Z","avatar_url":"https://github.com/Nebo15.png","language":"Elixir","readme":"# Multiverse\n\n[![Deps Status](https://beta.hexfaktor.org/badge/all/github/Nebo15/multiverse.svg)](https://beta.hexfaktor.org/github/Nebo15/multiverse) [![Hex.pm Downloads](https://img.shields.io/hexpm/dw/multiverse.svg?maxAge=3600)](https://hex.pm/packages/multiverse) [![Latest Version](https://img.shields.io/hexpm/v/multiverse.svg?maxAge=3600)](https://hex.pm/packages/multiverse) [![License](https://img.shields.io/hexpm/l/multiverse.svg?maxAge=3600)](https://hex.pm/packages/multiverse) [![Build Status](https://travis-ci.org/Nebo15/multiverse.svg?branch=master)](https://travis-ci.org/Nebo15/multiverse) [![Coverage Status](https://coveralls.io/repos/github/Nebo15/multiverse/badge.svg?branch=master)](https://coveralls.io/github/Nebo15/multiverse?branch=master) [![Ebert](https://ebertapp.io/github/Nebo15/multiverse.svg)](https://ebertapp.io/github/Nebo15/multiverse)\n\nThis 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.\n\n![Compatibility Layers](http://amberonrails.com/images/posts/move-fast-dont-break-your-api/compatibility-layers.png \"Compatibility Layers\")\n\nInspired by Stripe API. Read more at [MOVE FAST, DON'T BREAK YOUR API](http://amberonrails.com/move-fast-dont-break-your-api/) or [API versioning](https://stripe.com/blog/api-versioning).\n\n## Goals\n\n  - reduce changes required to support multiple API versions;\n  - provide a way to test and schedule API version releases;\n  - to have minimum dependencies and low performance hit;\n  - to be flexible enough for most of projects to adopt it.\n\n## Adapters\n\nMultiverse allows you to use a custom adapter which can, for eg.:\n\n  - store consumer version upon his first request and re-use it as default each time consumer is using your API, eliminating need of passing version headers for them (a.k.a. version pinning). Change this version when consumer has explicitly set it;\n  - use _other than ISO date_ version types, eg. incremental counters (`v1`, `v2`);\n  - handle malformed versions by responding with JSON errors.\n\nDefault 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](https://hexdocs.pm/multiverse/2.0.0/Multiverse.Adapters.ISODate.html)):\n\n  - `: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;\n  - `: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.\n\nISO date adapter allows API clients to use channel name instead of date:\n\n  - `latest` channel would fallback to the current date;\n  - `edge` channel would disable all changes altogether.\n\nChannels allow you to plan version releases upfront and test them without affecting users,\njust set future date for a change and pass it explicitly or use `edge` channel to test latest\napplication version.\n\n## Installation\n\nThe package (take look at [hex.pm](https://hex.pm/packages/multiverse)) can be installed as:\n\n  1. Add `multiverse` to your list of dependencies in `mix.exs`:\n\n  ```elixir\n  def deps do\n    [{:multiverse, \"~\u003e 2.0.0\"}]\n  end\n  ```\n\n  2. Make sure that `multiverse` is available at runtime in your production:\n\n  ```elixir\n  def application do\n    [applications: [:multiverse]]\n  end\n  ```\n\n## How to use\n\n  1. Insert this plug into your API pipeline (in your ```router.ex```):\n\n  ```elixir\n  pipeline :api do\n    plug :accepts, [\"json\"]\n    plug :put_secure_browser_headers\n\n    plug Multiverse, default_version: :latest\n  end\n  ```\n\n  2. Define module that handles change\n\n  ```elixir\n  defmodule AccountTypeChange do\n    @behaviour Multiverse.Change\n\n    def handle_request(%Plug.Conn{} = conn) do\n      # Mutate your request here\n      IO.inspect \"AccountTypeChange.handle_request applied to request\"\n      conn\n    end\n\n    def handle_response(%Plug.Conn{} = conn) do\n      # Mutate your response here\n      IO.inspect \"AccountTypeChange.handle_response applied to response\"\n      conn\n    end\n  end\n  ```\n\n  3. Enable the change:\n\n  ```elixir\n  pipeline :api do\n    plug :accepts, [\"json\"]\n    plug :put_secure_browser_headers\n\n    plug Multiverse,\n      default_version: :latest,\n      gates: %{\n        ~D[2016-07-21] =\u003e [AccountTypeChange]\n      }\n  end\n  ```\n\n  4. Send your API requests with ```X-API-Version``` header with version lower or equal to ```2016-07-20```.\n\n### Overriding version header\n\n  You can use any version headers by passing option to Multiverse:\n\n  ```elixir\n  pipeline :api do\n    plug :accepts, [\"json\"]\n    plug :put_secure_browser_headers\n\n    plug Multiverse,\n      default_version: :latest,\n      version_header: \"x-my-version-header\",\n      gates: %{\n        ~D[2016-07-21] =\u003e [AccountTypeChange]\n      }\n  end\n  ```\n\n### Using custom adapters\n\n  You can use your own adapter which implements `Multiverse.Adapter` behaviour:\n\n  ```elixir\n  pipeline :api do\n    plug :accepts, [\"json\"]\n    plug :put_secure_browser_headers\n\n    plug Multiverse,\n      default_version: :latest,\n      adapter: MyApp.SmartMultiverseAdapter,\n      gates: %{\n        ~D[2016-07-21] =\u003e [AccountTypeChange]\n      }\n  end\n  ```\n\n## Structuring your tests\n\n  1. Split your tests into versions:\n\n    $ ls -l test/acceptance\n    total 0\n    drwxr-xr-x  2 andrew  staff  68 Aug  1 19:23 AccountTypeChange\n    drwxr-xr-x  2 andrew  staff  68 Aug  1 19:24 OlderChange\n\n  2. Avoid touching request or response in old tests. Create API gates and matching folder in acceptance tests.\n\n## Other things you might want to do\n\n1. Store Multiverse configuration in `config.ex`:\n\n  ```elixir\n  use Mix.Config\n\n  config :my_app, MyApp.Endpoint,\n    default_version: :latest,\n    gates: %{\n      ~D[2016-07-21] =\u003e [AccountTypeChange]\n    }\n  ```\n\n  ```elixir\n  plug Multiverse, otp_app: :my_app, endpoint: __MODULE__\n  ```\n\n2. Generate API documentation from changes `@moduledoc`'s.\n\n3. Other awesome stuff. Open an issue and tell me about it! :).\n\n# License\n\nSee [LICENSE.md](LICENSE.md).\n","funding_links":[],"categories":["Framework Components"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNebo15%2Fmultiverse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNebo15%2Fmultiverse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNebo15%2Fmultiverse/lists"}