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' helpers
$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 using the restify helper
# my $r = $self->routes;
# $self->restify->routes($r, {accounts => {invoices => undef}});
}
# 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 under {
my $c = shift;
# To consistenly get the element's ID relative to the under 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 = lookup_account_resource($c->restify->current_id);
# By stashing the $account here, it will now be available in the delete,
# read, patch, and update actions. This under action is added to every
# collection by default to help reduce your code, but can be disabled if
# you wish.
$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 under method
$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.
#
# /accounts * accounts
# +/ GET "accounts_list" Accounts::list
# +/ POST "accounts_create" Accounts::create
# +/:accounts_id * "accounts"
# +/ * "accounts_under" Accounts::under
# +/ 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 under
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 Mojolicious::Controller::stash yet.
restify->routes
This helper allows you to create REST collections from a Perl HASH
. It uses the key/values to invoke the "collection" route shortcut with any route- specific options. It automatically chains routes to each parent, and progressively builds a namespace as it traverses through every key.
See "collection" for more route-specific options.
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 set below
# /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 an under
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.
- under
-
$r->collection('nounder', under => 0);
Enables or disables adding an
under
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.
COPYRIGHT AND LICENSE
Copyright (C) 2015, 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.