SlideShare una empresa de Scribd logo
1 de 32
Descargar para leer sin conexión
Web::Machine
Simpl{e,y} HTTP?!
Web::Machine?
➔ Simple HTTP State Machine…
➔ Represented as Resource classes
◆ See API Design talk
➔ Provides hooks for HTTP states
➔ Replacement for MVC style Web
Frameworks
➔ Plack compatible
PLACK
use Plack::Builder;
use Bean::API;
builder {
mount ‘/’ => Bean::API->as_psgi_app
}
sub as_psgi_app {
my ($self) = @_;
$self = ref $self ? $self : $self->new;
$self->router->add_route('/users/:id' =>
validations => {
id => Int,
},
target => sub {
my ($request, $id) = @_;
my $app = Web::Machine->new(
resource => Bean::API::Resources::User',
resource_args => [
user_id => $id,
]
)->to_app;
return $app->($request->env);
}
);
return Plack::App::Path::Router->new(router => $self->router)->to_app;
}
sub as_psgi_app {
my ($self) = @_;
$self = ref $self ? $self : $self->new;
$self->router->add_route('/users/:id' =>
validations => {
id => Int,
},
target => sub {
my ($request, $id) = @_;
my $app = Web::Machine->new(
resource => Bean::API::Resources::User',
resource_args => [
user_id => $id,
]
)->to_app;
return $app->($request->env);
}
);
return Plack::App::Path::Router->new(router => $self->router)->to_app;
}
my $app = Web::Machine->new(
# Resource is a Web::Machine::Resource subclass
resource => Bean::API::Resources::User',
# resource_args are passed to the Resource subclass on initialization
resource_args => [
user_id => $id,
]
)->to_app;
my $app = Web::Machine->new(
# Resource is a Web::Machine::Resource subclass
resource => Bean::API::Resources::User',
# resource_args are passed to the Resource subclass on initialization
resource_args => [
user_id => $id,
]
)->to_app;
my $app = Web::Machine->new(
# Resource is a Web::Machine::Resource subclass
resource => Bean::API::Resources::User',
# resource_args are passed to the Resource subclass on initialization
resource_args => [
user_id => $id,
]
)->to_app;
sub as_psgi_app {
my ($self) = @_;
$self = ref $self ? $self : $self->new;
$self->router->add_route('/users/:id' =>
validations => {
id => Int,
},
target => sub {
my ($request, $id) = @_;
my $app = Web::Machine->new(
resource => Bean::API::Resources::User',
resource_args => [
user_id => $id,
]
)->to_app;
return $app->($request->env);
}
);
return Plack::App::Path::Router->new(router => $self->router)->to_app;
}
Resource Class
➔ @ISA
◆ Web::Machine::Resource
➔ use Moo{se} for fun and profit
➔ Kinda like a controller.
➔ has request, has response.
package Bean::API::Resources::User;
use Moo;
extends ‘Web::Machine::Resource’;
1;
package Bean::API::Resources::User;
use Moo;
extends ‘Web::Machine::Resource’;
use Types::Standard qw/Int/
has user_id => (
is => ‘ro’,
isa => Int,
required => 1
);
1;
sub as_psgi_app {
my ($self) = @_;
$self = ref $self ? $self : $self->new;
$self->router->add_route('/users/:id' =>
validations => {
id => Int,
},
target => sub {
my ($request, $id) = @_;
my $app = Web::Machine->new(
resource => Bean::API::Resources::User',
resource_args => [
user_id => $id,
]
)->to_app;
return $app->($request->env);
}
);
return Plack::App::Path::Router->new(router => $self->router)->to_app;
}
package Bean::API::Resources::User;
use Moo;
extends ‘Web::Machine::Resource’;
use Types::Standard qw/Str/;
has user_id => (
isa => Str,
is => ‘ro’,
required => 1
);
has user => (
is => ‘lazy’,
isa => Maybe[‘Bean::Schema::ResultUser’],
builder => 1,
);
...
sub _build_user {
return $schema->resultset(‘User’)->find($self->user_id);
}
...
sub resource_exists { 1 } sub service_available { 1 }
sub is_authorized { 1 } sub forbidden { 0 }
sub allow_missing_post { 0 } sub malformed_request { 0 }
sub uri_too_long { 0 } sub known_content_type { 1 }
sub valid_content_headers { 1 } sub valid_entity_length { 1 }
sub options { +{} } sub allowed_methods { [ qw[GET HEAD] ] }
sub known_methods { [qw[ GET HEAD POST PUT DELETE TRACE CONNECT OPTIONS ]]}
sub delete_resource { 0 } sub delete_completed { 1 }
sub post_is_create { 0 } sub create_path { undef }
sub base_uri { undef } sub process_post { 0 }
sub content_types_provided { [] } sub content_types_accepted { [] }
sub charsets_provided { [] } sub default_charset {}
sub languages_provided { [] } sub encodings_provided { { 'identity' => sub { $_[1] } } }
sub variances { [] } sub is_conflict { 0 }
sub multiple_choices { 0 } sub previously_existed { 0 }
sub moved_permanently { 0 } sub moved_temporarily { 0 }
sub last_modified { undef } sub expires { undef }
sub generate_etag { undef } sub finish_request {}
sub create_path_after_handler { 0 }
sub resource_exists { 1 } sub service_available { 1 }
sub is_authorized { 1 } sub forbidden { 0 }
sub allow_missing_post { 0 } sub malformed_request { 0 }
sub uri_too_long { 0 } sub known_content_type { 1 }
sub valid_content_headers { 1 } sub valid_entity_length { 1 }
sub options { +{} } sub allowed_methods { [ qw[ GET HEAD ] ] }
sub known_methods { [qw[ GET HEAD POST PUT DELETE TRACE CONNECT OPTIONS ]] }
sub delete_resource { 0 } sub delete_completed { 1 }
sub post_is_create { 0 } sub create_path { undef }
sub base_uri { undef } sub process_post { 0 }
sub content_types_provided { [] } sub content_types_accepted { [] }
sub charsets_provided { [] } sub default_charset {}
sub languages_provided { [] } sub encodings_provided { { 'identity' => sub { $_[1] } } }
sub variances { [] } sub is_conflict { 0 }
sub multiple_choices { 0 } sub previously_existed { 0 }
sub moved_permanently { 0 } sub moved_temporarily { 0 }
sub last_modified { undef } sub expires { undef }
sub generate_etag { undef } sub finish_request {}
sub create_path_after_handler { 0 }
GET
➔ content_types_provided
◆ Takes a list of
● Hashrefs
◆ Key: Content-Type
◆ Value: callback for data output
◆ First item is default content-type
➔ resource_exists
◆ returns 404 if this returns false
➔ Auto encoding if charset
package Bean::API::Resources::User;
…
# TRUE ? continue : return 404 RESOURCE NOT FOUND
sub resource_exists {
return !! $self->user;
}
sub content_types_provided {
return [
{‘application/json’ => ‘user_to_json’},
{‘text/html’ => ‘user_to_html’},
{‘application/x-tar => ‘user_to_tar’}
]
}
…
use CPanel::JSON::XS;
use Template::Toolkit;
sub user_to_json {
# May not handle inflated data! But fine for simple data
return encode_json({$self->user->get_columns});
}
sub user_to_html {
return $mason->run(‘/user’)->output;
}
...
package Bean::API::Resources::User;
…
sub resource_exists {
return !! $self->user;
}
# HashRefs of content type and handler name
# FOR GET REQUESTS
sub content_types_provided {
return [
{‘application/json’ => ‘user_to_json’},
{‘text/html’ => ‘user_to_html’},
{‘application/x-tar => ‘user_to_tar’}
];
}
...
package Bean::API::Resources::User;
…
sub resource_exists {
return !! $self->user;
}
sub content_types_provided {
return [
{‘application/json’ => ‘user_to_json’},
{‘text/html’ => ‘user_to_html’},
{‘application/x-tar => ‘user_to_tar’}
];
}
...
…
use CPanel::JSON::XS;
use Template::Toolkit;
sub user_to_json {
# May not handle inflated data! But fine for simple data
return encode_json({$self->user->get_columns});
}
sub user_to_html {
return $mason->run(‘/user’)->output;
}
...
package Bean::API::Resources::User;
…
sub resource_exists {
return !! $self->user;
}
sub content_types_provided {
return [
{‘application/json’ => ‘user_to_json’},
{‘text/html’ => ‘user_to_html’},
{‘application/x-tar => ‘user_to_tar’}
];
}
...
…
use CPanel::JSON::XS;
use Mason;
sub user_to_json {
# May not handle inflated data! But fine for simple data
return encode_json({$self->user->get_columns});
}
sub user_to_html {
return $mason->run(‘/user’)->output;
}
...
Authentication
➔ Authn/Authz
◆ Authentication (401) -> is_authorized(‘Authorization’)
◆ Authorization (403) -> forbidden()
➔ Can be a role for all resources
sub _basic_authn {
my ($self, $authn_string) = @_;
my ($username, $password) =
split(‘:’, decode_base64($authn_string));
my $is_authenticated =
$self->schema->resultset(‘User’)
->find({username => $username})
->is_authenticated($password);
if ($is_authenticated){
return 1;
} else {
return create_header(WWWAuthenticate => [
‘Basic’ => (realm => ”BB-LDAP”’)
]);
}
}
package Bean::API::Auth;
use Moo::Role;
use Web::Machine::Utils qw/create_header/;
# HTTP is bad at the distinction between Authz and
Authn
sub is_authorized {
my ($self, $authn_header) = @_;
my ($authn_type, $authn_string) =
split(‘ ‘, $authn_header);
if ($authn_type eq ‘Basic’){
return $self->_basic_authn($authn_string);
}
}
sub _basic_authn {
my ($self, $authn_string) = @_;
my ($username, $password) =
split(‘:’, decode_base64($authn_string));
my $is_authenticated =
$self
->schema
->resultset(‘User’)
->find({username => $username})
->is_authenticated($password);
if ($is_authenticated){
return 1;
} else {
return ‘Basic realm=”BB-LDAP”’
}
}
package Bean::API::Auth;
use Moo::Role;
# HTTP is bad at the distinction between Authz and
Authn
sub is_authorized {
my ($self, $authn_header) = @_;
my ($authn_type, $authn_string) =
split(‘ ‘, $authn_header);
if ($authn_type eq ‘Basic’){
return $self->_basic_authn($authn_string);
}
}
sub _basic_authn {
my ($self, $authn_string) = @_;
my ($username, $password) =
split(‘:’, decode_base64($authn_string));
my $is_authenticated =
$self
->schema
->resultset(‘User’)
->find({username => $username})
->is_authenticated($password);
if ($is_authenticated){
return 1;
} else {
return ‘Basic realm=”BB-LDAP”’
}
}
package Bean::API::Auth;
use Moo::Role;
# HTTP is bad at the distinction between Authz and
Authn
sub is_authorized {
my ($self, $authn_header) = @_;
my ($authn_type, $authn_string) =
split(‘ ‘, $authn_header);
if ($authn_type eq ‘Basic’){
return $self->_basic_authn($authn_string);
}
}
package Bean::API::Resources::User;
# HTTP is bad at the distinction between Authz and Authn
sub forbidden {
my ($self) = @_;
my $is_authorized = 0;
if ($self->request->method eq ‘GET’){
$is_authorized = $self->active_user->can_retrieve($self->user);
}
return $is_authorized;
}
PUT
➔ content_types_accepted
◆ Takes a list of
● Hashrefs
◆ Key: Content-Type
◆ Value: callback for data input
◆ First item is default content-type
package Bean::API::Resources::User;
sub content_types_accepted {
return [
{‘application/json’ => ‘user_from_json’},
];
}
# PUT user with 204 response
sub user_from_json {
my ($self) = @_;
$self->user->delete;
$self->user->create(decode_json($self->request->body));
}
POST
➔ post_is_create
◆ create_path / create_path_after_handler
◆ Then the post is treated like a PUT
➔ process_post
◆ handles all other post request
◆ No Support for Content-type based handlers
package Bean::API::Resources::User;
sub process_post {
my ($self) = @_;
# Do whatever you want
# No. really. anything!
# Return a status code
# If you set the response->body then it will be encoded with the correct charset if set
}
package Bean::API::Resources::User;
sub content_types_accepted {
return [
{‘application/json’ => ‘user_from_json’},
{‘application/x-webform-url-encoded’ => ‘user_from_webform’},
];
}
sub user_from_json {
# create/update user (POST/PUT)
}
sub post_is_create {1}
sub create_path_after_handler {return ‘/user/’.$self->user->id)}
DELETE
➔ delete_resource
◆ true if delete was/appears successful
◆ false if delete failed
➔ delete_completed
◆ delete appears successful but isn’t complete
Discussion
Questions, Answers, Understanding

