View Source JSONAPI.View behaviour (jsonapi v1.7.1)

A View is simply a module that defines certain callbacks to configure proper rendering of your JSONAPI documents.

defmodule PostView do
  use JSONAPI.View

  def fields, do: [:id, :text, :body]
  def type, do: "post"
  def relationships do
    [author: UserView,
     comments: CommentView]
  end
end

defmodule UserView do
  use JSONAPI.View

  def fields, do: [:id, :username]
  def type, do: "user"
  def relationships, do: []
end

defmodule CommentView do
  use JSONAPI.View

  def fields, do: [:id, :text]
  def type, do: "comment"
  def relationships do
    [user: {UserView, :include}]
  end
end

defmodule DogView do
  use JSONAPI.View, namespace: "/pupperz-api"
end

You can now call UserView.show(user, conn, conn.params) and it will render a valid jsonapi doc.

Fields

By default, the resulting JSON document consists of fields, defined in the fields/0 function. You can define custom fields or override current fields by defining a 2-arity function inside the view that takes data and conn as arguments and has the same name as the field it will be producing. Refer to our fullname/2 example below.

defmodule UserView do
  use JSONAPI.View

  def fullname(data, conn), do: "fullname"

  def fields, do: [:id, :username, :fullname]
  def type, do: "user"
  def relationships, do: []
end

Fields may be omitted manually using the hidden/1 function.

defmodule UserView do
  use JSONAPI.View

  def fields, do: [:id, :username, :email]

  def type, do: "user"

  def hidden(_data) do
    [:email] # will be removed from the response
  end
end

In order to use sparse fieldsets you must include the JSONAPI.QueryParser plug.

If you want to fetch fields from the given data dynamically, you can use the get_field/3 callback.

defmodule UserView do
  use JSONAPI.View

  def fields, do: [:id, :username, :email]

  def type, do: "user"

  def get_field(field, data, _conn) do
    Map.fetch!(data, field)
  end
end

Relationships

Currently the relationships callback expects that a map is returned configuring the information you will need. If you have the following Ecto Model setup

defmodule User do
  schema "users" do
    field :username
    has_many :posts
    has_one :image
  end
end

and the includes setup from above. If your Post has loaded the author and the query asks for it then it will be loaded.

So for example: GET /posts?include=post.author if the author record is loaded on the Post, and you are using the JSONAPI.QueryParser it will be included in the includes section of the JSONAPI document.

If you always want to include a relationship. First make sure its always preloaded and then use the [user: {UserView, :include}] syntax in your includes function. This tells the serializer to always include if its loaded.

Options

  • :host (binary) - Allows the host to be overridden for generated URLs. Defaults to host of the supplied conn.

  • :scheme (atom) - Enables configuration of the HTTP scheme for generated URLS. Defaults to scheme from the provided conn.

  • :namespace (binary) - Allows the namespace of a given resource. This may be configured globally or overridden on the View itself. Note that if you have a globally defined namespace and need to remove the namespace for a resource, set the namespace to a blank String.

The default behaviour for host and scheme is to derive it from the conn provided, while the default style for presentation in names is to be underscored and not dashed.

Summary

Types

@type data() :: any()
@type field() :: atom()
@type links() :: %{required(atom()) => String.t()}
@type meta() :: %{required(atom()) => String.t()}
@type options() :: keyword()
@type resource_id() :: String.t()
@type resource_type() :: String.t()
@type t() :: module()

Callbacks

@callback attributes(data(), Plug.Conn.t() | nil) :: map()
@callback fields() :: [field()]
Link to this callback

get_field(field, data, t)

View Source (optional)
@callback get_field(field(), data(), Plug.Conn.t()) :: any()
@callback hidden(data()) :: [field()]
@callback id(data()) :: resource_id() | nil
@callback links(data(), Plug.Conn.t()) :: links()
@callback meta(data(), Plug.Conn.t()) :: meta() | nil
@callback namespace() :: String.t()
Link to this callback

pagination_links(data, t, page, options)

View Source
@callback path() :: String.t() | nil
@callback relationships() :: [
  {atom(), t() | {t(), :include} | {atom(), t()} | {atom(), t(), :include}}
]
@callback type() :: resource_type()
@callback url_for(data(), Plug.Conn.t() | nil) :: String.t()
Link to this callback

url_for_pagination(data, t, params)

View Source
@callback url_for_pagination(data(), Plug.Conn.t(), JSONAPI.Paginator.params()) ::
  String.t()
Link to this callback

url_for_rel(term, t, arg3)

View Source
@callback url_for_rel(term(), String.t(), Plug.Conn.t() | nil) :: String.t()
Link to this callback

visible_fields(data, arg2)

View Source
@callback visible_fields(data(), Plug.Conn.t() | nil) :: [atom()]

Functions

Link to this function

url_for(view, data, conn)

View Source
@spec url_for(t(), term(), Plug.Conn.t() | nil) :: String.t()
Link to this function

url_for_pagination(view, data, conn, pagination_params)

View Source
Link to this function

url_for_rel(view, data, rel_type, conn)

View Source
@spec url_for_rel(t(), data(), resource_type(), Plug.Conn.t() | nil) :: String.t()
@spec url_for_rel(t(), data(), Plug.Conn.query_params(), JSONAPI.Paginator.params()) ::
  String.t()
Link to this function

visible_fields(view, data, conn)

View Source
@spec visible_fields(t(), data(), Plug.Conn.t() | nil) :: [atom()]