Stop Making The Web
   Harder Than It Is;
Real-world REST, HATEOAS, and Hypermedia
             APIs with Magpie
                Kip Hampton
          Senior Architect, Tamarou
                       @kiphampton
                   https://github.com/ubu
         https://metacpan.org/author/KHAMPTON
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, Forms
    o    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.
 o Configuration determines which components
    are loaded into the pipeline.
 o Components determine which of their event
    methods will fire.
• Implemented via Plack::Middleware::Magpie.
Hello, Magpie
use 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 Pipelines
    Dynamic 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 Resource
package 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!

Stop Making The Web Harder Than It Is; Real-world REST, HATEOAS, and Hypermedia APIs with Magpie

  • 1.
    Stop Making TheWeb Harder Than It Is; Real-world REST, HATEOAS, and Hypermedia APIs with Magpie Kip Hampton Senior Architect, Tamarou @kiphampton https://github.com/ubu https://metacpan.org/author/KHAMPTON
  • 2.
    I’m looking atyou, gphat...
  • 3.
  • 4.
    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.
  • 5.
    Why Is TheWeb 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).
  • 6.
    REST == UsingAll 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!)
  • 7.
    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, Forms o Custom media types especially useful.
  • 8.
    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
  • 9.
    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 } }
  • 10.
    "A resource isnot 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
  • 11.
    The Resource Is Not The Thing
  • 12.
    Introducing Magpie • Builtspecifically with Resource-oriented development in mind. • Uses a event-based pipeline processing model. o Configuration determines which components are loaded into the pipeline. o Components determine which of their event methods will fire. • Implemented via Plack::Middleware::Magpie.
  • 13.
    Hello, Magpie use Plack::Builder; usePlack::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.
  • 14.
    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?
  • 15.
    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.
  • 16.
    Dynamic Pipelines Dynamic 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, ];
  • 17.
    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.
  • 18.
    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.
  • 19.
    Do I reallyneed all that?
  • 20.
    Simple Resource package MyApp::Resource::Widget; useMoose; 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; }
  • 21.
    If there's noModel and the Resource is not The Thing, where does stuff go?
  • 22.
    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');
  • 23.
  • 24.
    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.
  • 25.
    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.
  • 26.
    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…
  • 27.
  • 28.
  • 29.
  • 30.
    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!