Fetch API Results from the Browser and send them to Shiny

[This article was first published on Colin Fay, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

How to fetch API results from client-side in a Shiny app and send them
to R.

Why on earth?

Good question! Why on earth would you want your Shiny application to
make API requests from the User Interface (i.e. from the browser)? Right
now, if your application makes API calls, chances are that you have
being doing them straight from R, and that it works pretty well. But in
some cases it might not be the correct implementation, notably if the
API limits requests based on an IP and your application gets a lot of
traffic. For example, Brewdog’s PUNK API limits
to one call per IP per second. In that scenario, if the calls are made
from the server, you will only be able to serve one call per second, and
if your users do a lot of API call at the same time, they will be slowed
down, as the server’s IP is limited to 1 call per second. On the other
end, if the API call is made from the users’ browsers, the server IP is
no longer limited: each user has its own limitation.

How to

You can write API calls using the fetch() JavaScript function. It can
then be used inside a Shiny JavaScript handler, or as a response to a
DOM event (for example, with tags$button("Get Me One!", onclick =
"get_rand_beer()")
, as we will see below).

Here is the general skeleton, that would work when the API does not need
authentication and returns JSON.

  • Inside JavaScript (here, we create a function that will be available
    on an onclick event)

<span class="c1">// JAVASCRIPT FUNCTION DEFINITION</span>
<span class="kd">const</span> <span class="nx">get_rand_beer</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
    <span class="c1">// FETCHING THE API DATA</span>
    <span class="nx">fetch</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://api.punkapi.com/v2/beers/random</span><span class="dl">"</span><span class="p">)</span>
      <span class="c1">// DEFINE WHAT HAPPENS WHEN JAVASCRIPT RECEIVES THE DATA</span>
      <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">data</span><span class="p">)</span> <span class="o">=></span><span class="p">{</span>
        <span class="c1">// CONVERT THE DATA TO JSON</span>
        <span class="nx">data</span><span class="p">.</span><span class="nx">json</span><span class="p">().</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
          <span class="c1">// SEND THE JSON TO R</span>
          <span class="nx">Shiny</span><span class="p">.</span><span class="nx">setInputValue</span><span class="p">(</span><span class="dl">"</span><span class="s2">beer</span><span class="dl">"</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="p">{</span><span class="na">priority</span><span class="p">:</span> <span class="dl">'</span><span class="s1">event</span><span class="dl">'</span><span class="p">})</span>
        <span class="p">})</span>
        <span class="c1">// DEFINE WHAT HAPPENS WHEN THERE IS AN ERROR TURNING DATA TO JSON</span>
        <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
          <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error catchin result from API</span><span class="dl">"</span><span class="p">)</span>
        <span class="p">})</span>
      <span class="p">})</span>
      <span class="c1">// DEFINE WHAT HAPPENS WHEN THERE IS AN ERROR FETCHING THE API</span>
      <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
        <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error catchin result from API</span><span class="dl">"</span><span class="p">)</span>
      <span class="p">})</span>
  <span class="p">};</span>
  • Observe the event in your server:

<span class="n">observeEvent</span><span class="p">(</span><span class="w"> </span><span class="n">input</span><span class="o">$</span><span class="n">beer</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="c1"># Do things with input$beer</span><span class="w">
</span><span class="p">})</span><span class="w">
</span>

And here it is, when the users click on the button, the API calls will
be made from their browser, and then sent back to the server.

Note that the data shared between R and JavaScript is serialized to
JSON, so you will have to manipulate that format once you receive it in
R.

See an example at
ColinFay/punkapi

To leave a comment for the author, please follow the link and comment on their blog: Colin Fay.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)