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

Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 

Último (20)

Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 

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.