<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="http://www.r-bloggers.com/a-simple-prediction-web-service-using-the-new-fiery-package/"></div></div><div><a data-url="http://www.r-bloggers.com/a-simple-prediction-web-service-using-the-new-fiery-package/" data-counturl="http://www.r-bloggers.com/a-simple-prediction-web-service-using-the-new-fiery-package/" data-count="horizontal" data-text="A Simple Prediction Web Service Using the New fiery Package" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://rud.is/b/2016/07/05/a-simple-prediction-web-service-using-the-new-firery-package/"> R – rud.is</a></strong>, and kindly contributed to <a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><a target="_blank" href="https://github.com/thomasp85/fiery"><code>fiery</code></a> is a new <code>Rook</code>/<code>httuv</code>-based R web server in town created by <a target="_blank" href="http://twitter.com/thomasp85">@thomasp85</a> that aims to fill the gap between raw http &amp; websockets and Shiny with a flexible framework for handling requests and serving up responses. </p>
<p>The intent of this post is to provide a quick-start to using it setup a prediction API service.</p>
<p>We’ll be using the <em>super complex model</em> described in the first example of the <code>predict.lm</code> manual page and save the fitted model out so we can load it up in the web server and use it for predicting values from inputs.</p>
<pre><code>set.seed(1492)
x &lt;- rnorm(15)
y &lt;- x + rnorm(15)
fit &lt;- lm(y ~ x)
saveRDS(fit, &quot;model.rds&quot;)</code></pre>
<p>The code is annotated, but the gist is to:</p>
<ul>
<li>Fire up the server (NOTE: it puts itself on <code>0.0.0.0</code> <em>by default</em> so <em>CHANGE THIS</em> until you’re ready for production)</li>
<li>Load the saved model</li>
<li>Setup the routing for the requests</li>
<li>Send back the model as JSON (since it’s an API vs something meant for humans)</li>
</ul>
<p>Here’s the code (jump past it for more info):</p>
<pre><code>suppressPackageStartupMessages(library(fiery))
suppressPackageStartupMessages(library(utils))
suppressPackageStartupMessages(library(jsonlite))
suppressPackageStartupMessages(library(shiny))

app &lt;- Fire$new()

# This is absolutely necessary unless you're deliberately trying
# to expose the service to the entire network you are on which
# you probably don't want to do until in test / stage / prod

app$host &lt;- &quot;127.0.0.1&quot;
app$port &lt;- 9123 # completely arbitrary selection, make it whatevs

model &lt;- NULL

# When the app starts, we'll load the model we saved. This
# particular one is just the first example on ?predict.lm.
# This doesn't have to be global, per se, but this makes
# for a quick example of how to setup an model API server

app$on(&quot;start&quot;, function(server, ...) {
  message(sprintf(&quot;Running on %s:%s&quot;, app$host, app$port))
  model &lt;&lt;- readRDS(&quot;model.rds&quot;)
  message(&quot;Model loaded&quot;)
})

# when the request comes in, route it properly. this will
# be *much* nicer with Thomas' `routr` plugin, but you can
# get up and running now this way until it's fully documented
# and on CRAN.
#
# 3 routes:
#
# if &quot;/&quot; then return an empty HTML page
# if &quot;/info&quot; give some data about the server (just for example purposes)
# if &quot;/predict?val=##&quot; run the value through the model
#
# No error checking or anything as this is (again) a simple
# example

