SlideShare una empresa de Scribd logo
1 de 136
Descargar para leer sin conexión
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!

Más contenido relacionado

Último

Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontologyjohnbeverley2021
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 

Último (20)

Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 

Destacado

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
 

Destacado (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.