Más contenido relacionado

La actualidad más candente

The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDAleix Vergés
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien Potencier
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016Kacper Gunia
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 WorldFabien Potencier
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
WordPress for developers - phpday 2011
WordPress for developers -  phpday 2011WordPress for developers -  phpday 2011
WordPress for developers - phpday 2011Maurizio Pelizzone
 

La actualidad más candente (20)

The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
WordPress for developers - phpday 2011
WordPress for developers -  phpday 2011WordPress for developers -  phpday 2011
WordPress for developers - phpday 2011
 

Similar a Web::Machine - Simpl{e,y} HTTP

WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
Mojolicious. Веб в коробке!
Mojolicious. Веб в коробке!Mojolicious. Веб в коробке!
Mojolicious. Веб в коробке!Anatoly Sharifulin
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stackPaul Bearne
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On RailsJohn Wilker
 
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsMashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsBastian Hofmann
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworksdiego_k
 
Curscatalyst
CurscatalystCurscatalyst
CurscatalystKar Juan
 
Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009hugowetterberg
 

Similar a Web::Machine - Simpl{e,y} HTTP (20)

Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
Blog Hacks 2011
Blog Hacks 2011Blog Hacks 2011
Blog Hacks 2011
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
RESTful web services
RESTful web servicesRESTful web services
RESTful web services
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
Mojolicious. Веб в коробке!
Mojolicious. Веб в коробке!Mojolicious. Веб в коробке!
Mojolicious. Веб в коробке!
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stack
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On Rails
 
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsMashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web Apps
 
