plug_rest v0.8.0 PlugRest.Resource behaviour

Define callbacks and REST semantics for a Resource behaviour

Based on Cowboy’s cowboy_rest module. It operates on a Plug connection and a handler module which implements one or more of the optional callbacks.

For example, the route:

resource "/users/:username", MyApp.UserResource

will invoke the init/2 function of MyApp.UserResource if it exists and then continue executing to determine the state of the resource. By default the resource must implement a to_html content handler which returns a “text/html” representation of the resource.

defmodule MyApp.UserResource do

  use PlugRest.Resource

  def init(%{params: params} = conn, _state) do
    username = params["username"]
    state = %{username: username}
    {:ok, conn, state}
  end

  def allowed_methods(conn, state) do
    {["GET"], conn, state}
  end

  def resource_exists(conn, %{username: username} = state)
    # Look up user
    state2 = %{state | name: "John Doe"}
    {true, conn, state2}
  end

  def content_types_provided(conn, state) do
    {[{"text/html", :to_html}], conn, state}
  end

  def to_html(conn, %{name: name} = state) do
    {"<p>Hello, #{name}</p>", conn, state}
  end
end

Each callback accepts a %Plug.Conn{} struct and the current state of the resource, and returns a three-element tuple of the form {value, conn, state}.

The resource callbacks are named below, along with their default values. Some functions are skipped if they are undefined. Others have no default value.

allowed_methods        : ["GET", "HEAD", "OPTIONS"]
allow_missing_post     : true
charsets_provided      : skip
content_types_accepted : none
content_types_provided : [{{"text", "html", %{}}, :to_html}]
delete_completed       : true
delete_resource        : false
expires                : nil
forbidden              : false
generate_etag          : nil
is_authorized          : true
is_conflict            : false
known_methods          : ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
languages_provided     : skip
last_modified          : nil
malformed_request      : false
moved_permanently      : false
moved_temporarily      : false
multiple_choices       : false
options                : :ok
previously_existed     : false
resource_exists        : true
service_available      : true
uri_too_long           : false
valid_content_headers  : true
valid_entity_length    : true
variances              : []

You must also define the content handler callbacks that are specified through content_types_accepted/2 and content_types_provided/2. It is conventional to name the functions after the content types that they handle, such as from_html and to_html.

The handler function which provides a representation of the resource must return a three element tuple of the form {body, conn, state}, where body is one of:

  • binary(), which will be sent with send_resp/3
  • {:chunked, Enum.t}, which will usesend_chunked/2*{:file, binary()}, which will use send_file/3

You can halt the resource handling from any callback and return a manual response like so:

response = send_resp(conn, status_code, resp_body)
{:stop, response, state}

The content accepted handlers defined in content_types_accepted will be called for POST, PUT, and PATCH requests. By default, the response body will be empty. If desired, you can set the response body like so:

conn2 = put_rest_body(conn, "#{conn.method} was successful")
{true, conn2, state}

Summary

Functions

Returns the requested media type

Returns the REST response body if it has been set

Puts the media type in the connection

Manually sets the REST response body in the connection

Executes the REST state machine with a connection and resource

Types

conn :: Plug.Conn.t
content_handler :: PlugRest.State.content_handler
etag :: PlugRest.State.etag
etags_list :: PlugRest.Conn.etags_list
handler :: PlugRest.State.handler
media_type :: PlugRest.State.media_type
opts :: Plug.opts
priority_type :: PlugRest.Conn.priority_type
quality_type :: PlugRest.Conn.quality_type
state :: PlugRest.State.t
status_code :: 200..503

Functions

get_media_type(conn)

Specs

get_media_type(conn) :: media_type | nil

Returns the requested media type

get_rest_body(conn)

Specs

get_rest_body(conn) :: binary | nil

Returns the REST response body if it has been set

put_media_type(conn, media_type)

Specs

put_media_type(conn, media_type) :: conn

Puts the media type in the connection

put_rest_body(conn, resp_body)

Specs

put_rest_body(conn, binary) :: conn

Manually sets the REST response body in the connection

upgrade(conn, handler, options)

Specs

upgrade(conn, handler, Keyword.t) :: conn

Executes the REST state machine with a connection and resource

Accepts a Plug.Conn struct, a PlugRest.Resource handler module, and an options list, and executes the REST state machine.

Callbacks

allow_missing_post(conn, state) (optional)

Specs

allow_missing_post(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
allowed_methods(conn, state) (optional)

Specs

allowed_methods(conn, state) ::
  {[binary], conn, state} |
  {:stop, conn, state}
charsets_provided(conn, state) (optional)

Specs

charsets_provided(conn, state) ::
  {[binary], conn, state} |
  {:stop, conn, state}
content_types_accepted(conn, state) (optional)

Specs

content_types_accepted(conn, state) ::
  {[media_type], conn, state} |
  {:stop, conn, state}
content_types_provided(conn, state) (optional)

Specs

content_types_provided(conn, state) ::
  {[content_type_p], conn, state} |
  {:stop, conn, state}
delete_completed(conn, state) (optional)

Specs

delete_completed(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
delete_resource(conn, state) (optional)

Specs

delete_resource(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
expires(conn, state) (optional)

Specs

expires(conn, state) ::
  {:calendar.datetime | binary | nil, conn, state} |
  {:stop, conn, state}
forbidden(conn, state) (optional)

Specs

forbidden(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
generate_etag(conn, state) (optional)

Specs

generate_etag(conn, state) ::
  {binary | {:weak | :strong, binary}, conn, state} |
  {:stop, conn, state}
init(opts) (optional)

Specs

init(opts) :: opts
init(conn, state) (optional)

Specs

init(conn, state) ::
  {:ok, conn, state} |
  {:stop, conn, state}
is_authorized(conn, state) (optional)

Specs

is_authorized(conn, state) ::
  {true | {false, binary}, conn, state} |
  {:stop, conn, state}
is_conflict(conn, state) (optional)

Specs

is_conflict(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
known_methods(conn, state) (optional)

Specs

known_methods(conn, state) ::
  {[binary], conn, state} |
  {:stop, conn, state}
languages_provided(conn, state) (optional)

Specs

languages_provided(conn, state) ::
  {[binary], conn, state} |
  {:stop, conn, state}
last_modified(conn, state) (optional)

Specs

last_modified(conn, state) ::
  {:calendar.datetime, conn, state} |
  {:stop, conn, state}
malformed_request(conn, state) (optional)

Specs

malformed_request(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
moved_permanently(conn, state) (optional)

Specs

moved_permanently(conn, state) ::
  {{true, binary} | false, conn, state} |
  {:stop, conn, state}
moved_temporarily(conn, state) (optional)

Specs

moved_temporarily(conn, state) ::
  {{true, binary} | false, conn, state} |
  {:stop, conn, state}
multiple_choices(conn, state) (optional)

Specs

multiple_choices(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
options(conn, state) (optional)

Specs

options(conn, state) ::
  {:ok, conn, state} |
  {:stop, conn, state}
previously_existed(conn, state) (optional)

Specs

previously_existed(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
resource_exists(conn, state) (optional)

Specs

resource_exists(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
service_available(conn, state) (optional)

Specs

service_available(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
uri_too_long(conn, state) (optional)

Specs

uri_too_long(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
valid_content_headers(conn, state) (optional)

Specs

valid_content_headers(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
valid_entity_length(conn, state) (optional)

Specs

valid_entity_length(conn, state) ::
  {boolean, conn, state} |
  {:stop, conn, state}
variances(conn, state) (optional)

Specs

variances(conn, state) ::
  {[binary], conn, state} |
  {:stop, conn, state}