SlideShare une entreprise Scribd logo
1  sur  136
Télécharger pour lire hors ligne
Making Your Perl REST   Sterling Hanenkamp, PPW 2008
What is REST?
What is REST?

• Ever heard of...
What is REST?

• Ever heard of...


• SOAP?
What is REST?

• Ever heard of...


• SOAP?


• RPC?
What is REST?

• Ever heard of...


• SOAP?


• RPC?


• XML-RPC?
What is REST?

• Ever heard of...


• SOAP?


• RPC?


• XML-RPC?


• WebDAV?
What is REST?

• Ever heard of...


• SOAP?


• RPC?


• XML-RPC?


• WebDAV?


• It’s kind of like that.
What is REST?

• Ever heard of...          • Ever heard of...


• SOAP?


• RPC?


• XML-RPC?


• WebDAV?


• It’s kind of like that.
What is REST?

• Ever heard of...          • Ever heard of...


• SOAP?                     • HTTP?


• RPC?


• XML-RPC?


• WebDAV?


• It’s kind of like that.
What is REST?

• Ever heard of...          • Ever heard of...


• SOAP?                     • HTTP?


• RPC?                      • XML?


• XML-RPC?


• WebDAV?


• It’s kind of like that.
What is REST?

• Ever heard of...          • Ever heard of...


• SOAP?                     • HTTP?


• RPC?                      • XML?


• XML-RPC?                  • YAML?


• WebDAV?


• It’s kind of like that.
What is REST?

• Ever heard of...          • Ever heard of...


• SOAP?                     • HTTP?


• RPC?                      • XML?


• XML-RPC?                  • YAML?


• WebDAV?                   • JSON?


• It’s kind of like that.
What is REST?

• Ever heard of...          • Ever heard of...


• SOAP?                     • HTTP?


• RPC?                      • XML?


• XML-RPC?                  • YAML?


• WebDAV?                   • JSON?


• It’s kind of like that.   • It’s kind of like that too
What are we NOT talking about?
What are we NOT talking about?

• REST is a general purpose term
What are we NOT talking about?

• REST is a general purpose term


• I’m not talking about a general notion
What are we NOT talking about?

• REST is a general purpose term


• I’m not talking about a general notion


• We’re talking about REST APIs
What are we NOT talking about?

• REST is a general purpose term


• I’m not talking about a general notion


• We’re talking about REST APIs


• Web Services
What are we NOT talking about?

• REST is a general purpose term


• I’m not talking about a general notion


• We’re talking about REST APIs


• Web Services


• Mashups!!!! Web 2.0!!! Yippee!!!
What are we NOT talking about?

• REST is a general purpose term


• I’m not talking about a general notion


• We’re talking about REST APIs


• Web Services


• Mashups!!!! Web 2.0!!! Yippee!!!
What are we NOT talking about?

• REST is a general purpose term


• I’m not talking about a general notion


• We’re talking about REST APIs


• Web Services


• Mashups!!!! Web 2.0!!! Yippee!!!


• I’ve used my lifetime supply of exclamation points...
The REST Triangle
The REST Triangle

    no
       un
    ht s
      tp
         ://
             ww
                w.
                   on
                        lam
                           p.c
                              om

                      content types
              YAML, XML, JSON, etc.


                                 T E
                              LE
                         DE
                    U T,
        b s ST, P
      er PO
     v ,
     G ET
The REST Triangle

    no                                 • Nouns (=URL)
       un
    ht s
      tp
         ://
             ww
                w.
                   on
                        lam
                           p.c
                              om

                      content types
              YAML, XML, JSON, etc.


                                 T E
                              LE
                         DE
                    U T,
        b s ST, P
      er PO
     v ,
     G ET
The REST Triangle

    no                                 • Nouns (=URL)
       un
    ht s
      tp
         ://
             ww                        • Verbs (=HTTP METHOD)
                w.
                   on
                        lam
                           p.c
                              om

                      content types
              YAML, XML, JSON, etc.


                                 T E
                              LE
                         DE
                    U T,
        b s ST, P
      er PO
     v ,
     G ET
The REST Triangle

    no                                 • Nouns (=URL)
       un
    ht s
      tp
         ://
             ww                        • Verbs (=HTTP METHOD)
                w.
                   on
                        lam
                           p.c
                              om       • Content (=MIME Type)

                      content types
              YAML, XML, JSON, etc.


                                 T E
                              LE
                         DE
                    U T,
        b s ST, P
      er PO
     v ,
     G ET
REST Web Services
REST Web Services




                    CRUD
REST Web Services




                    CRUD
                           Create
REST Web Services




                    CRUD
                           Create

                           Read
REST Web Services




                    CRUD
                           Create

                           Read

                       Update
REST Web Services




                    CRUD
                           Create

                           Read

                       Update

                           Delete
REST Web Services

• Treat your data like a static web page




                                           CRUD
                                                  Create

                                                  Read

                                              Update

                                                  Delete
REST Web Services

• Treat your data like a static web page




                                           CRUD
• Add data by POSTing a web page                  Create

                                                  Read

                                              Update

                                                  Delete
REST Web Services

• Treat your data like a static web page




                                           CRUD
• Add data by POSTing a web page                  Create

• Fetch data by GETting a web page                Read

                                              Update

                                                  Delete
REST Web Services

• Treat your data like a static web page




                                           CRUD
• Add data by POSTing a web page                  Create

• Fetch data by GETting a web page                Read
• Update data by PUTing a web page
                                              Update

                                                  Delete
REST Web Services

• Treat your data like a static web page




                                           CRUD
• Add data by POSTing a web page                  Create

• Fetch data by GETting a web page                Read
• Update data by PUTing a web page
                                              Update
• Delete data by DELETing a web page

                                                  Delete
REST Web Services

• Treat your data like a static web page




                                           CRUD
• Add data by POSTing a web page                  Create

• Fetch data by GETting a web page                Read
• Update data by PUTing a web page
                                              Update
• Delete data by DELETing a web page


• E... it’s missing and it bugs me...
                                                  Delete
Who Uses It
Who Uses It

• Google           • Socialtext


• Yahoo!           • Digg


• Amazon           • Twitter


• Intuit           • eBay


• Best Practical   • Technorati


• Facebook         • Too many others to mention...
What about other stuff?
What about other stuff?

• RPC is a square peg
What about other stuff?

• RPC is a square peg


• REST is round hole
What about other stuff?

• RPC is a square peg


• REST is round hole
What about other stuff?

• RPC is a square peg


• REST is round hole


• But it works!
What about other stuff?

• RPC is a square peg


• REST is round hole


• But it works!


• Getting Info? GET
What about other stuff?

• RPC is a square peg


• REST is round hole


• But it works!


• Getting Info? GET


• Modifying Something? POST
What about other stuff?

• RPC is a square peg


• REST is round hole


• But it works!


• Getting Info? GET


• Modifying Something? POST


• Both? Not sure? POST
ENOUGH BASICS. LET’S DO SOMETHING.
# Manage your books from the command-line. Woo-hoo!
% ./book list
# Manage your books from the command-line. Woo-hoo!
% ./book list
0-8024-8160-4: .../library.cgi/=/model/book/id/0-8024-8160-4
0-85151-760-9: .../library.cgi/=/model/book/id/0-85151-760-9
0-936083-11-5: .../library.cgi/=/model/book/id/0-936083-11-5
% ./book read 0-8024-8160-4
% ./book read 0-8024-8160-4
---
author: David Clotfelter
city: Chicago
id: 0-8024-8160-4
isbn: 0-8024-8160-4
publisher: Moody Publishers
title: >
  Sinners in the Hands of a Good God:
  Reconciling Divine Judgment and Mercy'
year: 2004
% ./book create reformation.yml
% ./book create reformation.yml
0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5
% ./book create reformation.yml
0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5

% ./book update 0-87552-183-5 reformation2.yml
% ./book create reformation.yml
0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5

% ./book update 0-87552-183-5 reformation2.yml
Updated 0-87552-183-5
% ./book create reformation.yml
0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5

% ./book update 0-87552-183-5 reformation2.yml
Updated 0-87552-183-5

% ./book delete 0-87552-183-5
% ./book create reformation.yml
0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5

% ./book update 0-87552-183-5 reformation2.yml
Updated 0-87552-183-5

% ./book delete 0-87552-183-5
Deleted 0-87552-183-5
Okay...
                         Putting it together
But what did that do?
Explaining the Nouns (a.k.a. URLs)
Explaining the Nouns (a.k.a. URLs)

             Scheme Borrowed from Jifty
Explaining the Nouns (a.k.a. URLs)

                 Scheme Borrowed from Jifty
         What             Example             Why?

         Prefix               /=           Marker for REST

     Kind of Thing        /=/model          More Kinds

    Name of Thing      /=/model/book       More Models

     Field of Thing   /=/model/book/id Multiple Identifiers

     Value of Field   /=/mode/book/id/1   Multiple Things
Explaining the Nouns (a.k.a. URLs)

                 Scheme Borrowed from Jifty
         What             Example             Why?

         Prefix               /=           Marker for REST

     Kind of Thing        /=/model          More Kinds

    Name of Thing      /=/model/book       More Models

     Field of Thing   /=/model/book/id Multiple Identifiers

     Value of Field   /=/mode/book/id/1   Multiple Things
Explaining the Nouns (a.k.a. URLs)

                 Scheme Borrowed from Jifty
         What             Example             Why?

         Prefix               /=           Marker for REST

     Kind of Thing        /=/model          More Kinds

    Name of Thing      /=/model/book       More Models

     Field of Thing   /=/model/book/id Multiple Identifiers

     Value of Field   /=/mode/book/id/1   Multiple Things
