summaryrefslogtreecommitdiff
path: root/posts/2010-03-19-easily-create-rest-interface-with-the-dancer-1.170.org
blob: a1e56a56a94bf2869b25b2a16deda0ac3b71f678 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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]].