stop making the web harder than it is; real-world rest, hateoas, and hypermedia apis with magpie
DESCRIPTION
Developing for the Web shouldn't be hard. Yet, many smart developers make it more difficult than it needs to be by choosing tools and frameworks that do not fully take advantage of all that HTTP has to offer. This talk demonstrates how projects at all levels-- from the simplest brochureware site to the most advanced Hypermedia APIs--can be made simpler by getting back to the basics of HTTP. We introduce Tamarou's internal application development and publishing framework, Magpie (scheduled for public release to coincide with YAPC::NA) and step through a series of real-world examples to show how its resource-oriented approach to development keeps simple things simple and makes hard things easier. Topics include: * Why MVC is the wrong way to think about Web development. * Why most frameworks that claim to be RESTful aren't (and how that makes life harder) * An brief introduction to Resource-oriented development. * A series of production-tested Magpie recipes covering the gamut of Web-dev from simple templated sites through advanced Hypermedia applications.TRANSCRIPT
Stop Making The Web Harder Than It Is;
Kip HamptonSenior Architect, Tamarou
@kiphamptonhttps://github.com/ubu
https://metacpan.org/author/KHAMPTON
Real-world REST, HATEOAS, and Hypermedia APIs with Magpie
I’m looking at you, gphat...
ZOMG Teh Future!
Haha, Only Serious
• Dedicated Hypermedia Type (HTML)
• Communication sent over HTTP using the standard verbs. (GET, POST)
• Data contains embedded, discoverable links to related resources and addditional metadata.
• Raw payload meaningful to both humans and specialized clients.
Why Is The Web Still Hard?
• We invented (then re-invented) new things instead of using all that HTTP offered.
• We overburdened the things we did use.
• We applied the wrong design patterns (MVC).
REST == Using All Of HTTP
• HTTP Verbs (GET, POST, PUT, DELETE, etc)
• Status Codes (there's more to life than 200 OK)
• Headers (Link, ETag, X-* custom headers)
• Media Types (Be inventive!)
Sorry, HATEOASers• Hypermedia as the Engine of
Application State
• Don't make the client have to guess (or already know) what to do next.
o Think: HTML Links, Formso Custom media types especially
useful.
Hypertext Application Language
• Simple, lightweight.
• Comprehensible to both human and automated clients.
• Associated Resources can be embedded or linked to.
• Available in both JSON and XML formats.
• More at: http://stateless.co/hal_specification.html
HAL (JSON){ "_links": { "self": { "href": "/orders" }, "next": { "href": "/orders?page=2" }, "find": { "href": "/orders{?id}", "templated": true } }, "_embedded": { "orders": [{ "_links": { "self": { "href": "/orders/123" }, "basket": { "href": "/baskets/98712" }, "customer": { "href": "/customers/7809" } }, "total": 30.00, "currency": "USD", "status": "shipped", },{ "_links": { "self": { "href": "/orders/124" }, "basket": { "href": "/baskets/97213" }, "customer": { "href": "/customers/12369" } }, "total": 20.00, "currency": "USD", "status": "processing" }] }, currentlyProcessing: 14, shippedToday: 20 }}
"A resource is not the thing that is transferred across the wire or picked up off the disk or seen from afar while walking your dog. Each of those is only a representation."
Roy Fielding, 2002
The Resource Is Not The Thing
Introducing Magpie• Built specifically with Resource-oriented
development in mind.
• Uses a event-based pipeline processing model.
oConfiguration determines which components are loaded into the pipeline.
oComponents determine which of their event methods will fire.
• Implemented via Plack::Middleware::Magpie.
Hello, Magpieuse Plack::Builder;use Plack::Middleware::Magpie;my $docroot = ‘/some/path/to/htdocs’;
my $app = builder { enable "Magpie", pipeline => [ 'Magpie::Transformer::XSLT' => { stylesheet => “$docroot/stylesheets/hello.xsl” } ];
enable "Static", path => qr!\.xml$!, root => $docroot;};
$app;
• Single pipeline component.• Resource data passed from upstream
middleware.
Dispatching• The URL path is only part of the
equation.
• Dispatching happens on two levels:
1. Which components will be loaded into the pipeline?
2. Which event methods will be fired within those components?
Loading Components• Application pipelines are defined via
configuration (Plack::Builder-like DSL, or XML file).
• Several options:
• Static pipelines.
• Dynamic pipelines via the machine() keyword and one or more of the match* options.
• Components are added top-down, in configuration order.
Dynamic PipelinesDynamic component loading via the machine()
keyword.
• match -- Adds component(s) conditionally based on string equality or regular expression match against the request’s path.
enable "Magpie", pipeline => [machine { match qr|^/api/cast-member| => [‘MyApp::Resource::CastMember’], match qr|^/api/prop| => [‘MyApp::Resource::Prop’],} MyApp::Serializer::JSON, ];
Dynamic Pipelines (cont’d)
• match_template -- Adds component(s) conditionally based on regular expression match and uses URI Template-like brackets ({}) to capture param/value pairs.
• match_env -- Adds component(s) by evaluating an anonymous subroutine which is passed the Plack environment hash at request time.
• match_accept -- Adds component(s) by evaluating a content negotiation matrix against the Accept* headers of the incoming request.
Event Dispatching• Each component class controls its own event
dispatching.
• Standard event models.
o Magpie::Dispatcher::RequestMethod
o Magpie::Dispatcher::RequestParam
• Easy to roll your own.
o Write your event methods,
o Register the methods you want Magpie to know about,
o Implement load_queue() to define which events fire under what circumstances.
Do I really need all that?
Simple Resourcepackage MyApp::Resource::Widget;use Moose;extends 'Magpie::Resource';use Magpie::Constants;
sub GET { my ($self, $context) = @_; $self->parent_handler->resource($self);
my $data = $self->however_you_get_widget_data(%some_args);
unless ($data) { $self->set_error({ status_code => 404, reason => 'Resource not found.' }); return DONE; }
$self->data($data); return OK;}
If there's no Model and the Resource is not
The Thing, where does stuff go?
Assets• Each Magpie application has a Bread::Board
container to hold the things required to implement your Resource classes and other components.
• Assets can be added both via the DSL and the XML config. (merged at start-up).
• Available in each component class$dbh = $self->resolve_asset( service => 'db_handle');
But Wait!
There's more!
Extras• Existing Plack::Middleware::* classes can be used as pipeline
components with no modification.
• Component class event methods have full access to the pipeline and can end the processing chain, add or remove components, etc.
• Component base classes offer a predictable set of convenience attibutes for operating on the incoming request, the outgoing response, the current resource class, etc.
• All component classes are Trait-aware from the start.
What's There?• A solid, stable, tested core.
• Workable APIs for various common component types (Resources, Transformers, Plugins, Dispatchers).
• Small but growing number of general components. (KiokuDB and File Resources, XSLT, Template Toolkit Transformers, etc.)
• A committed core of developers.
What's Missing?• Docs, docs, docs.
• Many more generic component classes.
• Bootstrap profiles for common types of applications.
• Magpie GUI.
• Mostly, what Magpie needs right now is…
YOU!
Questions?
Thank You
More Information•GitHub:
https://github.com/Tamarou/magpie
•IRC:irc.perl.org #magpie
•Mailing List:http://magpie-lists.tamarou.com/listinfo/
devel
•Hallway++Barge right up and ask!