Explaining the Nouns (a.k.a. URLs)

                 Scheme Borrowed from Jifty
         What             Example             Why?

         Prefix               /=           Marker for REST

     Kind of Thing        /=/model          More Kinds

    Name of Thing      /=/model/book       More Models

     Field of Thing   /=/model/book/id Multiple Identifiers

     Value of Field   /=/mode/book/id/1   Multiple Things
Explaining the Nouns (a.k.a. URLs)

                 Scheme Borrowed from Jifty
         What             Example             Why?

         Prefix               /=           Marker for REST

     Kind of Thing        /=/model          More Kinds

    Name of Thing      /=/model/book       More Models

     Field of Thing   /=/model/book/id Multiple Identifiers

     Value of Field   /=/mode/book/id/1   Multiple Things
Explaining the Nouns (a.k.a. URLs)

                 Scheme Borrowed from Jifty
         What             Example             Why?

         Prefix               /=           Marker for REST

     Kind of Thing        /=/model          More Kinds

    Name of Thing      /=/model/book       More Models

     Field of Thing   /=/model/book/id Multiple Identifiers

     Value of Field   /=/mode/book/id/1   Multiple Things
Read (List)
# book list - lists all the books the server returns
subcommand 'list' => sub {

     # GET /=/model/book
     my $response = $ua->request(GET HOST.'/=/model/book/id');

     # On success, find the link and print them out
     if ($response->is_success) {
         my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm;
         for my $url (@links) {
             my ($id) = $url =~ /([d-]+)$/;
             print quot;$id: $urlnquot;;
         }
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Read (List)
# book list - lists all the books the server returns
subcommand 'list' => sub {

     # GET /=/model/book
     my $response = $ua->request(GET HOST.'/=/model/book/id');

     # On success, find the link and print them out
     if ($response->is_success) {
         my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm;
         for my $url (@links) {
             my ($id) = $url =~ /([d-]+)$/;
             print quot;$id: $urlnquot;;
         }
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Read (List)
# book list - lists all the books the server returns
subcommand 'list' => sub {

     # GET /=/model/book
     my $response = $ua->request(GET HOST.'/=/model/book/id');

     # On success, find the link and print them out
     if ($response->is_success) {
         my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm;
         for my $url (@links) {
             my ($id) = $url =~ /([d-]+)$/;
             print quot;$id: $urlnquot;;
         }
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Read (List)
# book list - lists all the books the server returns
subcommand 'list' => sub {

     # GET /=/model/book
     my $response = $ua->request(GET HOST.'/=/model/book/id');

     # On success, find the link and print them out
     if ($response->is_success) {
         my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm;
         for my $url (@links) {
             my ($id) = $url =~ /([d-]+)$/;
             print quot;$id: $urlnquot;;
         }
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Read (List)
# book list - lists all the books the server returns
subcommand 'list' => sub {

     # GET /=/model/book
     my $response = $ua->request(GET HOST.'/=/model/book/id');

     # On success, find the link and print them out
     if ($response->is_success) {
         my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm;
         for my $url (@links) {
             my ($id) = $url =~ /([d-]+)$/;
             print quot;$id: $urlnquot;;
         }
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Read (List)

# Get a whole list of available documents
GET qr{^/=/model/book/id$} => sub {
    print $q->header('text/html');

     # Find all the files available
     my @items;
     for my $filename (glob get_local_path('*')) {
         my ($id) = $filename =~ m{([d-]+)$};
         next unless defined $id;

         push @items, $q->li(
             $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id),
         );
     }

     # List the items
     print $q->ul( @items);
};
Read (List)

# Get a whole list of available documents
GET qr{^/=/model/book/id$} => sub {
    print $q->header('text/html');

     # Find all the files available
     my @items;
     for my $filename (glob get_local_path('*')) {
         my ($id) = $filename =~ m{([d-]+)$};
         next unless defined $id;

         push @items, $q->li(
             $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id),
         );
     }

     # List the items
     print $q->ul( @items);
};
Read (List)

# Get a whole list of available documents
GET qr{^/=/model/book/id$} => sub {
    print $q->header('text/html');

     # Find all the files available
     my @items;
     for my $filename (glob get_local_path('*')) {
         my ($id) = $filename =~ m{([d-]+)$};
         next unless defined $id;

         push @items, $q->li(
             $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id),
         );
     }

     # List the items
     print $q->ul( @items);
};
Read (List)

# Get a whole list of available documents
GET qr{^/=/model/book/id$} => sub {
    print $q->header('text/html');

     # Find all the files available
     my @items;
     for my $filename (glob get_local_path('*')) {
         my ($id) = $filename =~ m{([d-]+)$};
         next unless defined $id;

         push @items, $q->li(
             $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id),
         );
     }

     # List the items
     print $q->ul( @items);
};
Read (List)

# Get a whole list of available documents
GET qr{^/=/model/book/id$} => sub {
    print $q->header('text/html');

     # Find all the files available
     my @items;
     for my $filename (glob get_local_path('*')) {
         my ($id) = $filename =~ m{([d-]+)$};
         next unless defined $id;

         push @items, $q->li(
             $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id),
         );
     }

     # List the items
     print $q->ul( @items);
};
Read (Single)

     # book read <id> - reads the book file for <id>
     subcommand 'read' => sub {
         my $id = shift @ARGV;

         # GET /=/model/book/id/[id]
         my $response = $ua->request(GET HOST.'/=/model/book/id/'
                                         .$id);

      # On success, print the file
      if ($response->is_success) {
          print $response->content;
      }

      # On failure, barf
      else {
          barf $response;
      }
};
Read (Single)

     # book read <id> - reads the book file for <id>
     subcommand 'read' => sub {
         my $id = shift @ARGV;

         # GET /=/model/book/id/[id]
         my $response = $ua->request(GET HOST.'/=/model/book/id/'
                                         .$id);

      # On success, print the file
      if ($response->is_success) {
          print $response->content;
      }

      # On failure, barf
      else {
          barf $response;
      }
};
Read (Single)

     # book read <id> - reads the book file for <id>
     subcommand 'read' => sub {
         my $id = shift @ARGV;

         # GET /=/model/book/id/[id]
         my $response = $ua->request(GET HOST.'/=/model/book/id/'
                                         .$id);

      # On success, print the file
      if ($response->is_success) {
          print $response->content;
      }

      # On failure, barf
      else {
          barf $response;
      }
};
Read (Single)

     # book read <id> - reads the book file for <id>
     subcommand 'read' => sub {
         my $id = shift @ARGV;

         # GET /=/model/book/id/[id]
         my $response = $ua->request(GET HOST.'/=/model/book/id/'
                                         .$id);

      # On success, print the file
      if ($response->is_success) {
          print $response->content;
      }

      # On failure, barf
      else {
          barf $response;
      }
};
Read (Single)

     # book read <id> - reads the book file for <id>
     subcommand 'read' => sub {
         my $id = shift @ARGV;

         # GET /=/model/book/id/[id]
         my $response = $ua->request(GET HOST.'/=/model/book/id/'
                                         .$id);

      # On success, print the file
      if ($response->is_success) {
          print $response->content;
      }

      # On failure, barf
      else {
          barf $response;
      }
};
Read (Single)
# Look up and read a resource
GET qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Look up the resource file
     my $filename = get_local_path($id);
     if (-f $filename) {

         # Open and slurp up the file and output the resource
         open my $bookfh, $filename
             or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;;

         print $q->header('text/yaml');
         print do { local $/; <$bookfh> };
     }

     # No such resource exists
     else{
         barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;;
     }
};
Read (Single)
# Look up and read a resource
GET qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Look up the resource file
     my $filename = get_local_path($id);
     if (-f $filename) {

         # Open and slurp up the file and output the resource
         open my $bookfh, $filename
             or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;;

         print $q->header('text/yaml');
         print do { local $/; <$bookfh> };
     }

     # No such resource exists
     else{
         barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;;
     }
};
Read (Single)
# Look up and read a resource
GET qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Look up the resource file
     my $filename = get_local_path($id);
     if (-f $filename) {

         # Open and slurp up the file and output the resource
         open my $bookfh, $filename
             or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;;

         print $q->header('text/yaml');
         print do { local $/; <$bookfh> };
     }

     # No such resource exists
     else{
         barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;;
     }
};
Read (Single)
# Look up and read a resource
GET qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Look up the resource file
     my $filename = get_local_path($id);
     if (-f $filename) {

         # Open and slurp up the file and output the resource
         open my $bookfh, $filename
             or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;;

         print $q->header('text/yaml');
         print do { local $/; <$bookfh> };
     }

     # No such resource exists
     else{
         barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;;
     }
};
Read (Single)
# Look up and read a resource
GET qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Look up the resource file
     my $filename = get_local_path($id);
     if (-f $filename) {

         # Open and slurp up the file and output the resource
         open my $bookfh, $filename
             or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;;

         print $q->header('text/yaml');
         print do { local $/; <$bookfh> };
     }

     # No such resource exists
     else{
         barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;;
     }
};
Read (Single)
# Look up and read a resource
GET qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Look up the resource file
     my $filename = get_local_path($id);
     if (-f $filename) {

         # Open and slurp up the file and output the resource
         open my $bookfh, $filename
             or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;;

         print $q->header('text/yaml');
         print do { local $/; <$bookfh> };
     }

     # No such resource exists
     else{
         barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;;
     }
};
Create
# book create <filename> - submits the book file in <filename> to the server
subcommand 'create' => sub {
    my $file = shift @ARGV;

     # Slurp up the contents of the given filename
     my $book_data = slurp $file;

     # POST /=/model/book
     my $response = $ua->request(POST HOST.'/=/model/book',
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, return the new ID assigned to the resource
     if ($response->is_success) {
         my $url = $response->header('Location');
         my ($id) = $url =~ /([d-]+)$/;
         print quot;$id: $urlnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Create
# book create <filename> - submits the book file in <filename> to the server
subcommand 'create' => sub {
    my $file = shift @ARGV;

     # Slurp up the contents of the given filename
     my $book_data = slurp $file;

     # POST /=/model/book
     my $response = $ua->request(POST HOST.'/=/model/book',
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, return the new ID assigned to the resource
     if ($response->is_success) {
         my $url = $response->header('Location');
         my ($id) = $url =~ /([d-]+)$/;
         print quot;$id: $urlnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Create
# book create <filename> - submits the book file in <filename> to the server
subcommand 'create' => sub {
    my $file = shift @ARGV;

     # Slurp up the contents of the given filename
     my $book_data = slurp $file;

     # POST /=/model/book
     my $response = $ua->request(POST HOST.'/=/model/book',
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, return the new ID assigned to the resource
     if ($response->is_success) {
         my $url = $response->header('Location');
         my ($id) = $url =~ /([d-]+)$/;
         print quot;$id: $urlnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Create
# book create <filename> - submits the book file in <filename> to the server
subcommand 'create' => sub {
    my $file = shift @ARGV;

     # Slurp up the contents of the given filename
     my $book_data = slurp $file;

     # POST /=/model/book
     my $response = $ua->request(POST HOST.'/=/model/book',
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, return the new ID assigned to the resource
     if ($response->is_success) {
         my $url = $response->header('Location');
         my ($id) = $url =~ /([d-]+)$/;
         print quot;$id: $urlnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Create
# book create <filename> - submits the book file in <filename> to the server
subcommand 'create' => sub {
    my $file = shift @ARGV;

     # Slurp up the contents of the given filename
     my $book_data = slurp $file;

     # POST /=/model/book
     my $response = $ua->request(POST HOST.'/=/model/book',
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, return the new ID assigned to the resource
     if ($response->is_success) {
         my $url = $response->header('Location');
         my ($id) = $url =~ /([d-]+)$/;
         print quot;$id: $urlnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Create
# book create <filename> - submits the book file in <filename> to the server
subcommand 'create' => sub {
    my $file = shift @ARGV;

     # Slurp up the contents of the given filename
     my $book_data = slurp $file;

     # POST /=/model/book
     my $response = $ua->request(POST HOST.'/=/model/book',
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, return the new ID assigned to the resource
     if ($response->is_success) {
         my $url = $response->header('Location');
         my ($id) = $url =~ /([d-]+)$/;
         print quot;$id: $urlnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Create (part 1)


# Handle the creation of new books
POST qr{^/=/model/book$} => sub {

    # Check to make sure the input book is sane
    my $book= check_book( $q->param('POSTDATA') );

    # If we have an ISBN (some books don't!), then die if we already have
    # it because we don't permit POST cannot for updates!
    if ($book->{isbn} and -f get_local_path($book->{isbn})) {
        barf 500, 'Not Gonna Do It',
            'A POST may not be used to update an existing book.';
    }

    # Our data is sane!

 # ...
Create (part 1)


# Handle the creation of new books
POST qr{^/=/model/book$} => sub {

    # Check to make sure the input book is sane
    my $book= check_book( $q->param('POSTDATA') );

    # If we have an ISBN (some books don't!), then die if we already have
    # it because we don't permit POST cannot for updates!
    if ($book->{isbn} and -f get_local_path($book->{isbn})) {
        barf 500, 'Not Gonna Do It',
            'A POST may not be used to update an existing book.';
    }

    # Our data is sane!

 # ...
Create (part 1)


# Handle the creation of new books
POST qr{^/=/model/book$} => sub {

    # Check to make sure the input book is sane
    my $book= check_book( $q->param('POSTDATA') );

    # If we have an ISBN (some books don't!), then die if we already have
    # it because we don't permit POST cannot for updates!
    if ($book->{isbn} and -f get_local_path($book->{isbn})) {
        barf 500, 'Not Gonna Do It',
            'A POST may not be used to update an existing book.';
    }

    # Our data is sane!

 # ...
Create (part 1)


# Handle the creation of new books
POST qr{^/=/model/book$} => sub {

    # Check to make sure the input book is sane
    my $book= check_book( $q->param('POSTDATA') );

    # If we have an ISBN (some books don't!), then die if we already have
    # it because we don't permit POST cannot for updates!
    if ($book->{isbn} and -f get_local_path($book->{isbn})) {
        barf 500, 'Not Gonna Do It',
            'A POST may not be used to update an existing book.';
    }

    # Our data is sane!

 # ...
Create (part 1)


# Handle the creation of new books
POST qr{^/=/model/book$} => sub {

    # Check to make sure the input book is sane
    my $book= check_book( $q->param('POSTDATA') );

    # If we have an ISBN (some books don't!), then die if we already have
    # it because we don't permit POST cannot for updates!
    if ($book->{isbn} and -f get_local_path($book->{isbn})) {
        barf 500, 'Not Gonna Do It',
            'A POST may not be used to update an existing book.';
    }

    # Our data is sane!

 # ...
Create (part 1)


# Handle the creation of new books
POST qr{^/=/model/book$} => sub {

    # Check to make sure the input book is sane
    my $book= check_book( $q->param('POSTDATA') );

    # If we have an ISBN (some books don't!), then die if we already have
    # it because we don't permit POST cannot for updates!
    if ($book->{isbn} and -f get_local_path($book->{isbn})) {
        barf 500, 'Not Gonna Do It',
            'A POST may not be used to update an existing book.';
    }

    # Our data is sane!

 # ...
Create (part 2)
     # ...

     # Figure out an ID, this is either the ISBN or a generated ID
     my $id = $book->{isbn} ? $book->{isbn} : next_id;

     # Store the ID for reference within the record
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile(get_local_path($id), $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     my $resource_url = absolute_url('/=/model/book/id/'.$id);
     print $q->header(
         -status   => 201,
         -type     => 'text/html',
         -location => $resource_url,
     );
     print $q->h1(quot;Created $book->{title}quot;);
     print $q->ul(
         $q->li(
             $q->a({ href => $resource_url }, $resource_url)
         )
     );
};
Create (part 2)
     # ...

     # Figure out an ID, this is either the ISBN or a generated ID
     my $id = $book->{isbn} ? $book->{isbn} : next_id;

     # Store the ID for reference within the record
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile(get_local_path($id), $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     my $resource_url = absolute_url('/=/model/book/id/'.$id);
     print $q->header(
         -status   => 201,
         -type     => 'text/html',
         -location => $resource_url,
     );
     print $q->h1(quot;Created $book->{title}quot;);
     print $q->ul(
         $q->li(
             $q->a({ href => $resource_url }, $resource_url)
         )
     );
};
Create (part 2)
     # ...

     # Figure out an ID, this is either the ISBN or a generated ID
     my $id = $book->{isbn} ? $book->{isbn} : next_id;

     # Store the ID for reference within the record
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile(get_local_path($id), $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     my $resource_url = absolute_url('/=/model/book/id/'.$id);
     print $q->header(
         -status   => 201,
         -type     => 'text/html',
         -location => $resource_url,
     );
     print $q->h1(quot;Created $book->{title}quot;);
     print $q->ul(
         $q->li(
             $q->a({ href => $resource_url }, $resource_url)
         )
     );
};
Create (part 2)
     # ...

     # Figure out an ID, this is either the ISBN or a generated ID
     my $id = $book->{isbn} ? $book->{isbn} : next_id;

     # Store the ID for reference within the record
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile(get_local_path($id), $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     my $resource_url = absolute_url('/=/model/book/id/'.$id);
     print $q->header(
         -status   => 201,
         -type     => 'text/html',
         -location => $resource_url,
     );
     print $q->h1(quot;Created $book->{title}quot;);
     print $q->ul(
         $q->li(
             $q->a({ href => $resource_url }, $resource_url)
         )
     );
};
Create (part 2)
     # ...

     # Figure out an ID, this is either the ISBN or a generated ID
     my $id = $book->{isbn} ? $book->{isbn} : next_id;

     # Store the ID for reference within the record
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile(get_local_path($id), $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     my $resource_url = absolute_url('/=/model/book/id/'.$id);
     print $q->header(
         -status   => 201,
         -type     => 'text/html',
         -location => $resource_url,
     );
     print $q->h1(quot;Created $book->{title}quot;);
     print $q->ul(
         $q->li(
             $q->a({ href => $resource_url }, $resource_url)
         )
     );
};
Update
# book update <id> <filename> - updates the book file <id> using
<filename>
subcommand 'update' => sub {
    my $id   = shift @ARGV;
    my $file = shift @ARGV;

     # Slurp up the given file name
     my $book_data = slurp $file;

     # PUT /=/model/book/id/[id]
     my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id,
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, just announce success
     if ($response->is_success) {
         print quot;Updated $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Update
# book update <id> <filename> - updates the book file <id> using
<filename>
subcommand 'update' => sub {
    my $id   = shift @ARGV;
    my $file = shift @ARGV;

     # Slurp up the given file name
     my $book_data = slurp $file;

     # PUT /=/model/book/id/[id]
     my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id,
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, just announce success
     if ($response->is_success) {
         print quot;Updated $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Update
# book update <id> <filename> - updates the book file <id> using
<filename>
subcommand 'update' => sub {
    my $id   = shift @ARGV;
    my $file = shift @ARGV;

     # Slurp up the given file name
     my $book_data = slurp $file;

     # PUT /=/model/book/id/[id]
     my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id,
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, just announce success
     if ($response->is_success) {
         print quot;Updated $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Update
# book update <id> <filename> - updates the book file <id> using
<filename>
subcommand 'update' => sub {
    my $id   = shift @ARGV;
    my $file = shift @ARGV;

     # Slurp up the given file name
     my $book_data = slurp $file;

     # PUT /=/model/book/id/[id]
     my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id,
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, just announce success
     if ($response->is_success) {
         print quot;Updated $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Update
# book update <id> <filename> - updates the book file <id> using
<filename>
subcommand 'update' => sub {
    my $id   = shift @ARGV;
    my $file = shift @ARGV;

     # Slurp up the given file name
     my $book_data = slurp $file;

     # PUT /=/model/book/id/[id]
     my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id,
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, just announce success
     if ($response->is_success) {
         print quot;Updated $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Update
# book update <id> <filename> - updates the book file <id> using
<filename>
subcommand 'update' => sub {
    my $id   = shift @ARGV;
    my $file = shift @ARGV;

     # Slurp up the given file name
     my $book_data = slurp $file;

     # PUT /=/model/book/id/[id]
     my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id,
         'Content-Type' => 'text/yaml',
         Content        => $book_data,
     );

     # On success, just announce success
     if ($response->is_success) {
         print quot;Updated $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Update
# Handle updates to books
PUT qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Check to make sure the input book is sane
     my $book = check_book( $q->param('PUTDATA') );

     # Make sure the book already exists or barf
     my $resource_path= get_local_path($id);
     unless(-f $resource_path) {
         barf 500, 'Not Gonna Do It',
             'Cannot use PUTs for creating a new resource.';
     }

     # Make sure the ID is set
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile($resource_path, $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     print $q->header('text/html');
     print $q->h1(quot;Updated $book->{title}quot;);
};
Update
# Handle updates to books
PUT qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Check to make sure the input book is sane
     my $book = check_book( $q->param('PUTDATA') );

     # Make sure the book already exists or barf
     my $resource_path= get_local_path($id);
     unless(-f $resource_path) {
         barf 500, 'Not Gonna Do It',
             'Cannot use PUTs for creating a new resource.';
     }

     # Make sure the ID is set
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile($resource_path, $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     print $q->header('text/html');
     print $q->h1(quot;Updated $book->{title}quot;);
};
Update
# Handle updates to books
PUT qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Check to make sure the input book is sane
     my $book = check_book( $q->param('PUTDATA') );

     # Make sure the book already exists or barf
     my $resource_path= get_local_path($id);
     unless(-f $resource_path) {
         barf 500, 'Not Gonna Do It',
             'Cannot use PUTs for creating a new resource.';
     }

     # Make sure the ID is set
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile($resource_path, $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     print $q->header('text/html');
     print $q->h1(quot;Updated $book->{title}quot;);
};
Update
# Handle updates to books
PUT qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Check to make sure the input book is sane
     my $book = check_book( $q->param('PUTDATA') );

     # Make sure the book already exists or barf
     my $resource_path= get_local_path($id);
     unless(-f $resource_path) {
         barf 500, 'Not Gonna Do It',
             'Cannot use PUTs for creating a new resource.';
     }

     # Make sure the ID is set
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile($resource_path, $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     print $q->header('text/html');
     print $q->h1(quot;Updated $book->{title}quot;);
};
Update
# Handle updates to books
PUT qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Check to make sure the input book is sane
     my $book = check_book( $q->param('PUTDATA') );

     # Make sure the book already exists or barf
     my $resource_path= get_local_path($id);
     unless(-f $resource_path) {
         barf 500, 'Not Gonna Do It',
             'Cannot use PUTs for creating a new resource.';
     }

     # Make sure the ID is set
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile($resource_path, $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     print $q->header('text/html');
     print $q->h1(quot;Updated $book->{title}quot;);
};
Update
# Handle updates to books
PUT qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Check to make sure the input book is sane
     my $book = check_book( $q->param('PUTDATA') );

     # Make sure the book already exists or barf
     my $resource_path= get_local_path($id);
     unless(-f $resource_path) {
         barf 500, 'Not Gonna Do It',
             'Cannot use PUTs for creating a new resource.';
     }

     # Make sure the ID is set
     $book->{id} = $id;

     # Save the resource
     eval { YAML::DumpFile($resource_path, $book) };
     barf 500, 'I Am Broke', $@ if $@;

     # Note the success to the end-user
     print $q->header('text/html');
     print $q->h1(quot;Updated $book->{title}quot;);
};
Delete

# book delete <id> - deletes the book resource with ID <id>
subcommand 'delete' => sub {
    my $id = shift @ARGV;

     # DELETE /=/model/book/id/[id]
     my $response = $ua->request(
         HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id)
     );

     # On success, announce it
     if ($response->is_success) {
         print quot;Deleted $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Delete

# book delete <id> - deletes the book resource with ID <id>
subcommand 'delete' => sub {
    my $id = shift @ARGV;

     # DELETE /=/model/book/id/[id]
     my $response = $ua->request(
         HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id)
     );

     # On success, announce it
     if ($response->is_success) {
         print quot;Deleted $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Delete

# book delete <id> - deletes the book resource with ID <id>
subcommand 'delete' => sub {
    my $id = shift @ARGV;

     # DELETE /=/model/book/id/[id]
     my $response = $ua->request(
         HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id)
     );

     # On success, announce it
     if ($response->is_success) {
         print quot;Deleted $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Delete

# book delete <id> - deletes the book resource with ID <id>
subcommand 'delete' => sub {
    my $id = shift @ARGV;

     # DELETE /=/model/book/id/[id]
     my $response = $ua->request(
         HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id)
     );

     # On success, announce it
     if ($response->is_success) {
         print quot;Deleted $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Delete

# book delete <id> - deletes the book resource with ID <id>
subcommand 'delete' => sub {
    my $id = shift @ARGV;

     # DELETE /=/model/book/id/[id]
     my $response = $ua->request(
         HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id)
     );

     # On success, announce it
     if ($response->is_success) {
         print quot;Deleted $idnquot;;
     }

     # On failure, barf
     else {
         barf $response;
     }
};
Delete

DELETE qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Make sure the book actually exists
     my $resource_path = get_local_path($id);
     unless (-f $resource_path) {
         barf 404, 'Where is What?',
             'Nothing here to delete.';
     }

     # Baleted!
     unlink $resource_path;

     # Tell me about it.
     print $q->header('text/html');
     print $q->h1(quot;Deleted $idquot;);
};
Delete

DELETE qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Make sure the book actually exists
     my $resource_path = get_local_path($id);
     unless (-f $resource_path) {
         barf 404, 'Where is What?',
             'Nothing here to delete.';
     }

     # Baleted!
     unlink $resource_path;

     # Tell me about it.
     print $q->header('text/html');
     print $q->h1(quot;Deleted $idquot;);
};
Delete

DELETE qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Make sure the book actually exists
     my $resource_path = get_local_path($id);
     unless (-f $resource_path) {
         barf 404, 'Where is What?',
             'Nothing here to delete.';
     }

     # Baleted!
     unlink $resource_path;

     # Tell me about it.
     print $q->header('text/html');
     print $q->h1(quot;Deleted $idquot;);
};
Delete

DELETE qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Make sure the book actually exists
     my $resource_path = get_local_path($id);
     unless (-f $resource_path) {
         barf 404, 'Where is What?',
             'Nothing here to delete.';
     }

     # Baleted!
     unlink $resource_path;

     # Tell me about it.
     print $q->header('text/html');
     print $q->h1(quot;Deleted $idquot;);
};
Delete

DELETE qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Make sure the book actually exists
     my $resource_path = get_local_path($id);
     unless (-f $resource_path) {
         barf 404, 'Where is What?',
             'Nothing here to delete.';
     }

     # Baleted!
     unlink $resource_path;

     # Tell me about it.
     print $q->header('text/html');
     print $q->h1(quot;Deleted $idquot;);
};
Delete

DELETE qr{^/=/model/book/id/([d-]+)$} => sub {
    my $id= $1;

     # Make sure the book actually exists
     my $resource_path = get_local_path($id);
     unless (-f $resource_path) {
         barf 404, 'Where is What?',
             'Nothing here to delete.';
     }

     # Baleted!
     unlink $resource_path;

     # Tell me about it.
     print $q->header('text/html');
     print $q->h1(quot;Deleted $idquot;);
};
Built-in Documentation
# Provide some nice documentation
GET qr{^/=$} => sub {
    print $q->header('text/html');

    print $q->h1('REST API Documentation');

    print $q->p('Here is a list of what you can do:');

    print $q->dl(
        $q->dt('GET /=/model/book/id'),
        $q->dd('Returns a list of available book IDs.'),

         $q->dt('GET /=/model/book/id/[ID]'),
         $q->dd('ID may be a number or the ISBN. Returns the book.'),

         $q->dt('POST /=/model/book'),
         $q->dd('Create a new book record. Returns the new URL to fetch with.'),

         $q->dt('PUT /=/model/book/id/[ID]'),
         $q->dd('Update a book by posting a complete book file.'),

         $q->dt('DELETE /=/model/book/id/[ID]'),
         $q->dd('Delete a book.'),
    );

    print $q->p('All book resources are stored or fetched in YAML format. The list of books will be
fetched in HTML with each LI in the returned listing containing a link to a book resource.');

    print $q->p('Here is a sample book. The quot;titlequot; field is the only required field for books. The
quot;isbnquot; field should be equal to the quot;idquot; field, if the quot;isbnquot; is present. The quot;idquot; field should be the
[ID] used to fetch, updated, or delete the record.');

    print $q->pre(q{isbn: 0-7852-1155-1
title: quot;The New Strong's Exhaustive Concordance of the Biblequot;
author: James Strong, LL.D., S.T.D.
publisher: Thomas Nelson Publishers
city: Nashville, Tennessee
year: 1995});
};
Exercises for the Audience

• Use whatever content types are most appropriate to your audience: XML,
  YAML, JSON, HTML, RSS/Atom, SQL, CSV, vFiles, PDF


• Don’t be afraid to offer multiple formats using the Accept: headers or even file
  name suffixes


• Use the full range of HTTP response codes to give clear responses


• Include additional X-blah: headers for metadata
Recommended Resources

• Sample Code:
  http://contentment.org/files/onlamp/library.cgi
  http://contentment.org/files/onlamp/book
• Original Articles:
  http://www.onlamp.com/pub/a/onlamp/2008/02/19/developing-restful-web-
  services-in-perl.html
  http://contentment.org/2008/08/developing-restful-web-service.html
• OpenResty - Nice REST middleware server by Agent Zhang:
  http://search.cpan.org/dist/OpenResty/
• Jifty - I ripped off the style of the REST interface of Jifty for this demo:
  http://search.cpan.org/dist/Jifty/
• HTTP Specification: http://www.w3.org/Protocols/rfc2616/rfc2616.html
• REST Wiki: http://rest.blueoxen.net/
Thank you!

Contenu connexe

Dernier

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 

Dernier (20)

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 

En vedette

Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 

En vedette (20)

Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 

Making Your Perl REST

  • 1. Making Your Perl REST Sterling Hanenkamp, PPW 2008
  • 3. What is REST? • Ever heard of...
  • 4. What is REST? • Ever heard of... • SOAP?
  • 5. What is REST? • Ever heard of... • SOAP? • RPC?
  • 6. What is REST? • Ever heard of... • SOAP? • RPC? • XML-RPC?
  • 7. What is REST? • Ever heard of... • SOAP? • RPC? • XML-RPC? • WebDAV?
  • 8. What is REST? • Ever heard of... • SOAP? • RPC? • XML-RPC? • WebDAV? • It’s kind of like that.
  • 9. What is REST? • Ever heard of... • Ever heard of... • SOAP? • RPC? • XML-RPC? • WebDAV? • It’s kind of like that.
  • 10. What is REST? • Ever heard of... • Ever heard of... • SOAP? • HTTP? • RPC? • XML-RPC? • WebDAV? • It’s kind of like that.
  • 11. What is REST? • Ever heard of... • Ever heard of... • SOAP? • HTTP? • RPC? • XML? • XML-RPC? • WebDAV? • It’s kind of like that.
  • 12. What is REST? • Ever heard of... • Ever heard of... • SOAP? • HTTP? • RPC? • XML? • XML-RPC? • YAML? • WebDAV? • It’s kind of like that.
  • 13. What is REST? • Ever heard of... • Ever heard of... • SOAP? • HTTP? • RPC? • XML? • XML-RPC? • YAML? • WebDAV? • JSON? • It’s kind of like that.
  • 14. What is REST? • Ever heard of... • Ever heard of... • SOAP? • HTTP? • RPC? • XML? • XML-RPC? • YAML? • WebDAV? • JSON? • It’s kind of like that. • It’s kind of like that too
  • 15. What are we NOT talking about?
  • 16. What are we NOT talking about? • REST is a general purpose term
  • 17. What are we NOT talking about? • REST is a general purpose term • I’m not talking about a general notion
  • 18. What are we NOT talking about? • REST is a general purpose term • I’m not talking about a general notion • We’re talking about REST APIs
  • 19. What are we NOT talking about? • REST is a general purpose term • I’m not talking about a general notion • We’re talking about REST APIs • Web Services
  • 20. What are we NOT talking about? • REST is a general purpose term • I’m not talking about a general notion • We’re talking about REST APIs • Web Services • Mashups!!!! Web 2.0!!! Yippee!!!
  • 21. What are we NOT talking about? • REST is a general purpose term • I’m not talking about a general notion • We’re talking about REST APIs • Web Services • Mashups!!!! Web 2.0!!! Yippee!!!
  • 22. What are we NOT talking about? • REST is a general purpose term • I’m not talking about a general notion • We’re talking about REST APIs • Web Services • Mashups!!!! Web 2.0!!! Yippee!!! • I’ve used my lifetime supply of exclamation points...
  • 24. The REST Triangle no un ht s tp :// ww w. on lam p.c om content types YAML, XML, JSON, etc. T E LE DE U T, b s ST, P er PO v , G ET
  • 25. The REST Triangle no • Nouns (=URL) un ht s tp :// ww w. on lam p.c om content types YAML, XML, JSON, etc. T E LE DE U T, b s ST, P er PO v , G ET
  • 26. The REST Triangle no • Nouns (=URL) un ht s tp :// ww • Verbs (=HTTP METHOD) w. on lam p.c om content types YAML, XML, JSON, etc. T E LE DE U T, b s ST, P er PO v , G ET
  • 27. The REST Triangle no • Nouns (=URL) un ht s tp :// ww • Verbs (=HTTP METHOD) w. on lam p.c om • Content (=MIME Type) content types YAML, XML, JSON, etc. T E LE DE U T, b s ST, P er PO v , G ET
  • 30. REST Web Services CRUD Create
  • 31. REST Web Services CRUD Create Read
  • 32. REST Web Services CRUD Create Read Update
  • 33. REST Web Services CRUD Create Read Update Delete
  • 34. REST Web Services • Treat your data like a static web page CRUD Create Read Update Delete
  • 35. REST Web Services • Treat your data like a static web page CRUD • Add data by POSTing a web page Create Read Update Delete
  • 36. REST Web Services • Treat your data like a static web page CRUD • Add data by POSTing a web page Create • Fetch data by GETting a web page Read Update Delete
  • 37. REST Web Services • Treat your data like a static web page CRUD • Add data by POSTing a web page Create • Fetch data by GETting a web page Read • Update data by PUTing a web page Update Delete
  • 38. REST Web Services • Treat your data like a static web page CRUD • Add data by POSTing a web page Create • Fetch data by GETting a web page Read • Update data by PUTing a web page Update • Delete data by DELETing a web page Delete
  • 39. REST Web Services • Treat your data like a static web page CRUD • Add data by POSTing a web page Create • Fetch data by GETting a web page Read • Update data by PUTing a web page Update • Delete data by DELETing a web page • E... it’s missing and it bugs me... Delete
  • 41. Who Uses It • Google • Socialtext • Yahoo! • Digg • Amazon • Twitter • Intuit • eBay • Best Practical • Technorati • Facebook • Too many others to mention...
  • 43. What about other stuff? • RPC is a square peg
  • 44. What about other stuff? • RPC is a square peg • REST is round hole
  • 45. What about other stuff? • RPC is a square peg • REST is round hole
  • 46. What about other stuff? • RPC is a square peg • REST is round hole • But it works!
  • 47. What about other stuff? • RPC is a square peg • REST is round hole • But it works! • Getting Info? GET
  • 48. What about other stuff? • RPC is a square peg • REST is round hole • But it works! • Getting Info? GET • Modifying Something? POST
  • 49. What about other stuff? • RPC is a square peg • REST is round hole • But it works! • Getting Info? GET • Modifying Something? POST • Both? Not sure? POST
  • 50. ENOUGH BASICS. LET’S DO SOMETHING.
  • 51. # Manage your books from the command-line. Woo-hoo! % ./book list
  • 52. # Manage your books from the command-line. Woo-hoo! % ./book list 0-8024-8160-4: .../library.cgi/=/model/book/id/0-8024-8160-4 0-85151-760-9: .../library.cgi/=/model/book/id/0-85151-760-9 0-936083-11-5: .../library.cgi/=/model/book/id/0-936083-11-5
  • 53. % ./book read 0-8024-8160-4
  • 54. % ./book read 0-8024-8160-4 --- author: David Clotfelter city: Chicago id: 0-8024-8160-4 isbn: 0-8024-8160-4 publisher: Moody Publishers title: > Sinners in the Hands of a Good God: Reconciling Divine Judgment and Mercy' year: 2004
  • 55.
  • 56. % ./book create reformation.yml
  • 57. % ./book create reformation.yml 0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5
  • 58. % ./book create reformation.yml 0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5 % ./book update 0-87552-183-5 reformation2.yml
  • 59. % ./book create reformation.yml 0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5 % ./book update 0-87552-183-5 reformation2.yml Updated 0-87552-183-5
  • 60. % ./book create reformation.yml 0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5 % ./book update 0-87552-183-5 reformation2.yml Updated 0-87552-183-5 % ./book delete 0-87552-183-5
  • 61. % ./book create reformation.yml 0-87552-183-5: .../library.cgi/=/model/book/id/0-87552-183-5 % ./book update 0-87552-183-5 reformation2.yml Updated 0-87552-183-5 % ./book delete 0-87552-183-5 Deleted 0-87552-183-5
  • 62. Okay... Putting it together But what did that do?
  • 63. Explaining the Nouns (a.k.a. URLs)
  • 64. Explaining the Nouns (a.k.a. URLs) Scheme Borrowed from Jifty
  • 65. Explaining the Nouns (a.k.a. URLs) Scheme Borrowed from Jifty What Example Why? Prefix /= Marker for REST Kind of Thing /=/model More Kinds Name of Thing /=/model/book More Models Field of Thing /=/model/book/id Multiple Identifiers Value of Field /=/mode/book/id/1 Multiple Things
  • 66. Explaining the Nouns (a.k.a. URLs) Scheme Borrowed from Jifty What Example Why? Prefix /= Marker for REST Kind of Thing /=/model More Kinds Name of Thing /=/model/book More Models Field of Thing /=/model/book/id Multiple Identifiers Value of Field /=/mode/book/id/1 Multiple Things
  • 67. Explaining the Nouns (a.k.a. URLs) Scheme Borrowed from Jifty What Example Why? Prefix /= Marker for REST Kind of Thing /=/model More Kinds Name of Thing /=/model/book More Models Field of Thing /=/model/book/id Multiple Identifiers Value of Field /=/mode/book/id/1 Multiple Things
  • 68. Explaining the Nouns (a.k.a. URLs) Scheme Borrowed from Jifty What Example Why? Prefix /= Marker for REST Kind of Thing /=/model More Kinds Name of Thing /=/model/book More Models Field of Thing /=/model/book/id Multiple Identifiers Value of Field /=/mode/book/id/1 Multiple Things
  • 69. Explaining the Nouns (a.k.a. URLs) Scheme Borrowed from Jifty What Example Why? Prefix /= Marker for REST Kind of Thing /=/model More Kinds Name of Thing /=/model/book More Models Field of Thing /=/model/book/id Multiple Identifiers Value of Field /=/mode/book/id/1 Multiple Things
  • 70. Explaining the Nouns (a.k.a. URLs) Scheme Borrowed from Jifty What Example Why? Prefix /= Marker for REST Kind of Thing /=/model More Kinds Name of Thing /=/model/book More Models Field of Thing /=/model/book/id Multiple Identifiers Value of Field /=/mode/book/id/1 Multiple Things
  • 71. Read (List) # book list - lists all the books the server returns subcommand 'list' => sub { # GET /=/model/book my $response = $ua->request(GET HOST.'/=/model/book/id'); # On success, find the link and print them out if ($response->is_success) { my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm; for my $url (@links) { my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } } # On failure, barf else { barf $response; } };
  • 72. Read (List) # book list - lists all the books the server returns subcommand 'list' => sub { # GET /=/model/book my $response = $ua->request(GET HOST.'/=/model/book/id'); # On success, find the link and print them out if ($response->is_success) { my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm; for my $url (@links) { my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } } # On failure, barf else { barf $response; } };
  • 73. Read (List) # book list - lists all the books the server returns subcommand 'list' => sub { # GET /=/model/book my $response = $ua->request(GET HOST.'/=/model/book/id'); # On success, find the link and print them out if ($response->is_success) { my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm; for my $url (@links) { my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } } # On failure, barf else { barf $response; } };
  • 74. Read (List) # book list - lists all the books the server returns subcommand 'list' => sub { # GET /=/model/book my $response = $ua->request(GET HOST.'/=/model/book/id'); # On success, find the link and print them out if ($response->is_success) { my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm; for my $url (@links) { my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } } # On failure, barf else { barf $response; } };
  • 75. Read (List) # book list - lists all the books the server returns subcommand 'list' => sub { # GET /=/model/book my $response = $ua->request(GET HOST.'/=/model/book/id'); # On success, find the link and print them out if ($response->is_success) { my @links = $response->content =~ /bhref=quot;([^quot;]+)quot;/gm; for my $url (@links) { my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } } # On failure, barf else { barf $response; } };
  • 76. Read (List) # Get a whole list of available documents GET qr{^/=/model/book/id$} => sub { print $q->header('text/html'); # Find all the files available my @items; for my $filename (glob get_local_path('*')) { my ($id) = $filename =~ m{([d-]+)$}; next unless defined $id; push @items, $q->li( $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id), ); } # List the items print $q->ul( @items); };
  • 77. Read (List) # Get a whole list of available documents GET qr{^/=/model/book/id$} => sub { print $q->header('text/html'); # Find all the files available my @items; for my $filename (glob get_local_path('*')) { my ($id) = $filename =~ m{([d-]+)$}; next unless defined $id; push @items, $q->li( $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id), ); } # List the items print $q->ul( @items); };
  • 78. Read (List) # Get a whole list of available documents GET qr{^/=/model/book/id$} => sub { print $q->header('text/html'); # Find all the files available my @items; for my $filename (glob get_local_path('*')) { my ($id) = $filename =~ m{([d-]+)$}; next unless defined $id; push @items, $q->li( $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id), ); } # List the items print $q->ul( @items); };
  • 79. Read (List) # Get a whole list of available documents GET qr{^/=/model/book/id$} => sub { print $q->header('text/html'); # Find all the files available my @items; for my $filename (glob get_local_path('*')) { my ($id) = $filename =~ m{([d-]+)$}; next unless defined $id; push @items, $q->li( $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id), ); } # List the items print $q->ul( @items); };
  • 80. Read (List) # Get a whole list of available documents GET qr{^/=/model/book/id$} => sub { print $q->header('text/html'); # Find all the files available my @items; for my $filename (glob get_local_path('*')) { my ($id) = $filename =~ m{([d-]+)$}; next unless defined $id; push @items, $q->li( $q->a({ href => absolute_url('/=/model/book/id/'.$id) }, $id), ); } # List the items print $q->ul( @items); };
  • 81. Read (Single) # book read <id> - reads the book file for <id> subcommand 'read' => sub { my $id = shift @ARGV; # GET /=/model/book/id/[id] my $response = $ua->request(GET HOST.'/=/model/book/id/' .$id); # On success, print the file if ($response->is_success) { print $response->content; } # On failure, barf else { barf $response; } };
  • 82. Read (Single) # book read <id> - reads the book file for <id> subcommand 'read' => sub { my $id = shift @ARGV; # GET /=/model/book/id/[id] my $response = $ua->request(GET HOST.'/=/model/book/id/' .$id); # On success, print the file if ($response->is_success) { print $response->content; } # On failure, barf else { barf $response; } };
  • 83. Read (Single) # book read <id> - reads the book file for <id> subcommand 'read' => sub { my $id = shift @ARGV; # GET /=/model/book/id/[id] my $response = $ua->request(GET HOST.'/=/model/book/id/' .$id); # On success, print the file if ($response->is_success) { print $response->content; } # On failure, barf else { barf $response; } };
  • 84. Read (Single) # book read <id> - reads the book file for <id> subcommand 'read' => sub { my $id = shift @ARGV; # GET /=/model/book/id/[id] my $response = $ua->request(GET HOST.'/=/model/book/id/' .$id); # On success, print the file if ($response->is_success) { print $response->content; } # On failure, barf else { barf $response; } };
  • 85. Read (Single) # book read <id> - reads the book file for <id> subcommand 'read' => sub { my $id = shift @ARGV; # GET /=/model/book/id/[id] my $response = $ua->request(GET HOST.'/=/model/book/id/' .$id); # On success, print the file if ($response->is_success) { print $response->content; } # On failure, barf else { barf $response; } };
  • 86. Read (Single) # Look up and read a resource GET qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Look up the resource file my $filename = get_local_path($id); if (-f $filename) { # Open and slurp up the file and output the resource open my $bookfh, $filename or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;; print $q->header('text/yaml'); print do { local $/; <$bookfh> }; } # No such resource exists else{ barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;; } };
  • 87. Read (Single) # Look up and read a resource GET qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Look up the resource file my $filename = get_local_path($id); if (-f $filename) { # Open and slurp up the file and output the resource open my $bookfh, $filename or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;; print $q->header('text/yaml'); print do { local $/; <$bookfh> }; } # No such resource exists else{ barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;; } };
  • 88. Read (Single) # Look up and read a resource GET qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Look up the resource file my $filename = get_local_path($id); if (-f $filename) { # Open and slurp up the file and output the resource open my $bookfh, $filename or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;; print $q->header('text/yaml'); print do { local $/; <$bookfh> }; } # No such resource exists else{ barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;; } };
  • 89. Read (Single) # Look up and read a resource GET qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Look up the resource file my $filename = get_local_path($id); if (-f $filename) { # Open and slurp up the file and output the resource open my $bookfh, $filename or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;; print $q->header('text/yaml'); print do { local $/; <$bookfh> }; } # No such resource exists else{ barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;; } };
  • 90. Read (Single) # Look up and read a resource GET qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Look up the resource file my $filename = get_local_path($id); if (-f $filename) { # Open and slurp up the file and output the resource open my $bookfh, $filename or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;; print $q->header('text/yaml'); print do { local $/; <$bookfh> }; } # No such resource exists else{ barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;; } };
  • 91. Read (Single) # Look up and read a resource GET qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Look up the resource file my $filename = get_local_path($id); if (-f $filename) { # Open and slurp up the file and output the resource open my $bookfh, $filename or barf 500, quot;I Am Brokequot;, quot;Cannot open $filename: $!quot;; print $q->header('text/yaml'); print do { local $/; <$bookfh> }; } # No such resource exists else{ barf 404, quot;Where is What?quot;, quot;Book for $id does not exist.quot;; } };
  • 92. Create # book create <filename> - submits the book file in <filename> to the server subcommand 'create' => sub { my $file = shift @ARGV; # Slurp up the contents of the given filename my $book_data = slurp $file; # POST /=/model/book my $response = $ua->request(POST HOST.'/=/model/book', 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, return the new ID assigned to the resource if ($response->is_success) { my $url = $response->header('Location'); my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } # On failure, barf else { barf $response; } };
  • 93. Create # book create <filename> - submits the book file in <filename> to the server subcommand 'create' => sub { my $file = shift @ARGV; # Slurp up the contents of the given filename my $book_data = slurp $file; # POST /=/model/book my $response = $ua->request(POST HOST.'/=/model/book', 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, return the new ID assigned to the resource if ($response->is_success) { my $url = $response->header('Location'); my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } # On failure, barf else { barf $response; } };
  • 94. Create # book create <filename> - submits the book file in <filename> to the server subcommand 'create' => sub { my $file = shift @ARGV; # Slurp up the contents of the given filename my $book_data = slurp $file; # POST /=/model/book my $response = $ua->request(POST HOST.'/=/model/book', 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, return the new ID assigned to the resource if ($response->is_success) { my $url = $response->header('Location'); my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } # On failure, barf else { barf $response; } };
  • 95. Create # book create <filename> - submits the book file in <filename> to the server subcommand 'create' => sub { my $file = shift @ARGV; # Slurp up the contents of the given filename my $book_data = slurp $file; # POST /=/model/book my $response = $ua->request(POST HOST.'/=/model/book', 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, return the new ID assigned to the resource if ($response->is_success) { my $url = $response->header('Location'); my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } # On failure, barf else { barf $response; } };
  • 96. Create # book create <filename> - submits the book file in <filename> to the server subcommand 'create' => sub { my $file = shift @ARGV; # Slurp up the contents of the given filename my $book_data = slurp $file; # POST /=/model/book my $response = $ua->request(POST HOST.'/=/model/book', 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, return the new ID assigned to the resource if ($response->is_success) { my $url = $response->header('Location'); my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } # On failure, barf else { barf $response; } };
  • 97. Create # book create <filename> - submits the book file in <filename> to the server subcommand 'create' => sub { my $file = shift @ARGV; # Slurp up the contents of the given filename my $book_data = slurp $file; # POST /=/model/book my $response = $ua->request(POST HOST.'/=/model/book', 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, return the new ID assigned to the resource if ($response->is_success) { my $url = $response->header('Location'); my ($id) = $url =~ /([d-]+)$/; print quot;$id: $urlnquot;; } # On failure, barf else { barf $response; } };
  • 98. Create (part 1) # Handle the creation of new books POST qr{^/=/model/book$} => sub { # Check to make sure the input book is sane my $book= check_book( $q->param('POSTDATA') ); # If we have an ISBN (some books don't!), then die if we already have # it because we don't permit POST cannot for updates! if ($book->{isbn} and -f get_local_path($book->{isbn})) { barf 500, 'Not Gonna Do It', 'A POST may not be used to update an existing book.'; } # Our data is sane! # ...
  • 99. Create (part 1) # Handle the creation of new books POST qr{^/=/model/book$} => sub { # Check to make sure the input book is sane my $book= check_book( $q->param('POSTDATA') ); # If we have an ISBN (some books don't!), then die if we already have # it because we don't permit POST cannot for updates! if ($book->{isbn} and -f get_local_path($book->{isbn})) { barf 500, 'Not Gonna Do It', 'A POST may not be used to update an existing book.'; } # Our data is sane! # ...
  • 100. Create (part 1) # Handle the creation of new books POST qr{^/=/model/book$} => sub { # Check to make sure the input book is sane my $book= check_book( $q->param('POSTDATA') ); # If we have an ISBN (some books don't!), then die if we already have # it because we don't permit POST cannot for updates! if ($book->{isbn} and -f get_local_path($book->{isbn})) { barf 500, 'Not Gonna Do It', 'A POST may not be used to update an existing book.'; } # Our data is sane! # ...
  • 101. Create (part 1) # Handle the creation of new books POST qr{^/=/model/book$} => sub { # Check to make sure the input book is sane my $book= check_book( $q->param('POSTDATA') ); # If we have an ISBN (some books don't!), then die if we already have # it because we don't permit POST cannot for updates! if ($book->{isbn} and -f get_local_path($book->{isbn})) { barf 500, 'Not Gonna Do It', 'A POST may not be used to update an existing book.'; } # Our data is sane! # ...
  • 102. Create (part 1) # Handle the creation of new books POST qr{^/=/model/book$} => sub { # Check to make sure the input book is sane my $book= check_book( $q->param('POSTDATA') ); # If we have an ISBN (some books don't!), then die if we already have # it because we don't permit POST cannot for updates! if ($book->{isbn} and -f get_local_path($book->{isbn})) { barf 500, 'Not Gonna Do It', 'A POST may not be used to update an existing book.'; } # Our data is sane! # ...
  • 103. Create (part 1) # Handle the creation of new books POST qr{^/=/model/book$} => sub { # Check to make sure the input book is sane my $book= check_book( $q->param('POSTDATA') ); # If we have an ISBN (some books don't!), then die if we already have # it because we don't permit POST cannot for updates! if ($book->{isbn} and -f get_local_path($book->{isbn})) { barf 500, 'Not Gonna Do It', 'A POST may not be used to update an existing book.'; } # Our data is sane! # ...
  • 104. Create (part 2) # ... # Figure out an ID, this is either the ISBN or a generated ID my $id = $book->{isbn} ? $book->{isbn} : next_id; # Store the ID for reference within the record $book->{id} = $id; # Save the resource eval { YAML::DumpFile(get_local_path($id), $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user my $resource_url = absolute_url('/=/model/book/id/'.$id); print $q->header( -status => 201, -type => 'text/html', -location => $resource_url, ); print $q->h1(quot;Created $book->{title}quot;); print $q->ul( $q->li( $q->a({ href => $resource_url }, $resource_url) ) ); };
  • 105. Create (part 2) # ... # Figure out an ID, this is either the ISBN or a generated ID my $id = $book->{isbn} ? $book->{isbn} : next_id; # Store the ID for reference within the record $book->{id} = $id; # Save the resource eval { YAML::DumpFile(get_local_path($id), $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user my $resource_url = absolute_url('/=/model/book/id/'.$id); print $q->header( -status => 201, -type => 'text/html', -location => $resource_url, ); print $q->h1(quot;Created $book->{title}quot;); print $q->ul( $q->li( $q->a({ href => $resource_url }, $resource_url) ) ); };
  • 106. Create (part 2) # ... # Figure out an ID, this is either the ISBN or a generated ID my $id = $book->{isbn} ? $book->{isbn} : next_id; # Store the ID for reference within the record $book->{id} = $id; # Save the resource eval { YAML::DumpFile(get_local_path($id), $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user my $resource_url = absolute_url('/=/model/book/id/'.$id); print $q->header( -status => 201, -type => 'text/html', -location => $resource_url, ); print $q->h1(quot;Created $book->{title}quot;); print $q->ul( $q->li( $q->a({ href => $resource_url }, $resource_url) ) ); };
  • 107. Create (part 2) # ... # Figure out an ID, this is either the ISBN or a generated ID my $id = $book->{isbn} ? $book->{isbn} : next_id; # Store the ID for reference within the record $book->{id} = $id; # Save the resource eval { YAML::DumpFile(get_local_path($id), $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user my $resource_url = absolute_url('/=/model/book/id/'.$id); print $q->header( -status => 201, -type => 'text/html', -location => $resource_url, ); print $q->h1(quot;Created $book->{title}quot;); print $q->ul( $q->li( $q->a({ href => $resource_url }, $resource_url) ) ); };
  • 108. Create (part 2) # ... # Figure out an ID, this is either the ISBN or a generated ID my $id = $book->{isbn} ? $book->{isbn} : next_id; # Store the ID for reference within the record $book->{id} = $id; # Save the resource eval { YAML::DumpFile(get_local_path($id), $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user my $resource_url = absolute_url('/=/model/book/id/'.$id); print $q->header( -status => 201, -type => 'text/html', -location => $resource_url, ); print $q->h1(quot;Created $book->{title}quot;); print $q->ul( $q->li( $q->a({ href => $resource_url }, $resource_url) ) ); };
  • 109. Update # book update <id> <filename> - updates the book file <id> using <filename> subcommand 'update' => sub { my $id = shift @ARGV; my $file = shift @ARGV; # Slurp up the given file name my $book_data = slurp $file; # PUT /=/model/book/id/[id] my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id, 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, just announce success if ($response->is_success) { print quot;Updated $idnquot;; } # On failure, barf else { barf $response; } };
  • 110. Update # book update <id> <filename> - updates the book file <id> using <filename> subcommand 'update' => sub { my $id = shift @ARGV; my $file = shift @ARGV; # Slurp up the given file name my $book_data = slurp $file; # PUT /=/model/book/id/[id] my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id, 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, just announce success if ($response->is_success) { print quot;Updated $idnquot;; } # On failure, barf else { barf $response; } };
  • 111. Update # book update <id> <filename> - updates the book file <id> using <filename> subcommand 'update' => sub { my $id = shift @ARGV; my $file = shift @ARGV; # Slurp up the given file name my $book_data = slurp $file; # PUT /=/model/book/id/[id] my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id, 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, just announce success if ($response->is_success) { print quot;Updated $idnquot;; } # On failure, barf else { barf $response; } };
  • 112. Update # book update <id> <filename> - updates the book file <id> using <filename> subcommand 'update' => sub { my $id = shift @ARGV; my $file = shift @ARGV; # Slurp up the given file name my $book_data = slurp $file; # PUT /=/model/book/id/[id] my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id, 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, just announce success if ($response->is_success) { print quot;Updated $idnquot;; } # On failure, barf else { barf $response; } };
  • 113. Update # book update <id> <filename> - updates the book file <id> using <filename> subcommand 'update' => sub { my $id = shift @ARGV; my $file = shift @ARGV; # Slurp up the given file name my $book_data = slurp $file; # PUT /=/model/book/id/[id] my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id, 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, just announce success if ($response->is_success) { print quot;Updated $idnquot;; } # On failure, barf else { barf $response; } };
  • 114. Update # book update <id> <filename> - updates the book file <id> using <filename> subcommand 'update' => sub { my $id = shift @ARGV; my $file = shift @ARGV; # Slurp up the given file name my $book_data = slurp $file; # PUT /=/model/book/id/[id] my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id, 'Content-Type' => 'text/yaml', Content => $book_data, ); # On success, just announce success if ($response->is_success) { print quot;Updated $idnquot;; } # On failure, barf else { barf $response; } };
  • 115. Update # Handle updates to books PUT qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Check to make sure the input book is sane my $book = check_book( $q->param('PUTDATA') ); # Make sure the book already exists or barf my $resource_path= get_local_path($id); unless(-f $resource_path) { barf 500, 'Not Gonna Do It', 'Cannot use PUTs for creating a new resource.'; } # Make sure the ID is set $book->{id} = $id; # Save the resource eval { YAML::DumpFile($resource_path, $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user print $q->header('text/html'); print $q->h1(quot;Updated $book->{title}quot;); };
  • 116. Update # Handle updates to books PUT qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Check to make sure the input book is sane my $book = check_book( $q->param('PUTDATA') ); # Make sure the book already exists or barf my $resource_path= get_local_path($id); unless(-f $resource_path) { barf 500, 'Not Gonna Do It', 'Cannot use PUTs for creating a new resource.'; } # Make sure the ID is set $book->{id} = $id; # Save the resource eval { YAML::DumpFile($resource_path, $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user print $q->header('text/html'); print $q->h1(quot;Updated $book->{title}quot;); };
  • 117. Update # Handle updates to books PUT qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Check to make sure the input book is sane my $book = check_book( $q->param('PUTDATA') ); # Make sure the book already exists or barf my $resource_path= get_local_path($id); unless(-f $resource_path) { barf 500, 'Not Gonna Do It', 'Cannot use PUTs for creating a new resource.'; } # Make sure the ID is set $book->{id} = $id; # Save the resource eval { YAML::DumpFile($resource_path, $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user print $q->header('text/html'); print $q->h1(quot;Updated $book->{title}quot;); };
  • 118. Update # Handle updates to books PUT qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Check to make sure the input book is sane my $book = check_book( $q->param('PUTDATA') ); # Make sure the book already exists or barf my $resource_path= get_local_path($id); unless(-f $resource_path) { barf 500, 'Not Gonna Do It', 'Cannot use PUTs for creating a new resource.'; } # Make sure the ID is set $book->{id} = $id; # Save the resource eval { YAML::DumpFile($resource_path, $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user print $q->header('text/html'); print $q->h1(quot;Updated $book->{title}quot;); };
  • 119. Update # Handle updates to books PUT qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Check to make sure the input book is sane my $book = check_book( $q->param('PUTDATA') ); # Make sure the book already exists or barf my $resource_path= get_local_path($id); unless(-f $resource_path) { barf 500, 'Not Gonna Do It', 'Cannot use PUTs for creating a new resource.'; } # Make sure the ID is set $book->{id} = $id; # Save the resource eval { YAML::DumpFile($resource_path, $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user print $q->header('text/html'); print $q->h1(quot;Updated $book->{title}quot;); };
  • 120. Update # Handle updates to books PUT qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Check to make sure the input book is sane my $book = check_book( $q->param('PUTDATA') ); # Make sure the book already exists or barf my $resource_path= get_local_path($id); unless(-f $resource_path) { barf 500, 'Not Gonna Do It', 'Cannot use PUTs for creating a new resource.'; } # Make sure the ID is set $book->{id} = $id; # Save the resource eval { YAML::DumpFile($resource_path, $book) }; barf 500, 'I Am Broke', $@ if $@; # Note the success to the end-user print $q->header('text/html'); print $q->h1(quot;Updated $book->{title}quot;); };
  • 121. Delete # book delete <id> - deletes the book resource with ID <id> subcommand 'delete' => sub { my $id = shift @ARGV; # DELETE /=/model/book/id/[id] my $response = $ua->request( HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id) ); # On success, announce it if ($response->is_success) { print quot;Deleted $idnquot;; } # On failure, barf else { barf $response; } };
  • 122. Delete # book delete <id> - deletes the book resource with ID <id> subcommand 'delete' => sub { my $id = shift @ARGV; # DELETE /=/model/book/id/[id] my $response = $ua->request( HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id) ); # On success, announce it if ($response->is_success) { print quot;Deleted $idnquot;; } # On failure, barf else { barf $response; } };
  • 123. Delete # book delete <id> - deletes the book resource with ID <id> subcommand 'delete' => sub { my $id = shift @ARGV; # DELETE /=/model/book/id/[id] my $response = $ua->request( HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id) ); # On success, announce it if ($response->is_success) { print quot;Deleted $idnquot;; } # On failure, barf else { barf $response; } };
  • 124. Delete # book delete <id> - deletes the book resource with ID <id> subcommand 'delete' => sub { my $id = shift @ARGV; # DELETE /=/model/book/id/[id] my $response = $ua->request( HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id) ); # On success, announce it if ($response->is_success) { print quot;Deleted $idnquot;; } # On failure, barf else { barf $response; } };
  • 125. Delete # book delete <id> - deletes the book resource with ID <id> subcommand 'delete' => sub { my $id = shift @ARGV; # DELETE /=/model/book/id/[id] my $response = $ua->request( HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id) ); # On success, announce it if ($response->is_success) { print quot;Deleted $idnquot;; } # On failure, barf else { barf $response; } };
  • 126. Delete DELETE qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Make sure the book actually exists my $resource_path = get_local_path($id); unless (-f $resource_path) { barf 404, 'Where is What?', 'Nothing here to delete.'; } # Baleted! unlink $resource_path; # Tell me about it. print $q->header('text/html'); print $q->h1(quot;Deleted $idquot;); };
  • 127. Delete DELETE qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Make sure the book actually exists my $resource_path = get_local_path($id); unless (-f $resource_path) { barf 404, 'Where is What?', 'Nothing here to delete.'; } # Baleted! unlink $resource_path; # Tell me about it. print $q->header('text/html'); print $q->h1(quot;Deleted $idquot;); };
  • 128. Delete DELETE qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Make sure the book actually exists my $resource_path = get_local_path($id); unless (-f $resource_path) { barf 404, 'Where is What?', 'Nothing here to delete.'; } # Baleted! unlink $resource_path; # Tell me about it. print $q->header('text/html'); print $q->h1(quot;Deleted $idquot;); };
  • 129. Delete DELETE qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Make sure the book actually exists my $resource_path = get_local_path($id); unless (-f $resource_path) { barf 404, 'Where is What?', 'Nothing here to delete.'; } # Baleted! unlink $resource_path; # Tell me about it. print $q->header('text/html'); print $q->h1(quot;Deleted $idquot;); };
  • 130. Delete DELETE qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Make sure the book actually exists my $resource_path = get_local_path($id); unless (-f $resource_path) { barf 404, 'Where is What?', 'Nothing here to delete.'; } # Baleted! unlink $resource_path; # Tell me about it. print $q->header('text/html'); print $q->h1(quot;Deleted $idquot;); };
  • 131. Delete DELETE qr{^/=/model/book/id/([d-]+)$} => sub { my $id= $1; # Make sure the book actually exists my $resource_path = get_local_path($id); unless (-f $resource_path) { barf 404, 'Where is What?', 'Nothing here to delete.'; } # Baleted! unlink $resource_path; # Tell me about it. print $q->header('text/html'); print $q->h1(quot;Deleted $idquot;); };
  • 132. Built-in Documentation # Provide some nice documentation GET qr{^/=$} => sub { print $q->header('text/html'); print $q->h1('REST API Documentation'); print $q->p('Here is a list of what you can do:'); print $q->dl( $q->dt('GET /=/model/book/id'), $q->dd('Returns a list of available book IDs.'), $q->dt('GET /=/model/book/id/[ID]'), $q->dd('ID may be a number or the ISBN. Returns the book.'), $q->dt('POST /=/model/book'), $q->dd('Create a new book record. Returns the new URL to fetch with.'), $q->dt('PUT /=/model/book/id/[ID]'), $q->dd('Update a book by posting a complete book file.'), $q->dt('DELETE /=/model/book/id/[ID]'), $q->dd('Delete a book.'), ); print $q->p('All book resources are stored or fetched in YAML format. The list of books will be fetched in HTML with each LI in the returned listing containing a link to a book resource.'); print $q->p('Here is a sample book. The quot;titlequot; field is the only required field for books. The quot;isbnquot; field should be equal to the quot;idquot; field, if the quot;isbnquot; is present. The quot;idquot; field should be the [ID] used to fetch, updated, or delete the record.'); print $q->pre(q{isbn: 0-7852-1155-1 title: quot;The New Strong's Exhaustive Concordance of the Biblequot; author: James Strong, LL.D., S.T.D. publisher: Thomas Nelson Publishers city: Nashville, Tennessee year: 1995}); };
  • 133. Exercises for the Audience • Use whatever content types are most appropriate to your audience: XML, YAML, JSON, HTML, RSS/Atom, SQL, CSV, vFiles, PDF • Don’t be afraid to offer multiple formats using the Accept: headers or even file name suffixes • Use the full range of HTTP response codes to give clear responses • Include additional X-blah: headers for metadata
  • 134. Recommended Resources • Sample Code: http://contentment.org/files/onlamp/library.cgi http://contentment.org/files/onlamp/book • Original Articles: http://www.onlamp.com/pub/a/onlamp/2008/02/19/developing-restful-web- services-in-perl.html http://contentment.org/2008/08/developing-restful-web-service.html • OpenResty - Nice REST middleware server by Agent Zhang: http://search.cpan.org/dist/OpenResty/ • Jifty - I ripped off the style of the REST interface of Jifty for this demo: http://search.cpan.org/dist/Jifty/ • HTTP Specification: http://www.w3.org/Protocols/rfc2616/rfc2616.html • REST Wiki: http://rest.blueoxen.net/
  • 135.