<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/introducing-reqres/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.data-imaginist.com/2017/Introducing-reqres/"> Data Imaginist - R posts</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><img align="right" src="https://i1.wp.com/www.data-imaginist.com/assets/images/reqres_logo_small.png?w=456" data-recalc-dims="1"></p>
<p>I’m very happy to announce that <code>reqres</code> has been released on CRAN. <code>reqres</code> is<br>
a new (in R context) approach to working with HTTP messages, that is, the<br>
<strong>req</strong>uests you send to a server and the <strong>res</strong>pons it returns. The<br>
uunderlying mechanics of a web server is seldom something that R users comes<br>
into contact with, indeed the most popular way of using R code for the web is<br>
<a rel="nofollow" href="http://shiny.rstudio.com/" target="_blank"><code>Shiny</code></a> by RStudio and<br>
<a rel="nofollow" href="https://www.opencpu.org/" target="_blank"><code>OpenCPU</code></a> by Jeroen Ooms, both of which abstracts the<br>
actual HTTP messaging away in order to provide a more friendly and R-native<br>
interface to building web apps and services.</p>
<p><em>So why bother with HTTP in R at all?</em><br>
Both of the above frameworks favors <em>ease-of-use</em> over control, and sometimes<br>
you just want control. Maybe you don’t need the overhead that comes with<br>
full-fledged web app frameworks, maybe the high abstraction level makes it<br>
difficult to achieve what you want, or maybe you’re the developer of Shiny or<br>
OpenCPU and wants to declutter your codebase <img alt="😉" src="https://s.w.org/images/core/emoji/2/72x72/1f609.png" class="wp-smiley">. I’m of course<br>
here to tell you to take a look at <a rel="nofollow" href="http://github.com/thomasp85/fiery" target="_blank"><code>fiery</code></a><br>
(which I’m developing) if you can give a nod to the two former reasons. I’m not<br>
going to spend more time on how and why to build a web server (that will happen<br>
in another series of blog posts), but simply state that there are very valid<br>
reasons for working directly with HTTP messaging in R and that <code>reqres</code> is here<br>
to soothe the pain of it, should you ever be in that position.</p>
<h2>An overview of <em>reqres</em></h2>
<p>There are two main objects in <code>reqres</code> that the developer should know about. The<br>
<code>Request</code> class and the <code>Response</code> class. Both of these are build on<br>
<a rel="nofollow" href="https://github.com/r-lib/R6" target="_blank"><code>R6</code></a> and heavily inspired by the request and<br>
response classes in <a rel="nofollow" href="http://expressjs.com/" target="_blank">Express.js</a> (a web server framework<br>
for <a rel="nofollow" href="https://nodejs.org/en/" target="_blank">Node.js</a>) to the point of seeming very familiar if<br>
you’ve ever worked with Express.</p>
<h3>The <em>Request</em> class</h3>
<p>When a HTTP request is recieved on the server the most likely way it ends up in<br>
R is through the <a rel="nofollow" href="https://github.com/rstudio/httpuv" target="_blank"><code>httpuv</code></a> package, a<br>
minimal web server build upon libuv (which were developed for Node – we’re<br>
beginning to owe the JavaScript crowd a beer). <code>httpuv</code> passes the request on as<br>
a Rook compliant environment (<a rel="nofollow" href="https://github.com/jeffreyhorner/Rook" target="_blank">Rook</a><br>
being an earlier web server specification developed by Jeffrey Horner) and this<br>
is the point where <code>reqres</code> can intercept it and make your life easier.</p>
<p>In order to showcase the <code>Request</code> class we need a HTTP request. Thankfully<br>
<code>fiery</code> provides a function for mocking Rook requests, so we can play around<br>
with <code>reqres</code> without building up a true server.</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>reqres</span><span>)</span><span>
</span><span>rook</span><span> </span><span>&lt;-</span><span> </span><span>fiery</span><span>::</span><span>fake_request</span><span>(</span><span>
</span><span>'http://www.data-imaginist.com/reqres/demo?user=Thomas+Lin+Pedersen&amp;id=123'</span><span>,</span><span>
</span><span>method</span><span> </span><span>=</span><span> </span><span>'get'</span><span>,</span><span>
</span><span>content</span><span> </span><span>=</span><span> </span><span>'{&quot;numbers&quot;:[1,2,3],&quot;letters&quot;:[&quot;a&quot;,&quot;b&quot;, &quot;c&quot;]}'</span><span>,</span><span>
</span><span>headers</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>
</span><span>Content_Type</span><span> </span><span>=</span><span> </span><span>'application/json'</span><span>,</span><span>
</span><span>Accept</span><span> </span><span>=</span><span> </span><span>'application/json, application/xml, text/*'</span><span>,</span><span>
</span><span>Accept_Encoding</span><span> </span><span>=</span><span> </span><span>'gzip'</span><span>,</span><span>
</span><span>Cookie</span><span> </span><span>=</span><span> </span><span>'session=321'</span><span>
</span><span>)</span><span>
</span><span>)</span><span>
</span><span>request</span><span> </span><span>&lt;-</span><span> </span><span>Request</span><span>$</span><span>new</span><span>(</span><span>rook</span><span>)</span><span>
</span><span>request</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## A HTTP request
## ==============
## Trusted: No
##  Method: get
##     URL: http://www.data-imaginist.com:80/reqres/demo?user=Thomas+Lin+Pedersen&amp;id=123</code></pre>
</figure>
<p>We now have a supercharged <code>Request</code> object. Being an <code>R6</code> class it uses<br>
reference semantics and there will thus only exist one version of this request<br>
no matter how many times we reassign it to a new variable. We can ask the<br>
request all sorts on things about itself, such as the method, full url, path<br>
(the part of the url following the host address), the query (the optional part<br>
of the url following the <code>?</code>).</p>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>method</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;get&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>url</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;http://www.data-imaginist.com:80/reqres/demo?user=Thomas+Lin+Pedersen&amp;id=123&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>path</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;/reqres/demo&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>query</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## $user
## [1] &quot;Thomas Lin Pedersen&quot;
## 
## $id
## [1] 123</code></pre>
</figure>
<p>As can be seen the query gets parsed automatically into a list. The same is true<br>
for cookies. One surprise might come when we try to look at the body.</p>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>body</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## NULL</code></pre>
</figure>
<p>The body is only parsed on request. The reason for this is that the request body<br>
can be in all sorts of formats, some not even understandable by R. The format of<br>
the body is advertised in the <code>Content-Type</code> header (here <code>application/json</code>)<br>
and we can ask the request whether it is of a certain format.</p>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>is</span><span>(</span><span>'html'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] FALSE</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>is</span><span>(</span><span>'json'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] TRUE</code></pre>
</figure>
<p>This can be used to determine the correct approach to reading the body. An<br>
easier way is through the <code>parser()</code> method that takes multiple different<br>
parsing functions and chooses the correct (if present) and fills in the body.<br>
<code>reqres</code> already comes with a list of parsers for the standard formats so often<br>
this is a very easy task.</p>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>parse</span><span>(</span><span>default_parsers</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] TRUE</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>body</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## $numbers
## [1] 1 2 3
## 
## $letters
## [1] &quot;a&quot; &quot;b&quot; &quot;c&quot;</code></pre>
</figure>
<p>The method returns <code>TRUE</code> if successful and <code>FALSE</code> otherwise. One little magic<br>
feature is that the body is automatically decompressed if compressed (e.g.<br>
gzipped).</p>
<p>Arbitrary headers can be extracted with the <code>get_header()</code> method.</p>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>get_header</span><span>(</span><span>'Accept-Encoding'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;gzip&quot;</code></pre>
</figure>
<p>The last major feature of the <code>Request</code> class is content negotiation. It is<br>
expected that the client informs the server what format, encoding, etc it<br>
understands and prefers and the server then choses the best one it can do (this<br>
is communicated through the <code>Accept(-*)</code> headers). The <code>Request</code> class has a<br>
range of methods that helps you chose the correct format of the response body.</p>
<figure>
<pre><code data-lang="r"><span>request</span><span>$</span><span>accepts</span><span>(</span><span>c</span><span>(</span><span>'html'</span><span>,</span><span> </span><span>'text/plain'</span><span>))</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;html&quot;</code></pre>
</figure>
<p>While the content negotiation seems relatively simple in our little contrived<br>
example, it can easily end up being hairy as each format can be weighted by a<br>
priority score and wildcards should be prioritized less. The <code>accepts()</code> method<br>
takes care of all of this for you and simply returns the prefered choice out of<br>
the given.</p>
<h3>The <em>Response</em> class</h3>
<p>While the <code>Request</code> class is mainly meant for parsing and reading the intend of<br>
the client, <code>Response</code> class is meant for manipulation, ultimately resulting in<br>
an answer to the <code>Request</code>. A response is always linked to a request and cannot<br>
exist in solitude. While it can be created using the standard <code>R6</code><br>
<code>Response$new()</code> ideom, it is recommended to create one from the request<br>
instead.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span> </span><span>&lt;-</span><span> </span><span>request</span><span>$</span><span>respond</span><span>()</span><span>
</span><span>response</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## A HTTP response
## ===============
##         Status: 404 - Not Found
##   Content type: text/plain
## 
## In response to: http://www.data-imaginist.com:80/reqres/demo?user=Thomas+Lin+Pedersen&amp;id=123</code></pre>
</figure>
<p>The reason why this is recommended is that the <code>respond()</code> method will always<br>
return a response, either creating one or returning the one already exisiting.<br>
<code>Response$new()</code> will throw an error if a response has already been created for<br>
the request.</p>
<figure>
<pre><code data-lang="r"><span>try</span><span>(</span><span>Response</span><span>$</span><span>new</span><span>(</span><span>request</span><span>))</span><span>
</span><span>identical</span><span>(</span><span>response</span><span>,</span><span> </span><span>request</span><span>$</span><span>respond</span><span>())</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] TRUE</code></pre>
</figure>
<p>Responses are initialised to <code>404- Not Found</code> with an empty body but it is often<br>
desirable to change this (unless, of course, the requested ressource is not<br>
found). Status codes can be manipulated with the <code>status</code> field or the<br>
<code>status_with_text()</code> method which will also update the body to contain the name<br>
of the status code, e.g.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>status_with_text</span><span>(</span><span>416</span><span>)</span><span>
</span><span>response</span><span>$</span><span>body</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;Range Not Satisfiable&quot;</code></pre>
</figure>
<p>Headers can be set with the <code>set_header()</code> and <code>append_header()</code> method and<br>
retrieved with <code>get_header()</code>.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>set_header</span><span>(</span><span>'Server'</span><span>,</span><span> </span><span>'fiery-0.2.3'</span><span>)</span><span>
</span><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Server'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;fiery-0.2.3&quot;</code></pre>
</figure>
<p>The <code>set_header()</code> method is the lowest common denominator when it comes to<br>
adding headers to your response. In addition there are a range of helpers for<br>
specific common headers.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>timestamp</span><span>()</span><span>
</span><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Date'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;Thu, 10 Aug 2017 09:15:20 GMT&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>type</span><span> </span><span>&lt;-</span><span> </span><span>'json'</span><span>
</span><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Content-Type'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;application/json&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>set_links</span><span>(</span><span>alternative</span><span> </span><span>=</span><span> </span><span>'/feed'</span><span>)</span><span>
</span><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Link'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;; rel=\&quot;alternative\&quot;&quot;</code></pre>
</figure>
<p>Furtermore, there’s a special method for setting cookies. While cookies are set<br>
with the <code>Set-Cookie</code> header, they live in a separate container until the<br>
response is ready to be send in order to facilitate lookup by cookie name.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>set_cookie</span><span>(</span><span>'session'</span><span>,</span><span> </span><span>uuid</span><span>::</span><span>UUIDgenerate</span><span>(),</span><span> </span><span>max_age</span><span> </span><span>=</span><span> </span><span>9000</span><span>,</span><span> </span><span>secure</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Set-Cookie'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## NULL</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>has_cookie</span><span>(</span><span>'session'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] TRUE</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>as_list</span><span>()</span><span>$</span><span>headers</span><span>[[</span><span>'Set-Cookie'</span><span>]]</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;session=776396a3-556e-4bef-88a5-228965ecfb3c; Max-Age=9000; Secure&quot;</code></pre>
</figure>
<p>Apart from the headers, the each response also contains their own data store<br>
that can contain any data. This facilitate communication between different<br>
middleware (code that modify the HTTP messages on the server). The data store is<br>
used pretty much like the headers.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>set_data</span><span>(</span><span>'alphabet'</span><span>,</span><span> </span><span>letters</span><span>)</span><span>
</span><span>response</span><span>$</span><span>has_data</span><span>(</span><span>'alphabet'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] TRUE</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>get_data</span><span>(</span><span>'alphabet'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">##  [1] &quot;a&quot; &quot;b&quot; &quot;c&quot; &quot;d&quot; &quot;e&quot; &quot;f&quot; &quot;g&quot; &quot;h&quot; &quot;i&quot; &quot;j&quot; &quot;k&quot; &quot;l&quot; &quot;m&quot; &quot;n&quot; &quot;o&quot; &quot;p&quot; &quot;q&quot;
## [18] &quot;r&quot; &quot;s&quot; &quot;t&quot; &quot;u&quot; &quot;v&quot; &quot;w&quot; &quot;x&quot; &quot;y&quot; &quot;z&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>remove_data</span><span>(</span><span>'alphabet'</span><span>)</span></code></pre>
</figure>
<p>The data contained in the data store will never become part of the actual<br>
response so anything can be added here safely.</p>
<p>Often the server responds with a file, e.g. a HTML file defining the web page<br>
the client requested. Files are easily added with the <code>file</code> field, which will<br>
take care of setting the <code>Content-Type</code> and <code>Last-Modified</code> headers as well as<br>
checking that the file actually exists.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>file</span><span> </span><span>&lt;-</span><span> </span><span>system.file</span><span>(</span><span>'NEWS.md'</span><span>,</span><span> </span><span>package</span><span> </span><span>=</span><span> </span><span>'reqres'</span><span>)</span><span>
</span><span>response</span><span>$</span><span>type</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;text/markdown&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Last-Modified'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;Thu, 10 Aug 2017 08:33:54 GMT&quot;</code></pre>
</figure>
<p>If the file is meant for download rather than display the <code>attach()</code> method will<br>
set the correct headers to indicate to the browser that it should initiate a<br>
download.</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>attach</span><span>(</span><span>system.file</span><span>(</span><span>'help'</span><span>,</span><span> </span><span>'figures'</span><span>,</span><span> </span><span>'reqres_logo.png'</span><span>,</span><span> </span><span>package</span><span> </span><span>=</span><span> </span><span>'reqres'</span><span>))</span><span>
</span><span>response</span><span>$</span><span>type</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;image/png&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Content-Disposition'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;attachment; filename=reqres_logo.png&quot;</code></pre>
</figure>
<p>Lastly, the response body is accessible in the <code>body</code> field. It can be<br>
absolutely anything you wish as until the response is send of, but should be<br>
formatted to either a raw vector or a string prior to handing the response of to<br>
e.g. <code>httpuv</code>. Thankfully there’s a parallel to <code>Request$parse()</code> in the form of<br>
<code>Response$format</code> that performs content negotiation based on the supplied<br>
formatters, chooses the prefered one and applies it, finally applying<br>
compression if the client permits it. To make life easier the standard<br>
formatters have been collected in <code>default_formatters</code> so this step is<br>
easy-peasy (headers will of course be set for you).</p>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>body</span><span> </span><span>&lt;-</span><span> </span><span>mtcars</span><span>
</span><span>head</span><span>(</span><span>response</span><span>$</span><span>body</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>format</span><span>(</span><span>default_formatters</span><span>,</span><span> </span><span>compress</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] TRUE</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>body</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [{&quot;mpg&quot;:21,&quot;cyl&quot;:6,&quot;disp&quot;:160,&quot;hp&quot;:110,&quot;drat&quot;:3.9,&quot;wt&quot;:2.62,&quot;qsec&quot;:16.46,&quot;vs&quot;:0,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Mazda RX4&quot;},{&quot;mpg&quot;:21,&quot;cyl&quot;:6,&quot;disp&quot;:160,&quot;hp&quot;:110,&quot;drat&quot;:3.9,&quot;wt&quot;:2.875,&quot;qsec&quot;:17.02,&quot;vs&quot;:0,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Mazda RX4 Wag&quot;},{&quot;mpg&quot;:22.8,&quot;cyl&quot;:4,&quot;disp&quot;:108,&quot;hp&quot;:93,&quot;drat&quot;:3.85,&quot;wt&quot;:2.32,&quot;qsec&quot;:18.61,&quot;vs&quot;:1,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:1,&quot;_row&quot;:&quot;Datsun 710&quot;},{&quot;mpg&quot;:21.4,&quot;cyl&quot;:6,&quot;disp&quot;:258,&quot;hp&quot;:110,&quot;drat&quot;:3.08,&quot;wt&quot;:3.215,&quot;qsec&quot;:19.44,&quot;vs&quot;:1,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:1,&quot;_row&quot;:&quot;Hornet 4 Drive&quot;},{&quot;mpg&quot;:18.7,&quot;cyl&quot;:8,&quot;disp&quot;:360,&quot;hp&quot;:175,&quot;drat&quot;:3.15,&quot;wt&quot;:3.44,&quot;qsec&quot;:17.02,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Hornet Sportabout&quot;},{&quot;mpg&quot;:18.1,&quot;cyl&quot;:6,&quot;disp&quot;:225,&quot;hp&quot;:105,&quot;drat&quot;:2.76,&quot;wt&quot;:3.46,&quot;qsec&quot;:20.22,&quot;vs&quot;:1,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:1,&quot;_row&quot;:&quot;Valiant&quot;},{&quot;mpg&quot;:14.3,&quot;cyl&quot;:8,&quot;disp&quot;:360,&quot;hp&quot;:245,&quot;drat&quot;:3.21,&quot;wt&quot;:3.57,&quot;qsec&quot;:15.84,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Duster 360&quot;},{&quot;mpg&quot;:24.4,&quot;cyl&quot;:4,&quot;disp&quot;:146.7,&quot;hp&quot;:62,&quot;drat&quot;:3.69,&quot;wt&quot;:3.19,&quot;qsec&quot;:20,&quot;vs&quot;:1,&quot;am&quot;:0,&quot;gear&quot;:4,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Merc 240D&quot;},{&quot;mpg&quot;:22.8,&quot;cyl&quot;:4,&quot;disp&quot;:140.8,&quot;hp&quot;:95,&quot;drat&quot;:3.92,&quot;wt&quot;:3.15,&quot;qsec&quot;:22.9,&quot;vs&quot;:1,&quot;am&quot;:0,&quot;gear&quot;:4,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Merc 230&quot;},{&quot;mpg&quot;:19.2,&quot;cyl&quot;:6,&quot;disp&quot;:167.6,&quot;hp&quot;:123,&quot;drat&quot;:3.92,&quot;wt&quot;:3.44,&quot;qsec&quot;:18.3,&quot;vs&quot;:1,&quot;am&quot;:0,&quot;gear&quot;:4,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Merc 280&quot;},{&quot;mpg&quot;:17.8,&quot;cyl&quot;:6,&quot;disp&quot;:167.6,&quot;hp&quot;:123,&quot;drat&quot;:3.92,&quot;wt&quot;:3.44,&quot;qsec&quot;:18.9,&quot;vs&quot;:1,&quot;am&quot;:0,&quot;gear&quot;:4,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Merc 280C&quot;},{&quot;mpg&quot;:16.4,&quot;cyl&quot;:8,&quot;disp&quot;:275.8,&quot;hp&quot;:180,&quot;drat&quot;:3.07,&quot;wt&quot;:4.07,&quot;qsec&quot;:17.4,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:3,&quot;_row&quot;:&quot;Merc 450SE&quot;},{&quot;mpg&quot;:17.3,&quot;cyl&quot;:8,&quot;disp&quot;:275.8,&quot;hp&quot;:180,&quot;drat&quot;:3.07,&quot;wt&quot;:3.73,&quot;qsec&quot;:17.6,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:3,&quot;_row&quot;:&quot;Merc 450SL&quot;},{&quot;mpg&quot;:15.2,&quot;cyl&quot;:8,&quot;disp&quot;:275.8,&quot;hp&quot;:180,&quot;drat&quot;:3.07,&quot;wt&quot;:3.78,&quot;qsec&quot;:18,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:3,&quot;_row&quot;:&quot;Merc 450SLC&quot;},{&quot;mpg&quot;:10.4,&quot;cyl&quot;:8,&quot;disp&quot;:472,&quot;hp&quot;:205,&quot;drat&quot;:2.93,&quot;wt&quot;:5.25,&quot;qsec&quot;:17.98,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Cadillac Fleetwood&quot;},{&quot;mpg&quot;:10.4,&quot;cyl&quot;:8,&quot;disp&quot;:460,&quot;hp&quot;:215,&quot;drat&quot;:3,&quot;wt&quot;:5.424,&quot;qsec&quot;:17.82,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Lincoln Continental&quot;},{&quot;mpg&quot;:14.7,&quot;cyl&quot;:8,&quot;disp&quot;:440,&quot;hp&quot;:230,&quot;drat&quot;:3.23,&quot;wt&quot;:5.345,&quot;qsec&quot;:17.42,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Chrysler Imperial&quot;},{&quot;mpg&quot;:32.4,&quot;cyl&quot;:4,&quot;disp&quot;:78.7,&quot;hp&quot;:66,&quot;drat&quot;:4.08,&quot;wt&quot;:2.2,&quot;qsec&quot;:19.47,&quot;vs&quot;:1,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:1,&quot;_row&quot;:&quot;Fiat 128&quot;},{&quot;mpg&quot;:30.4,&quot;cyl&quot;:4,&quot;disp&quot;:75.7,&quot;hp&quot;:52,&quot;drat&quot;:4.93,&quot;wt&quot;:1.615,&quot;qsec&quot;:18.52,&quot;vs&quot;:1,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Honda Civic&quot;},{&quot;mpg&quot;:33.9,&quot;cyl&quot;:4,&quot;disp&quot;:71.1,&quot;hp&quot;:65,&quot;drat&quot;:4.22,&quot;wt&quot;:1.835,&quot;qsec&quot;:19.9,&quot;vs&quot;:1,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:1,&quot;_row&quot;:&quot;Toyota Corolla&quot;},{&quot;mpg&quot;:21.5,&quot;cyl&quot;:4,&quot;disp&quot;:120.1,&quot;hp&quot;:97,&quot;drat&quot;:3.7,&quot;wt&quot;:2.465,&quot;qsec&quot;:20.01,&quot;vs&quot;:1,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:1,&quot;_row&quot;:&quot;Toyota Corona&quot;},{&quot;mpg&quot;:15.5,&quot;cyl&quot;:8,&quot;disp&quot;:318,&quot;hp&quot;:150,&quot;drat&quot;:2.76,&quot;wt&quot;:3.52,&quot;qsec&quot;:16.87,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Dodge Challenger&quot;},{&quot;mpg&quot;:15.2,&quot;cyl&quot;:8,&quot;disp&quot;:304,&quot;hp&quot;:150,&quot;drat&quot;:3.15,&quot;wt&quot;:3.435,&quot;qsec&quot;:17.3,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:2,&quot;_row&quot;:&quot;AMC Javelin&quot;},{&quot;mpg&quot;:13.3,&quot;cyl&quot;:8,&quot;disp&quot;:350,&quot;hp&quot;:245,&quot;drat&quot;:3.73,&quot;wt&quot;:3.84,&quot;qsec&quot;:15.41,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Camaro Z28&quot;},{&quot;mpg&quot;:19.2,&quot;cyl&quot;:8,&quot;disp&quot;:400,&quot;hp&quot;:175,&quot;drat&quot;:3.08,&quot;wt&quot;:3.845,&quot;qsec&quot;:17.05,&quot;vs&quot;:0,&quot;am&quot;:0,&quot;gear&quot;:3,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Pontiac Firebird&quot;},{&quot;mpg&quot;:27.3,&quot;cyl&quot;:4,&quot;disp&quot;:79,&quot;hp&quot;:66,&quot;drat&quot;:4.08,&quot;wt&quot;:1.935,&quot;qsec&quot;:18.9,&quot;vs&quot;:1,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:1,&quot;_row&quot;:&quot;Fiat X1-9&quot;},{&quot;mpg&quot;:26,&quot;cyl&quot;:4,&quot;disp&quot;:120.3,&quot;hp&quot;:91,&quot;drat&quot;:4.43,&quot;wt&quot;:2.14,&quot;qsec&quot;:16.7,&quot;vs&quot;:0,&quot;am&quot;:1,&quot;gear&quot;:5,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Porsche 914-2&quot;},{&quot;mpg&quot;:30.4,&quot;cyl&quot;:4,&quot;disp&quot;:95.1,&quot;hp&quot;:113,&quot;drat&quot;:3.77,&quot;wt&quot;:1.513,&quot;qsec&quot;:16.9,&quot;vs&quot;:1,&quot;am&quot;:1,&quot;gear&quot;:5,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Lotus Europa&quot;},{&quot;mpg&quot;:15.8,&quot;cyl&quot;:8,&quot;disp&quot;:351,&quot;hp&quot;:264,&quot;drat&quot;:4.22,&quot;wt&quot;:3.17,&quot;qsec&quot;:14.5,&quot;vs&quot;:0,&quot;am&quot;:1,&quot;gear&quot;:5,&quot;carb&quot;:4,&quot;_row&quot;:&quot;Ford Pantera L&quot;},{&quot;mpg&quot;:19.7,&quot;cyl&quot;:6,&quot;disp&quot;:145,&quot;hp&quot;:175,&quot;drat&quot;:3.62,&quot;wt&quot;:2.77,&quot;qsec&quot;:15.5,&quot;vs&quot;:0,&quot;am&quot;:1,&quot;gear&quot;:5,&quot;carb&quot;:6,&quot;_row&quot;:&quot;Ferrari Dino&quot;},{&quot;mpg&quot;:15,&quot;cyl&quot;:8,&quot;disp&quot;:301,&quot;hp&quot;:335,&quot;drat&quot;:3.54,&quot;wt&quot;:3.57,&quot;qsec&quot;:14.6,&quot;vs&quot;:0,&quot;am&quot;:1,&quot;gear&quot;:5,&quot;carb&quot;:8,&quot;_row&quot;:&quot;Maserati Bora&quot;},{&quot;mpg&quot;:21.4,&quot;cyl&quot;:4,&quot;disp&quot;:121,&quot;hp&quot;:109,&quot;drat&quot;:4.11,&quot;wt&quot;:2.78,&quot;qsec&quot;:18.6,&quot;vs&quot;:1,&quot;am&quot;:1,&quot;gear&quot;:4,&quot;carb&quot;:2,&quot;_row&quot;:&quot;Volvo 142E&quot;}]</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>compress</span><span>()</span><span>
</span><span>head</span><span>(</span><span>response</span><span>$</span><span>body</span><span>,</span><span> </span><span>30</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">##  [1] 1f 8b 08 00 00 00 00 00 00 03 9d 97 dd 6e e3 36 10 85 5f 85 d0 b5 57
## [24] 10 c9 a1 48 f9 ae 6b</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>type</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;application/json&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>response</span><span>$</span><span>get_header</span><span>(</span><span>'Content-Encoding'</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] &quot;gzip&quot;</code></pre>
</figure>
<h2>Wrapping up</h2>
<p>As I hope I’ve made clear, working directly with HTTP messages does not need to<br>
be a drag. Sure, there’s a sea of conventions around headers and status codes<br>
that can seem daunting, but <code>reqres</code> takes care of the minimum requirements for<br>
you, letting you focus on the server logic instead.</p>
<h3>Whats next</h3>
<p>I obviously hope <code>reqres</code> will become pervasive in the world of R web<br>
technologies as I think it will make everyones life easier. <code>fiery</code> already uses<br>
it in the development version on GitHub, as does <code>routr</code> so if you’re going to<br>
use either of these packages you’ll automatically become aquainted. Furthermore<br>
I’ve heard expression of interest from other developers so hopefully it will be<br>
adopted beyond my own packages.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://www.data-imaginist.com/2017/Introducing-reqres/"> Data Imaginist - R posts</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/Eo1uhmi6AV4" height="1"></a></div>