stop making the web harder than it is; real-world rest, hateoas, and hypermedia apis with magpie
Post on 10-May-2015
2.394 Views
Preview:
DESCRIPTION
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!
top related