NAME
Mojolicious::Plugin::Restify - Route shortcuts & helpers for REST collections
SYNOPSIS
# Mojolicious example (Mojolicious::Lite isn't supported)
package MyApp;
use Mojo::Base 'Mojolicious';
sub startup {
my $self = shift;
# imports the `collection' route shortcut and `restify' helper
$self->plugin('Restify');
# add REST collection endpoints manually
my $r = $self->routes;
my $accounts = $r->collection('accounts'); # /accounts
$accounts->collection('invoices'); # /accounts/:accounts_id/invoices
# or add the equivalent REST routes with an ARRAYREF (the helper will
# create chained routes from the path 'accounts/invoices' so you don't need
# to set ['accounts', 'accounts/invoices'])
my $r = $self->routes;
$self->restify->routes($r, ['accounts/invoices']);
# or add the equivalent REST routes with a HASHREF (might be easier to
# visualise how collections are chained together)
my $r = $self->routes;
$self->restify->routes($r, {
accounts => {
invoices => undef
}
});
}
Next create your controller for accounts.
# Restify controller depicting the REST actions for the /accounts collection.
# (The name of the controller is the Mojo::Util::camelized version of the
# collection path.)
package MyApp::Controller::Accounts;
use Mojo::Base 'Mojolicious::Controller';
sub resource_lookup {
my $c = shift;
# To consistenly get the element's ID relative to the resource_lookup
# action, use the helper as shown below. If you need to access an element ID
# from a collection further up the chain, you can access it from the stash.
#
# The naming convention is the name of the collection appended with '_id'.
# E.g., $c->stash('accounts_id').
my $account = your_lookup_account_resource_func($c->restify->current_id);
# By stashing the $account here, it will now be available in the delete,
# read, patch, and update actions. This resource_lookup action is option,
# but added to every collection by default to help reduce your code.
$c->stash(account => $account);
# must return a positive value to continue the dispatch chain
return 1 if $account;
# inform the end user that this specific resource does not exist
$c->reply->not_found and return 0;
}
sub create { ... }
sub delete { ... }
sub list { ... }
sub read {
my $c = shift;
# account was placed in the stash in the resource_lookup action
$c->render(json => $c->stash('account'));
}
sub patch { ... }
sub update { ... }
1;
DESCRIPTION
Mojolicious::Plugin::Restify is a Mojolicious::Plugin. It simplifies generating all of the Mojolicious::Routes for a typical REST collection endpoint (e.g., /accounts
or /invoices
) and maps the common HTTP verbs (DELETE
, GET
, PATCH
, POST
, PUT
) to underlying controller class methods.
For example, creating a collection called /accounts
would create the routes as shown below. N.B. The over
option in the example below corresponds to the name of a route condition. See "conditions" in Mojolicious::Routes.
# The collection route shortcut below creates the following routes, and maps
# them to controllers of the camelized route's name.
#
# Pattern Methods Name Class::Method Name
# ------- ------- ---- ------------------
# /accounts * accounts
# +/ GET "accounts_list" Accounts::list
# +/ POST "accounts_create" Accounts::create
# +/:accounts_id * "accounts"
# +/ * "accounts_resource_lookup" Accounts::resource_lookup
# +/ DELETE "accounts_delete" Accounts::delete
# +/ GET "accounts_read" Accounts::read
# +/ PATCH "accounts_patch" Accounts::patch
# +/ PUT "accounts_update" Accounts::update
# expects the element id (:accounts_id) for this collection to be a uuid
my $route = $r->collection('accounts', over => 'uuid');
Mojolicious::Plugin::Restify tries not to make too many assumptions, but the author's recent experience writing a REST-based API using Mojolicious has helped shaped this plugin, and might unwittingly express some of his bias.
HELPERS
Mojolicious::Plugin::Restify implements the following helpers.
restify->current_id
my $id = $c->restify->current_id;
Returns the element id at the current point in the dispatch chain.
This is the only way to guarantee the correct element's resource ID in a Mojolicious::Plugin::Restify action. The resource_lookup
action, which is added by default in both "collection" and "restify-routes", is added at different positions of the dispatch chain. As such, the router might not have added the value of any placeholders to the "stash" in Mojolicious::Controller yet.
restify->routes
This helper is a wrapper around the "collection" route shortcut. It facilitates creating REST collections using either an ARRAYREF
or HASHREF
.
It takes a Mojolicious::Routes object, the paths to create, and optionally options which are passed to the "collection" route shortcut.
# /accounts
# /accounts/1234
$self->restify->routes($self->routes, ['accounts'], {over => 'int'});
# /invoices
# /invoices/76be1f53-8363-4ac6-bd83-8b49e07b519c
$self->restify->routes($self->routes, ['invoices'], {over => 'uuid'});
Maybe you want to chain them.
# /accounts
# /accounts/1234
# /accounts/1234/invoices
# /accounts/1234/invoices/76be1f53-8363-4ac6-bd83-8b49e07b519c
$self->restify->routes(
$self->routes,
['accounts', ['accounts/invoices' => {over => 'uuid'}]],
{over => 'int'}
);
- ARRAYREF
-
Using the elements of the array, invokes "collection", passing any route- specific options.
It will automatically create and chain parent routes if you pass a full path e.g.,
['a/very/long/path']
. This is equivalent to the shell commandmkdir -p
.my $restify_routes = [ # /area-codes # /area-codes/:area_codes_id/numbers 'area-codes/numbers', # /news 'news', # /payments ['payments' => {over => 'int'}], # overrides default uuid route condition # /users # /users/:users_id/messages # /users/:users_id/messages/:messages_id/recipients 'users/messages/recipients', ]; $self->restify->routes($self->routes, $restify_routes, {over => 'uuid'});
In its most basic form,
REST
routes are created from aSCALAR
.# /accounts my $restify_routes = ['accounts'];
- HASHREF
-
Using the key/values of the hash, invokes "collection", passing any route- specific options.
It automatically chains routes to each parent, and progressively builds a namespace as it traverses through each key.
N.B., This was implemented before the
ARRAYREF
version, and is arguably a bit more confusing. It might be dropped in a later version to simplify the API.my $restify_routes = { # /area-codes # /area-codes/:area_codes_id/numbers 'area-codes' => { 'numbers' => undef }, # /news 'news' => undef, # /payments 'payments' => [undef, {over => 'int'}], # overrides default uuid route condition # /users # /users/:users_id/messages # /users/:users_id/messages/:messages_id/recipients 'users' => { 'messages' => { 'recipients' => undef } }, }; $self->restify->routes($self->routes, $restify_routes, {over => 'uuid'});
METHODS
Mojolicious::Plugin::Restify inherits all methods from Mojolicious::Plugin and implements the following new ones.
register
$plugin->register(Mojolicious->new);
Register plugin in Mojolicious application.
ROUTE CONDITIONS
Mojolicious::Plugin::Restify implements the following route conditions. These conditions can be used with the over
option in the "collection" shortcut.
Checks are made for the existence of the int
, standard
and uuid
conditions before adding them. This allows you to replace them with your own conditions of the same name by creating them before registering this plugin.
See "Adding-conditions" in Mojolicious::Guides::Routing to add your own.
int
# /numbers/1 # GOOD
# /numbers/0 # GOOD
# /numbers/one # BAD
# /numbers/-1 # BAD
# /numbers/0.114 # BAD (the standard :placeholder notation doesn't allow a '.')
my $r = $self->routes;
$r->collection('numbers', over => 'int');
A Mojolicious route condition (see "conditions" in Mojolicious::Routes) which restricts a route's collection's element id to whole positive integers which are >= 0
.
standard
my $r = $self->routes;
$r->collection('numbers', over => 'standard');
A collection's element resource ID is captured using "Standard-placeholders" in Mojolicious::Guides::Routing. This route condition allows everything the standard placeholder allows, which is similar to the regular expression ([^/.]+)
.
This is the default over option for a "collection".
uuid
# /uuids/8ebef0d0-d6cf-11e4-8830-0800200c9a66 GOOD
# /uuids/8EBEF0D0-D6CF-11E4-8830-0800200C9A66 GOOD
# /uuids/8ebef0d0d6cf11e488300800200c9a66 GOOD
# /uuids/malformed-uuid BAD
my $r = $self->routes;
$r->collection('uuids', over => 'uuid');
A Mojolicious route condition (see "conditions" in Mojolicious::Routes) which restricts a route's collection's element id to UUIDs only (with or without the separating hyphens).
ROUTE SHORTCUTS
Mojolicious::Plugin::Restify implements the following route shortcuts.
collection
my $r = $self->routes;
$r->collection('accounts');
A Mojolicious routes shortcut which helps create the most common REST routes for a collection endpoint and its associated element.
A collection endpoint (e.g., /accounts
) supports list (GET
) and create (POST
) actions. The collection's element (e.g., /accounts/:accounts_id
) supports delete (DELETE
), read (GET
), patch (PATCH
), and update (PUT
) actions.
By default, every HTTP request to a collection's element is routed through a resource_lookup
action (see "under" in Mojolicious::Routes::Route). This helps reduce the process of looking up a resource to a single location. See "SYNOPSIS" for an example of its use.
options
The following options allow a collection to be fine-tuned.
- controller
-
# collection doesn't build a namespace for subroutes by default my $accounts = $r->collection('accounts'); # MyApp::Controller::Accounts $accounts->collection('invoices'); # MyApp::Controller::Invoices # collection can build namespaces, but can be difficult to keep track of. Use # the restify helper if namespaces are important to you. # # MyApp::Controller::Accounts my $accounts = $r->collection('accounts'); # MyApp::Controller::Accounts::Invoices my $invoices = $accounts->collection('invoices', controller => 'accounts'); # MyApp::Controller::Accounts::Invoices::Foo $invoices->collection('foo', controller => 'accounts-invoices');
Prepends the controller name (which is automatically generated based on the path name) with this option value if present. Used internally by "restify" to build a perlish namespace from the paths. "collection" does not build a namespace by default.
- element
-
# GET,POST /messages 200 # DELETE,GET,PATCH,PUT,UPDATE /messages/1 200 $r->collection('messages'); # element routes are created by default # GET,POST /messages 200 # DELETE,GET,PATCH,PUT,UPDATE /messages/1 404 $r->collection('messages', element => 0);
Enables or disables adding an element to the collection. Disabling the element portion of a collection means that only the create and list actions will be created.
- over
-
$r->collection('accounts', over => 'uuid'); $r->collection('invoices', over => 'int');
Allows a collection's element to be restricted to a specific data type using Mojolicious' route conditions. "int", "standard" and "uuid" are added automatically if they don't already exist.
- prefix
-
# without a prefix $r->collection('invoices'); say $c->url_for('invoices', invoices_id => 1); # with a prefix $r->collection('invoices', prefix => 'v1'); say $c->url_for('v1_invoices', invoices_id => 1);
Adds a prefix to the automatically generated route name for each collection and element action.
- resource_lookup
-
$r->collection('nolookup', resource_lookup => 0);
Enables or disables adding a
resource_lookup
action to the element of the collection.
element
my $r = $self->routes;
my $news = $r->get('/news')->to('foo#news');
$news->element('news');
A Mojolicious route shortcut called internally by "collection" to add the element routes to a collection. You shouldn't need to call this shortcut directly.
When an element is added to a collection's route, the resource ID is captured using a standard placeholder by default.
CREDITS
In alphabetical order:
Castaway
Dragoș-Robert Neagu
COPYRIGHT AND LICENSE
Copyright (C) 2015-2017, Paul Williams.
This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.
AUTHOR
Paul Williams <kwakwa@cpan.org>
SEE ALSO
Mojolicious, Mojolicious::Plugin::REST, Mojolicious::Plugin::RESTRoutes.