app$on('request', function(server, id, request, ...) {

  response &lt;- list(
    status = 200L,
    headers = list('Content-Type'='text/html'),
    body = &quot;&quot;
  )

  # this helps us see what the path is
  path &lt;- get(&quot;PATH_INFO&quot;, envir=request)
  if (path == &quot;/info&quot;) {

    # Build a list of all the request headers so we can 
    # regurgitate them

    out &lt;- sapply(grep(&quot;^[A-Z_0-9]+&quot;, names(request), value=TRUE), function(x) {
      sprintf(&quot;%s: %s&quot;, x, get(x, envir=request))
    })
    out &lt;- paste0(out, collapse=&quot;\n&quot;)

    response$body &lt;- sprintf(&quot;&lt;pre>Connection Id: %s\n\n%s&lt;/pre>&quot;, id, out)

  } else if (grepl(&quot;^/predict&quot;, path)) {

    # this gets the query string; we're expecting val=##
    # but aren't going to do any error checking here.
    # You also would want to ensure there is nothing 
    # malicious in the query string.
    query  &lt;- get(&quot;QUERY_STRING&quot;, envir=request)

    # handy helper function from the Shiny folks
    input &lt;- shiny::parseQueryString(query)

    message(sprintf(&quot;Input: %s&quot;, input$val))

    # run the prediction and add the input var value to the list
    res &lt;- predict(model, data.frame(x=as.numeric(input$val)), se.fit = TRUE)
    res$INPUT &lt;- input$val

    # we want to return JSON
    response$headers &lt;- list(&quot;Content-Type&quot;=&quot;application/json&quot;)
    response$body &lt;- jsonlite::toJSON(res, auto_unbox=TRUE, pretty=TRUE)

  }

  response

})

# don't fire off a browser call
app$ignite(showcase=FALSE)
</code></pre>
<p>Assuming you’ve saved that as <code>modelserver.r</code>, you can fire that up in R/RStudio-proper or on the command-line with <code>Rscript modelserver.r</code> (also assuming the fitted model RDS file is in the same directory which is prbly not a good idea for production as well). </p>
<p>You can either enter something like <code>http://127.0.0.1:9123/predict?val=-1.5</code> into your browser to see the JSON result there ore use <code>cURL</code>:</p>
<pre><code>$ curl http://127.0.0.1:9123/predict?val=-1.5
{
  &quot;fit&quot;: -0.8545,
  &quot;se.fit&quot;: 0.5116,
  &quot;df&quot;: 13,
  &quot;residual.scale&quot;: 1.1088,
  &quot;INPUT&quot;: &quot;-1.5&quot;
}</code></pre>
<p>or even <code>httr</code>:</p>
<pre><code>httr::content(httr::GET(&quot;http://127.0.0.1:9123/predict?val=-1.5&quot;))
$fit
[1] -0.8545

$se.fit
[1] 0.5116

$df
[1] 13

$residual.scale
[1] 1.1088

$INPUT
[1] &quot;-1.5&quot;</code></pre>
<p>Try hitting <code>http://127.0.0.1:9123/</code> and <code>http://127.0.0.1:9123/info</code> in similar ways to see what you get.</p>
<p>Keep a watchful eye on <a target="_blank" href="https://github.com/thomasp85/routr"><code>routr</code></a> as it will make setting up API servers in R much easier than this. So far I’m finding <code>fiery</code> a nice middle-ground between writing raw <code>httuv</code> servers, abusing Shiny (since it’s really meant for UX work) or dealing with the slightly more complex <code>opencpu</code> package for turning R into a web request handling engine.</p>
<p>Ideally, one would put this behind a security-aware reverse proxy for both safety (you can add some web application firewall-ish rules) and load balancing, but for in-house/local testing, this is a super quick way to publish your models for wider use. Depending on the adoption rate of <code>fiery</code>, I’ll create some future posts that deal with the complexities of security and performance, along with how to put this all into something like Docker for rapid, controlled deployments.</p>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="http://www.r-bloggers.com/a-simple-prediction-web-service-using-the-new-fiery-package/"></div></div><div><a data-url="http://www.r-bloggers.com/a-simple-prediction-web-service-using-the-new-fiery-package/" data-counturl="http://www.r-bloggers.com/a-simple-prediction-web-service-using-the-new-fiery-package/" data-count="vertical" data-text="A Simple Prediction Web Service Using the New fiery Package" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://rud.is/b/2016/07/05/a-simple-prediction-web-service-using-the-new-firery-package/"> R – rud.is</a></strong>.</div>
<hr>
<a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="http://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="http://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="http://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="http://www.r-bloggers.com/?s=Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="http://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="http://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="http://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="http://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="http://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="http://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="http://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="http://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="http://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="http://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="http://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="http://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/Nw74v1UVFwI"></a></div>