PageRenderTime 51ms CodeModel.GetById 2ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 0ms

/2012/articles/2012-12-13.pod

http://github.com/rjbs/Perl-Advent
Unknown | 170 lines | 126 code | 44 blank | 0 comment | 0 complexity | 04ac7867979efed106584e89facc091d MD5 | raw file
  1Title: Take a little REST
  2Topic: adenosine
  3Author: Arthur Axel "fREW" Schmidt <frew@cpan.org>
  4
  5About six months ago I learned about L<resty|https://github.com/micha/resty>.
  6I think Stevan Little may have mentioned it in his L<Web::Machine> talk.
  7Unfortunately C<resty> had problems running in C<zsh>.  I initially tried to
  8fix the problem, but then I ported it to Perl instead, which was not only
  9easier but also ended up having a lot of other exciting benfits.
 10
 11=head1 L<What even is that thing?|https://www.youtube.com/watch?v=H4w0_n1Yras&t=3m29s>
 12
 13Adenosine is a tool that allows you to fiddle with
 14L<RESTful|https://en.wikipedia.org/wiki/Representational_state_transfer>
 15services easily.  The basic gist is that you can use C<HTTP> verbs (C<POST>,
 16C<PUT>, C<HEAD>, C<GET>, C<OPTIONS>, C<TRACE>) directly in your shell.
 17You get the body of the response as stdout, headers and more as stderr if
 18you turn on C<-v>, the exit code is directly related to the error code,
 19and there's a minimal plugin architecture (with more hooks on their way.)
 20
 21=head1 How do I use it?
 22
 23The first thing you need to do with adenosine is to set up your environment to
 24use it:
 25
 26  $ eval $(adenosine exports)
 27
 28The next thing you need to do is set the base URI.  The base URI is just a
 29URI with a C<*> in it.  So for example, why don't we start with the
 30DuckDuckGo API.  A simple, useful base URI could be set as follows:
 31
 32 $ adenosine 'http://api.duckduckgo.com/?q=*&o=json'
 33
 34So with that set all you need to do is:
 35
 36 $ GET test | pp
 37
 38The above will put C<test> into the base URI in place of the C<*>.  L<pp>
 39is just a tiny json pretty printer bundled with adenosine.
 40
 41If you don't specify a URI scheme (C<http://> or C<https://>), your URI will
 42be prepended with C<http://>, and if you don't specify a C<*> it will be
 43appended to your URI.
 44
 45C<GET> isn't all you can do, though it's certainly what I<I> do most often.
 46Here's an example of how I might send a text message with our API at work:
 47
 48  #!code
 49  $ adenosine 'http://our.api.com/api/2/*/sms'
 50  $ POST myaccount '{"message":"Hello Frew!","destinations":[8675309]}' \
 51    -H 'Content-Type: application/json' -H 'Accept: application/json'
 52
 53If you want to edit the data you are about to post, use adenosine's C<-V>
 54switch to open your C<$EDITOR>.
 55
 56There's more in the L<documentation|adenosine>, but that's basically how
 57it works.
 58
 59=head1 Too much to type!
 60
 61Sometimes you'll want to set certain headers for a given host.  For example, in
 62my previous example I need to set the C<Content-Type> and C<Accept> headers so
 63that my application will do the right thing.  I actually B<always> want to set
 64those headers when interacting with my application.  The way to do this nicely
 65is to create a configuration file for my server.  For example, I could create
 66the following:
 67
 68F<~/.resty/our.api.com>:
 69
 70  #!code
 71  POST -H 'Content-Type: application/json' -H 'Accept: application/json'
 72  PUT -H 'Content-Type: application/json' -H 'Accept: application/json'
 73  DELETE -H 'Content-Type: application/json' -H 'Accept: application/json'
 74  GET -H 'Content-Type: application/json' -H 'Accept: application/json'
 75
 76That will set those two headers for all four of the major HTTP verbs, so the
 77previous example could now be merely:
 78
 79  $ POST myaccount '{"message":"Hello Frew!","destinations":[8675309]}'
 80
 81=head1 Plugins
 82
 83One of the most exciting new features of adenosine (vs. resty) is that it
 84supports plugins.  I initially just wrote two:  Stopwatch and Rainbow.
 85
 86=head2 C<Stopwatch>
 87
 88C<Stopwatch> adds timing info to the output from C<-v>.  I like to know
 89how long various commands and requests take, especially when I am the
 90implementor of said command.  If something takes longer than 0.5s, I did a
 91bad job.  So C<Stopwatch> gives me exactly what information I need to know.
 92To enable it put the following in F<~/.adenosinerc.yml>:
 93
 94  #!vim yaml
 95  plugins:
 96     - ::Stopwatch
 97
 98=head2 C<Rainbow>
 99
100C<Rainbow> color codes the output from C<-v>.  I really like this, but
101obviously it's not for everyone.  At the most basic, you can enable it the
102same way that you enable C<Stopwatch>, but that just gives you the most
103basic color coding.  C<Rainbow> is implemented to be easily themable as well
104as overridable.  If you just wanted to override the color of the method from
105the request, put the following in F<~/.adenosinerc.yml>:
106
107  #!vim yaml
108  plugins:
109     - ::Rainbow: {
110           request_method_color: cyan
111       }
112
113That's fine for experimentation, but I'd like to encourage everyone to make
114their own themes and submit them as pull requests.  To make a theme, all you
115need to do is create a file as follows:
116
117  #!perl
118  package App::Adenosine::Plugin::Rainbow::Halloween;
119
120  use Moo;
121  extends 'App::Adenosine::Plugin::Rainbow';
122  has '+response_header_colon_color' => (default => sub { '' });
123  has '+response_header_name_color'  => (default => sub { 'orange1' });
124  has '+response_header_value_color' => (default => sub { 'orange2' });
125  # ...
126
127C<Rainbow> uses L<Term::ExtendedColor>, so to see what colors are available
128run the C<color_matrix> script that comes with it.  Also note that while in the
129example above only a single color is specified, the foreground, backround, and
130even a few other (spottily supported) attributes may be set:
131
132  #!perl
133  has '+response_header_value_color' => (
134    default => sub {
135       {
136          fg        => 'orange2',
137          bg        => 'cyan', # what a bad choice
138          bold      => 1,
139          italic    => 1,
140          underline => 1,
141       }
142    }
143  );
144
145Once you've done that, your F<~/.adenosinerc.yml> can reference your theme
146directly:
147
148  #!vim yaml
149  plugins:
150     - ::Rainbow::Halloween
151     - ::Stopwatch
152
153and that's adenosine!  Please play with it and let me know if you like it!
154
155=head1 Installing C<adenosine> without CPAN
156
157Most readers of this article are likely to be comfortable installing adenosine
158from the CPAN, but if you don't want to use CPAN, or you somehow got to this
159post as a non-L<japh|http://en.wikipedia.org/wiki/Just_another_Perl_hacker>,
160this might be more your speed:
161
162 git clone http://github.com/frioux/app-adenosine-prefab
163 source app-adenosine-prefab/adenosine-exports
164
165=head1 See Also
166
167=for :list
168* L<adenosine>
169* L<resty|https://github.com/micha/resty>
170