Server library to build JSON:API compliant REST APIs.
This library currently implements version 1.0 of the JSON:API specification.
However, to support resource creation alongside included resources, JSON:API 1.1 lid is supported.
- Full documentation can be found on hexdocs.pm
For the JSON:API specification documentation as well as other client and server implementations:
Add the following line to your mix.deps file with the desired version to install jsonapi_plug.
defp deps do [
...
{:jsonapi_plug, "~> 2.0"}
...
]
Upgrading the library should be safe for minor and patch version upgrades, it's still a good practice to check the changelog for more information on the release content. For major version upgrades, breaking changes should be expected, and the upgrade guide contains instructions on upgrading between major releases of the library.
You start by declaring one or more APIs. APIs are collections of endpoints that share a common configuration:
defmodule MyApp.API do
use JSONAPIPlug.API, otp_app: :my_app
endSee the JSONAPIPlug.API module documentation to learn how to customize your APIs
via application configuration of your app.
To start accept requests and serving responses, you need to define JSON:API resources.
Resources can be any struct @derive-ing the JSONAPIPlug.Resource protocol:
defmodule MyApp.Post do
use Ecto.Schema
@type t :: %__MODULE__{id: pos_integer(), body: String.t(), title: String.t()}
@derive {
JSONAPIPlug.Resource,
type: "post",
attributes: [:title, :text, :excerpt]
}
schema "posts" do
field :title
field :text
end
...
endSee JSONAPIPlug.Resource for the complete documentation of options you can pass to @derive,
including how to control serialization and deserialization, and add related resources.
Also, three optional protocols are available to allow further customization of resources.
- Resource attribute custom serialization and deserialization:
JSONAPIPlug.Resource.Attribute - Resource link generation:
JSONAPIPlug.Resource.Links - Resource link generation:
JSONAPIPlug.Resource.Meta
To serve JSON:API resources in Phoenix, you need to define routes in your router:
defmodule MyAppWeb.Router do
...
resource "/posts", MyApp.PostsController, only: [:create, :index, :show]
patch "/posts/:id", MyApp.PostsController, :update
endIn order to parse JSON:API requests from clients you need to add the JSONAPIPlug.Plug plug to each of your
phoenix controllers handling requests for a specific resource. This will take care of ensuring JSON:API request
compliance and will return errors for malformed requests.
When a valid request processed, the :jsonapi_plug Plug.Conn private field will be populated in the controller.
You can learn all about advanced request handling, including custom filtering, relationships inclusion, pagination
and sparse fields support by reading the JSONAPIPlug.Plug module documentation.
Once you receive a request in your controller and load data, you just call render to send a response:
defmodule MyAppWeb.PostsController do
...
plug JSONAPIPlug.Plug, api: MyApp.API, path: "posts", resource: MyApp.Post
...
def create(%Conn{private: %{jsonapi_plug: %JSONAPIPlug{} = jsonapi_plug}} = conn, params) do
post = ...create a post using jsonapi_plug parsed parameters...
render(conn, "create.json", %{data: post})
end
def index(%Conn{private: %{jsonapi_plug: %JSONAPIPlug{} = jsonapi_plug}} = conn, _params) do
posts = ...load data using jsonapi_plug parsed parameters...
render(conn, "index.json", %{data: post})
end
def show(%Conn{private: %{jsonapi_plug: %JSONAPIPlug{} = jsonapi_plug}} = conn, _params) do
post = ...load data using jsonapi_plug parsed parameters...
render(conn, "show.json", %{data: post})
end
def update(%Conn{private: %{jsonapi_plug: %JSONAPIPlug{} = jsonapi_plug}} = conn, params) do
post = ...update a post using jsonapi_plug parsed parameters...
render(conn, "update.json", %{data: post})
end
endFor phoenix to dispatch this for rendering you need to add this code to your MyAppWeb module:
def MyAppWeb do
...
def json_api do
quote do
use JSONAPIPlug.Phoenix.Component
end
end
...
endand define a corresponding rendering template module:
defmodule SibillWeb.PostsJSON do
@moduledoc false
use MyAppWeb, :json_api
endalternatively you can skip these steps by calling JSONAPIPlug.render/4 directly instead of render/3 in you controller:
...
def show(%Conn{private: %{jsonapi_plug: %JSONAPIPlug{} = jsonapi_plug}} = conn, _params) do
post = ...load data using jsonapi_plug parsed parameters...
JSONAPIPlug.render(conn, post \\ nil, meta \\ nil, options \\ [])
end
...If you have a Plug application, assuming you already set up routing you can call JSONAPIPlug.render/4 in your
pipeline to generate a JSONAPI.Document with your data for the client.
JSONAPIPlug.render(conn, post)
|> Jason.encode!()Render returns a JSONAPI.Document, that is serializable to JSON via Jason.
- This project was born as a fork of the jsonapi library but has since been completely rewritten and is now a completely different project.
- PRs for new features, bug fixes, documentation and tests are welcome
- If you are proposing a large feature or change, please open an issue for discussion