ja_resource v0.2.0 JaResource.Index behaviour

Provides handle_index/2, filter/4 and sort/4 callbacks.

It relies on (and uses):

  • JaResource.Repo
  • JaResource.Records
  • JaResource.Serializable

When used JaResource.Index defines the index/2 action suitable for handling json-api requests.

To customize the behaviour of the index action the following callbacks can be implemented:

  • handle_index/2
  • filter/4
  • sort/4
  • JaResource.Records.records/1
  • JaResource.Repo.repo/0
  • JaResource.Serializable.serialization_opts/3

Summary

Functions

Execute the index action on a given module implementing Index behaviour and conn

Callbacks

Callback executed for each filter param

Returns the models to be represented by this resource

Callback executed to query repo

Callback executed for each value in the sort param

Functions

call(controller, conn)

Execute the index action on a given module implementing Index behaviour and conn.

Callbacks

filter(arg0, arg1, arg2, arg3)

Specs

Callback executed for each filter param.

For example, if you wanted to optionally filter on an Article’s category and issue, your request url might look like:

/api/articles?filter[category]=elixir&filter[issue]=12

You would then want two callbacks:

def filter(_conn, query, "category", category) do
  where(query, category: category)
end

def filter(_conn, query, "issue", issue_id) do
  where(query, issue_id: issue_id)
end

You can also use guards to whitelist a handeful of attributes:

@filterable_attrs ~w(title category author_id issue_id)
def filter(_conn, query, attr, val) when attr in @filterable_attrs do
  where(query, [{String.to_existing_atom(attr), val}])
end

Anything not explicitly matched by your callbacks will be ignored.

handle_index(arg0, map)

Specs

handle_index(Plug.Conn.t, map) ::
  Plug.Conn.t |
  JaResource.records

Returns the models to be represented by this resource.

Default implementation is the result of the JaResource.Records.records/2 callback. Usually a module or an %Ecto.Query{}.

The results of this callback are passed to the filter and sort callbacks before the query is executed.

handle_index/2 can alternatively return a conn with any response/body.

Example custom implementation:

def handle_index(conn, _params) do
  case conn.assigns[:user] do
    nil  -> App.Post
    user -> User.own_posts(user)
  end
end

In most cases JaResource.Records.records/1, filter/4, and sort/4 are the better customization hooks.

handle_index_query(arg0, arg1)

Specs

handle_index_query(Plug.Conn.t, Ecto.Query.t | module) :: any

Callback executed to query repo.

By default this just calls all/2 on the repo. Can be customized for pagination, monitoring, etc. For example to paginate with Scrivener:

def handle_index_query(%{query_params: qp}, query) do
  repo().paginate(query, qp["page"] || %{})
end
sort(arg0, arg1, arg2, arg3)

Specs

sort(Plug.Conn.t, JaResource.records, String.t, :asc | :dsc) :: JaResource.records

Callback executed for each value in the sort param.

Fourth argument is the direction as an atom, either :asc or :desc based upon the presence or not of a - prefix.

For example if you wanted to sort by date then title your request url might look like:

/api/articles?sort=-created,title

You would then want two callbacks:

def sort(_conn, query, "created", direction) do
  order_by(query, [{direction, :inserted_at}])
end

def sort(_conn, query, "title", direction) do
  order_by(query, [{direction, :title}])
end

Anything not explicitly matched by your callbacks will be ignored.