summaryrefslogblamecommitdiff
path: root/posts/2010-03-19-easily-create-rest-interface-with-the-dancer-1.170.org
blob: a1e56a56a94bf2869b25b2a16deda0ac3b71f678 (plain) (tree)








































































































































































                                                                                                                 
This week, with [[http://www.sukria.net/fr/][Alexi]]'s help,
[[http://github.com/perldancer/Dancer][I've been working on]] to add
auto-(de)serialization to Dancer's request. This features will be
available in the next [[http://perldancer.org/][Dancer]] version, the
1.170 (which will be out before April).

The basic idea was to provides to developer a simple way to access data
that have been send in a serialized format, and to properly serialize
the response.

At the moment, the supported serializers are :

-  Dancer::Serialize::JSON
-  Dancer::Serialize::YAML
-  Dancer::Serialize::XML
-  Dancer::Serialize::Mutable

** Configuring an application to use the serializer

To activate serialization in your application:

#+BEGIN_SRC perl
    set serializer => 'JSON';
#+END_SRC

or in your configuration file:

#+BEGIN_EXAMPLE
    serializer: "JSON"
#+END_EXAMPLE

** A simple handler

Let's create a new dancer application (you can fetch the source on
[[http://git.lumberjaph.net/p5-dancer-rest.git/][my git server]] :

#+BEGIN_EXAMPLE
    % dancer -a dancerREST
    % cd dancerREST
    % vim dancerREST.pm
#+END_EXAMPLE

then

#+BEGIN_SRC perl
    package dancerREST;
    use Dancer ':syntax';

    my %users = ();

    post '/api/user/' => sub {
        my $params = request->params;
        if ($params->{name} && $params->{id}) {
            if (exists $users{$params->{id}}) {
                return {error => "user already exists"};
            }
            $users{$params->{id}} = {name => $params->{name}};
            return {id => $params->{id}, name => $params->{name}};
        }
        else {
            return {error => "name is missing"};
        }
    };

    true;
#+END_SRC

We can test if everything works as expected:

#+BEGIN_EXAMPLE
    % plackup app.psgi &
    % curl -H "Content-Type: application/json" -X POST http://localhost:5000/api/user/ -d '{"name":"foo","id":1}'
    # => {"name":"foo","id":"1"}
#+END_EXAMPLE

Now we add a method to fetch a list of users, and a method to get a
specific user:

#+BEGIN_SRC perl
    # return a specific user
    get '/api/user/:id' => sub {
        my $params = request->params;
        if (exists $users{$params->{id}}) {
            return $users{$params->{id}};
        }
        else {
            return {error => "unknown user"};
        }
    };

    # return a list of users
    get '/api/user/' => sub {
        my @users;
        push @users, {name => $users{$_}->{name}, id => $_}
            foreach keys %users;
        return \@users;
    };
#+END_SRC

If we want to fetch the full list:

#+BEGIN_SRC sh
    curl -H "Content-Type: application/json" http://localhost:5000/api/user/
    # => [{"name":"foo","id":"1"}]
#+END_SRC

and a specific user:

#+BEGIN_SRC sh
    curl -H "Content-Type: application/json" http://localhost:5000/api/user/1
    # => {"name":"foo"}
#+END_SRC

** The mutable serializer

The mutable serializer will try to load an appropriate serializer
guessing from the *Content-Type* and *Accept-Type* header. You can also
overload this by adding a *content\_type=application/json* parameter to
your request.

While setting your serializer to mutable, your let your user decide
which format they prefer between YAML, JSON and XML.

** And the bonus

Dancer provides now a new method to the request object : =is_ajax=. Now
you can write something like

#+BEGIN_SRC perl
    get '/user/:id' => sub {
        my $params = request->params;
        my $user   = $users{$params->{id}};
        my $result;
        if (!$user) {
            _render_user({error => "unknown user"});
        }
        else {
            _render_user($user);
        }
    };

    sub _render_user {
        my $result = shift;
        if (request->is_ajax) {
            return $result;
        }
        else {
            template 'user.tt', $result;
        }
    }
#+END_SRC

If we want to simulate an AJAX query:

#+BEGIN_EXAMPLE
    % curl -H "X-Requested-With: XMLHttpRequest" http://localhost:5000/user/1
#+END_EXAMPLE

and we will obtain our result in JSON. But we can also test without the
X-Requested-With:

#+BEGIN_EXAMPLE
    % curl http://localhost:5000/user/1
#+END_EXAMPLE

and the template will be rendered.

Hope you like this new features. I've also been working on something
similar for [[http://github.com/miyagawa/tatsumaki][Tatsumaki]].