View Source JSON:API library for Plug and Phoenix applications

Server library to build JSON:API compliant REST APIs.

JSON:API Support

This library currently implements version 1.0 of the JSON:API specification.

Documentation

Quickstart

Installation

Add the following line to your mix.deps file with the desired version to install jsonapi_plug.

defp deps do [
  ...
  {:jsonapi_plug, "~> 1.0"}
  ...
]

Configuration

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
end

See the JSONAPIPlug.API module documentation to learn how to customize your APIs via application configuration of your app.

Receiving requests

In order to parse JSON:API requests from clients you need to add the JSONAPIPlug.Plug plug to each of your plug pipelines or phoenix controllers handling requests for a specific resource:

defmodule MyApp.PostsController do
  ...
  plug JSONAPIPlug.Plug, api: MyApp.API, resource: MyApp.PostResource
  ...
end

This will take care of ensuring JSON:API specification compliance and will return errors for invalid requests.

The :api option expects a module using JSONAPI.API for configuration.

The :resource option expects a module using JSONAPIPlug.Resource to convert to/from JSON:API format.

When requests are processed, the :jsonapi_plug connection private field is populated with the parsed request.

See the JSONAPIPlug.Plug module documentation for usage and options.

Serving responses

To start serving responses, you need to have some data to return to clients:

defmodule MyApp.Post do
  @type t :: %__MODULE__{id: pos_integer(), body: String.t(), title: String.t()}

  @enforce_keys [:id, :body, :title]
  defstruct [:id, :body, :title]
end

and define a resource module to render your resource:

defmodule MyApp.PostResource do
  use JSONAPIPlug.Resource,
    type: "post",
    attributes: [
      title: nil,
      text: nil,
      excerpt: [serialize: fn %Post{} = post, _conn -> String.slice(post.body, 0..5) end]
    ]

  @impl JSONAPIPlug.Resource
  def meta(%Post{} = post, _conn), do: %{slug: to_slug(post.title)}
end

To use the resource module in Phoenix, just call render and pass the data from your controller:

  defmodule MyAppWeb.PostsController do
    ...
    plug JSONAPIPlug.Plug, api: MyApp.API, resource: MyApp.PostResource
    ...

    def create(%Conn{private: %{jsonapi_plug: 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: jsonapi_plug}} = conn, _params) do
      posts = ...load data using jsonapi_plug parsed parameters...
      render(conn, "index.json", %{data: posts})
    end

    def show(%Conn{private: %{jsonapi_plug: jsonapi_plug} = conn, _params) do
      post = ...load data using jsonapi_plug parsed parameters...
      render(conn, "show.json", %{data: post})
    end

    def udate(%Conn{private: %{jsonapi_plug: jsonapi_plug}} = conn, params) do
      post = ...update a post using jsonapi_plug parsed parameters...
     render(conn, "update.json", %{data: post})
    end
  end

If you have a Plug application, you can call JSONAPIPlug.Resource.render/5 to generate a JSONAPI.Document with your data for the client. The structure is serializable to JSON with Jason.

See the JSONAPIPlug.Plug and JSONAPIPlug.Resource modules documentation for more information.

Contributing

  • 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