RESTful web services

1,925 views
1,792 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,925
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
17
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

RESTful web services

  1. 1. RESTful Web Serviceswith Mojolicious and DBIx::Class
  2. 2. About me● Tudor Constantin● Perl Developer @ Evozon● http://programming.tudorconstantin.com/● http://stackoverflow.com/users/459233/tudor-constantin● https://github.com/tudorconstantin● http://www.linkedin.com/in/tudorconstantin● twitter: @tudorconstantin● gmail: tudorconstantin at gmail dot com
  3. 3. Content● Sample app overview - Expense Tracker● (Short) Intro to RESTful Web Services● DBIx::Class● Mojolicious● Routing in Mojo● Generic Mojo Controller for CRUD operations● Sample operation - update user● Steps for getting RESTful routes/operations for a table in DB
  4. 4. Sample app ExpenseTrackerVERY simple application - but usable (insert expenses, assign categories andsee reports)● Five tables ○ users ○ currencies ○ categories ○ operations ○ operations_categories● Relationships ○ 1 user has many categories ○ 1 user has many operations ○ 1 category has many sub categories ○ 1 category has many operations ○ 1 operation has many categories ○ 1 operation has a currency1 operation belongs to a user
  5. 5. Intro to RESTful WebServicesREST - REpresentational State Transfer ● concept introduced in 2000 by Roy Fielding in his academic dissertation, "Architectural Styles and the Design of Network-based Software Architectures"Main ideas for REST:● Resources are accessible through unique URLs: ○ /user/23 ○ /operations● Use HTTP methods explicitly ○ GET - for Read ○ POST - for Create ○ PUT - for Update ○ DELETE - for Delete● Be stateless ○ the server does not know nor cares about the state of the client application● Transfer Representations of resources (HTML, JSON, XML, etc)
  6. 6. DBIx::Class● An abstraction for working with DBs● More than an ORM (Object Relational Mapper) - It knows how to work on Result Sets● Components - simplified overview: ○ DBIx::Class::Schema - connection to DB ○ DBIx::Class::ResultSet - a query used for fetching a set of results ○ DBIx::Class::Row - objects returned from DBIx::Class::ResultSets using the create, find, next and all methods● Sample usage: my @rows = ExpenseTracker::Models->connect( $config->{database}->{ $mode }->{dsn}, $config->{database}->{ $mode }->{user}, $config->{database}->{ $mode }->{password}, ) # DBIx::Class::Schema ->resultset( ExpenseTracker::Models::Result::User ) # DBIx::Class::ResultSet ->search_rs( { id => 10 }, ) # DBIx::Class::ResultSet - only users with id = 10 ->all(); # The collection of DBIx::Class::Row instances
  7. 7. Mojolicious● Microframework inspired by Sinatra (Ruby)● Components of interest (for this app) ○ Router ○ Controller● Not (quite) interested in: ○ Views (since we render mainly json)● Not provided at all: ○ Models (we plug in and use DBIx::Class)
  8. 8. Routing in MojoliciousIn app context (ie - the startup routine):my $r = $self->routes;#sample route named login for GET - executing method login from controller ExpenseTracker::Controllers::Login$r->get(/login)->to(login#login)->name(login);Shortcut, generic routing:$params->{app_routes}->add_shortcut(resource => sub { my ($r, $name ) = @_; # Generate route for "/$name" - Controller is ExpenseTracker::Controller::camelize($name) my $resource = $r->route( "/$name" )->to("$name#"); # Handle POST requests - will hit the create method in controller $resource->post->to(#create)->name("create_$name"); # Handle GET requests - lists the collection of this resource - hits the list method in controller $resource->get->to(#list)->name("list_$name"); $resource = $r->route( "/$name/:id" )->to("$name#"); $resource->get->to(#show)->name("show_$name"); $resource->delete->to(#remove)->name("delete_$name"); $resource->put->to(#update)->name("update_$name"); return $resource; });
  9. 9. Generic Controller for CRUDOperations● Each resource needs a controller responsible for it● Each of those controllers will have to implement at least 7 actions: ○ create - POST /resource_name - creates a new resource ○ update - PUT /resource_name/:id - updates a resource ○ list - GET /resource_name - show the collection of resources ○ show - GET /resource_name/:id - get the resource with id :id ○ remove - DELETE /resource_name/:id - annihilate resource :id● Possible approaches ○ create a Moose role that will expose all those methods and use this role (I guess) ○ implement a basic controller that will be inherited by all the other resource controller
  10. 10. Sample op - update userIn child controller (ExpenseTracker::Controller::User)=head update sample of overriding a default update methodroute here: PUT /user/:id=cutsub update{ my $self = shift; return $self->render(status => 405, json => {message => You can only update your own profile!!!} ) if ( !defined $self->param(id) or !defined $self->app->user or $self->param(id) != $self->app->user->id ); return $self->SUPER::update(@_);}
  11. 11. Sample op - update userIn base controller ExpenseTracker::Controllers::Base - the one thatExpenseTracker::Controllers::User inherits from:sub update{ my $self = shift; my $result_rs = $self->app->model ->resultset( $self->{resource} ) ->search_rs( { id => $self->param(id) }, ); return $self->render_not_found if ( scalar( ( $result_rs->all ) ) == 0 ); $result_rs->update_all( $self->req->json ); $result_rs->result_class(DBIx::Class::ResultClass::HashRefInflator); my @result = $result_rs->all(); return $self->render_json( [ @result ] );}
  12. 12. Steps for getting RESTfulroutes/operations● Generate the DBIx::Class model based on the DB table, with DBIx:: Class::Schema::Loader● Create a controller that inherits from ExpenseTracker::Controllers::Base● Add the resource name to the conf.yml
  13. 13. The EndFork the sample app and play with it:https://github.com/tudorconstantin/expense-tracker

×