Add loop shortcode
Add loop shortcodeAdd loop shortcode
Add loop shortcode
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Mashing up JavaScript
Mashing up JavaScriptMashing up JavaScript
Mashing up JavaScript
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworks
 
Curscatalyst
CurscatalystCurscatalyst
Curscatalyst
 
Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009
 

Último

CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 

Último (20)

Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 

Web::Machine - Simpl{e,y} HTTP

  • 2. Web::Machine? ➔ Simple HTTP State Machine… ➔ Represented as Resource classes ◆ See API Design talk ➔ Provides hooks for HTTP states ➔ Replacement for MVC style Web Frameworks ➔ Plack compatible
  • 3. PLACK use Plack::Builder; use Bean::API; builder { mount ‘/’ => Bean::API->as_psgi_app }
  • 4. sub as_psgi_app { my ($self) = @_; $self = ref $self ? $self : $self->new; $self->router->add_route('/users/:id' => validations => { id => Int, }, target => sub { my ($request, $id) = @_; my $app = Web::Machine->new( resource => Bean::API::Resources::User', resource_args => [ user_id => $id, ] )->to_app; return $app->($request->env); } ); return Plack::App::Path::Router->new(router => $self->router)->to_app; }
  • 5. sub as_psgi_app { my ($self) = @_; $self = ref $self ? $self : $self->new; $self->router->add_route('/users/:id' => validations => { id => Int, }, target => sub { my ($request, $id) = @_; my $app = Web::Machine->new( resource => Bean::API::Resources::User', resource_args => [ user_id => $id, ] )->to_app; return $app->($request->env); } ); return Plack::App::Path::Router->new(router => $self->router)->to_app; }
  • 6. my $app = Web::Machine->new( # Resource is a Web::Machine::Resource subclass resource => Bean::API::Resources::User', # resource_args are passed to the Resource subclass on initialization resource_args => [ user_id => $id, ] )->to_app;
  • 7. my $app = Web::Machine->new( # Resource is a Web::Machine::Resource subclass resource => Bean::API::Resources::User', # resource_args are passed to the Resource subclass on initialization resource_args => [ user_id => $id, ] )->to_app;
  • 8. my $app = Web::Machine->new( # Resource is a Web::Machine::Resource subclass resource => Bean::API::Resources::User', # resource_args are passed to the Resource subclass on initialization resource_args => [ user_id => $id, ] )->to_app;
  • 9. sub as_psgi_app { my ($self) = @_; $self = ref $self ? $self : $self->new; $self->router->add_route('/users/:id' => validations => { id => Int, }, target => sub { my ($request, $id) = @_; my $app = Web::Machine->new( resource => Bean::API::Resources::User', resource_args => [ user_id => $id, ] )->to_app; return $app->($request->env); } ); return Plack::App::Path::Router->new(router => $self->router)->to_app; }
  • 10. Resource Class ➔ @ISA ◆ Web::Machine::Resource ➔ use Moo{se} for fun and profit ➔ Kinda like a controller. ➔ has request, has response.
  • 11. package Bean::API::Resources::User; use Moo; extends ‘Web::Machine::Resource’; 1;
  • 12. package Bean::API::Resources::User; use Moo; extends ‘Web::Machine::Resource’; use Types::Standard qw/Int/ has user_id => ( is => ‘ro’, isa => Int, required => 1 ); 1; sub as_psgi_app { my ($self) = @_; $self = ref $self ? $self : $self->new; $self->router->add_route('/users/:id' => validations => { id => Int, }, target => sub { my ($request, $id) = @_; my $app = Web::Machine->new( resource => Bean::API::Resources::User', resource_args => [ user_id => $id, ] )->to_app; return $app->($request->env); } ); return Plack::App::Path::Router->new(router => $self->router)->to_app; }
  • 13. package Bean::API::Resources::User; use Moo; extends ‘Web::Machine::Resource’; use Types::Standard qw/Str/; has user_id => ( isa => Str, is => ‘ro’, required => 1 ); has user => ( is => ‘lazy’, isa => Maybe[‘Bean::Schema::ResultUser’], builder => 1, ); ... sub _build_user { return $schema->resultset(‘User’)->find($self->user_id); } ...
  • 14. sub resource_exists { 1 } sub service_available { 1 } sub is_authorized { 1 } sub forbidden { 0 } sub allow_missing_post { 0 } sub malformed_request { 0 } sub uri_too_long { 0 } sub known_content_type { 1 } sub valid_content_headers { 1 } sub valid_entity_length { 1 } sub options { +{} } sub allowed_methods { [ qw[GET HEAD] ] } sub known_methods { [qw[ GET HEAD POST PUT DELETE TRACE CONNECT OPTIONS ]]} sub delete_resource { 0 } sub delete_completed { 1 } sub post_is_create { 0 } sub create_path { undef } sub base_uri { undef } sub process_post { 0 } sub content_types_provided { [] } sub content_types_accepted { [] } sub charsets_provided { [] } sub default_charset {} sub languages_provided { [] } sub encodings_provided { { 'identity' => sub { $_[1] } } } sub variances { [] } sub is_conflict { 0 } sub multiple_choices { 0 } sub previously_existed { 0 } sub moved_permanently { 0 } sub moved_temporarily { 0 } sub last_modified { undef } sub expires { undef } sub generate_etag { undef } sub finish_request {} sub create_path_after_handler { 0 }
  • 15. sub resource_exists { 1 } sub service_available { 1 } sub is_authorized { 1 } sub forbidden { 0 } sub allow_missing_post { 0 } sub malformed_request { 0 } sub uri_too_long { 0 } sub known_content_type { 1 } sub valid_content_headers { 1 } sub valid_entity_length { 1 } sub options { +{} } sub allowed_methods { [ qw[ GET HEAD ] ] } sub known_methods { [qw[ GET HEAD POST PUT DELETE TRACE CONNECT OPTIONS ]] } sub delete_resource { 0 } sub delete_completed { 1 } sub post_is_create { 0 } sub create_path { undef } sub base_uri { undef } sub process_post { 0 } sub content_types_provided { [] } sub content_types_accepted { [] } sub charsets_provided { [] } sub default_charset {} sub languages_provided { [] } sub encodings_provided { { 'identity' => sub { $_[1] } } } sub variances { [] } sub is_conflict { 0 } sub multiple_choices { 0 } sub previously_existed { 0 } sub moved_permanently { 0 } sub moved_temporarily { 0 } sub last_modified { undef } sub expires { undef } sub generate_etag { undef } sub finish_request {} sub create_path_after_handler { 0 }
  • 16. GET ➔ content_types_provided ◆ Takes a list of ● Hashrefs ◆ Key: Content-Type ◆ Value: callback for data output ◆ First item is default content-type ➔ resource_exists ◆ returns 404 if this returns false ➔ Auto encoding if charset
  • 17. package Bean::API::Resources::User; … # TRUE ? continue : return 404 RESOURCE NOT FOUND sub resource_exists { return !! $self->user; } sub content_types_provided { return [ {‘application/json’ => ‘user_to_json’}, {‘text/html’ => ‘user_to_html’}, {‘application/x-tar => ‘user_to_tar’} ] }
  • 18. … use CPanel::JSON::XS; use Template::Toolkit; sub user_to_json { # May not handle inflated data! But fine for simple data return encode_json({$self->user->get_columns}); } sub user_to_html { return $mason->run(‘/user’)->output; } ... package Bean::API::Resources::User; … sub resource_exists { return !! $self->user; } # HashRefs of content type and handler name # FOR GET REQUESTS sub content_types_provided { return [ {‘application/json’ => ‘user_to_json’}, {‘text/html’ => ‘user_to_html’}, {‘application/x-tar => ‘user_to_tar’} ]; } ...
  • 19. package Bean::API::Resources::User; … sub resource_exists { return !! $self->user; } sub content_types_provided { return [ {‘application/json’ => ‘user_to_json’}, {‘text/html’ => ‘user_to_html’}, {‘application/x-tar => ‘user_to_tar’} ]; } ... … use CPanel::JSON::XS; use Template::Toolkit; sub user_to_json { # May not handle inflated data! But fine for simple data return encode_json({$self->user->get_columns}); } sub user_to_html { return $mason->run(‘/user’)->output; } ...
  • 20. package Bean::API::Resources::User; … sub resource_exists { return !! $self->user; } sub content_types_provided { return [ {‘application/json’ => ‘user_to_json’}, {‘text/html’ => ‘user_to_html’}, {‘application/x-tar => ‘user_to_tar’} ]; } ... … use CPanel::JSON::XS; use Mason; sub user_to_json { # May not handle inflated data! But fine for simple data return encode_json({$self->user->get_columns}); } sub user_to_html { return $mason->run(‘/user’)->output; } ...
  • 21. Authentication ➔ Authn/Authz ◆ Authentication (401) -> is_authorized(‘Authorization’) ◆ Authorization (403) -> forbidden() ➔ Can be a role for all resources
  • 22. sub _basic_authn { my ($self, $authn_string) = @_; my ($username, $password) = split(‘:’, decode_base64($authn_string)); my $is_authenticated = $self->schema->resultset(‘User’) ->find({username => $username}) ->is_authenticated($password); if ($is_authenticated){ return 1; } else { return create_header(WWWAuthenticate => [ ‘Basic’ => (realm => ”BB-LDAP”’) ]); } } package Bean::API::Auth; use Moo::Role; use Web::Machine::Utils qw/create_header/; # HTTP is bad at the distinction between Authz and Authn sub is_authorized { my ($self, $authn_header) = @_; my ($authn_type, $authn_string) = split(‘ ‘, $authn_header); if ($authn_type eq ‘Basic’){ return $self->_basic_authn($authn_string); } }
  • 23. sub _basic_authn { my ($self, $authn_string) = @_; my ($username, $password) = split(‘:’, decode_base64($authn_string)); my $is_authenticated = $self ->schema ->resultset(‘User’) ->find({username => $username}) ->is_authenticated($password); if ($is_authenticated){ return 1; } else { return ‘Basic realm=”BB-LDAP”’ } } package Bean::API::Auth; use Moo::Role; # HTTP is bad at the distinction between Authz and Authn sub is_authorized { my ($self, $authn_header) = @_; my ($authn_type, $authn_string) = split(‘ ‘, $authn_header); if ($authn_type eq ‘Basic’){ return $self->_basic_authn($authn_string); } }
  • 24. sub _basic_authn { my ($self, $authn_string) = @_; my ($username, $password) = split(‘:’, decode_base64($authn_string)); my $is_authenticated = $self ->schema ->resultset(‘User’) ->find({username => $username}) ->is_authenticated($password); if ($is_authenticated){ return 1; } else { return ‘Basic realm=”BB-LDAP”’ } } package Bean::API::Auth; use Moo::Role; # HTTP is bad at the distinction between Authz and Authn sub is_authorized { my ($self, $authn_header) = @_; my ($authn_type, $authn_string) = split(‘ ‘, $authn_header); if ($authn_type eq ‘Basic’){ return $self->_basic_authn($authn_string); } }
  • 25. package Bean::API::Resources::User; # HTTP is bad at the distinction between Authz and Authn sub forbidden { my ($self) = @_; my $is_authorized = 0; if ($self->request->method eq ‘GET’){ $is_authorized = $self->active_user->can_retrieve($self->user); } return $is_authorized; }
  • 26. PUT ➔ content_types_accepted ◆ Takes a list of ● Hashrefs ◆ Key: Content-Type ◆ Value: callback for data input ◆ First item is default content-type
  • 27. package Bean::API::Resources::User; sub content_types_accepted { return [ {‘application/json’ => ‘user_from_json’}, ]; } # PUT user with 204 response sub user_from_json { my ($self) = @_; $self->user->delete; $self->user->create(decode_json($self->request->body)); }
  • 28. POST ➔ post_is_create ◆ create_path / create_path_after_handler ◆ Then the post is treated like a PUT ➔ process_post ◆ handles all other post request ◆ No Support for Content-type based handlers
  • 29. package Bean::API::Resources::User; sub process_post { my ($self) = @_; # Do whatever you want # No. really. anything! # Return a status code # If you set the response->body then it will be encoded with the correct charset if set }
  • 30. package Bean::API::Resources::User; sub content_types_accepted { return [ {‘application/json’ => ‘user_from_json’}, {‘application/x-webform-url-encoded’ => ‘user_from_webform’}, ]; } sub user_from_json { # create/update user (POST/PUT) } sub post_is_create {1} sub create_path_after_handler {return ‘/user/’.$self->user->id)}
  • 31. DELETE ➔ delete_resource ◆ true if delete was/appears successful ◆ false if delete failed ➔ delete_completed ◆ delete appears successful but isn’t complete