0

I'm trying to write an RShiny application that will accept a URL, read in one file and write to another file based on parameters in the URL. Basing my approach on R Shiny REST API communication this answer.

Below is a minimal functioning code to generate the app - and when I run it from a browser like Chrome (e.g. just entering the address http://127.0.0.1/?outDest=test2), it will create a file. But if I try to call it using a GET call from httr, it generates an error

could not find function "data_read"

Which makes sense, because that function is available to the server and not the ui, is my understanding at least.

So what I want to do, I think, is have the UI read in and parse the GET query - then trigger a reactiveEvent on the server side to take that data, but I can't get that to generate the output I want.

Is there a way for RShiny to handle this? Or another package - should I be looking at plumber?

Many thanks, Aodhán

library(shiny)
library(rjson)
library(callr)
library(httr)


data_read <- function(x) {
    
    json = fromJSON(file = x)
    dat_df <- bind_rows(lapply(json,as.data.frame))
    
}


    
shiny_UI <- function(req) {
  # The `req` object is a Rook environment
  # See https://github.com/jeffreyhorner/Rook#the-environment
  if (identical(req$REQUEST_METHOD, "GET")) {   
    x = data_read("C:/Users/Z0049Y2S/Documents/test.json")
    query_params <- parseQueryString(req$QUERY_STRING)
    #print(query_params)
    if(length(query_params$outDest) ){
        output_Destination = query_params$outDest
        print(output_Destination)
        write.csv("Hello",paste0(output_Destination,".csv"))
    }
    fluidPage(
      h1("Accepting POST requests from Shiny")
    )
  } 
}

shiny_Server <- function(input, output, session) {
    
}
AodhanOL
  • 630
  • 7
  • 26
  • 1
    `httr::GET` does not create or serve files, it returns a response object. Please see `?response()`. You can write the `content` of the response to a file e.g. via `jsonlite::write_json`. I guess you are already aware of my earlier answer [here](https://stackoverflow.com/questions/25283736/r-shiny-rest-api-communication/71064046#71064046)? – ismirsehregal Apr 28 '22 at 08:00
  • Yes it was a really good description - but I couldn't get it to do what I want. I should edit my question a bit - I want the GET query to trigger some action on the ShinyServer, to run some functions on a dataset and output it to a file. When I try to do that using the shiny_UI, I get an error saying it "could not find function" - which makes sense, because the function is defined external to the UI and I want it to happen on the server side. I will edit my question a bit. – AodhanOL Apr 28 '22 at 08:36

1 Answers1

1

Shiny apps are really designed to communicate with a client via websockets. For handling HTTP requests, you might want to consider a different approach, e.g. a plumber API.

Here's a tailored example of that:

p <- callr::r_bg(
  function() {
    library(plumber)

    pr() |>
      pr_handle("GET", "/", function(outFile) {
        write("Hello", outFile)
      }) |>
      pr_run(port = 9850)
  }
)

httr::GET("http://127.0.0.1:9850?outFile=hello.txt")
readLines("hello.txt")

p$kill()
Mikko Marttila
  • 10,972
  • 18
  • 31
  • I think this is probably the solution, I was used to working with Shiny which is why I defaulted to it, but I suspect I am better off learning a new library. – AodhanOL Apr 28 '22 at 08:46
  • Yeah, you'll get much better tools for working with requests from other libraries. It's definitely possible to hack Shiny to work with this---the UI as a function of `req` will get you there---but even in the medium term I think you will have a better experience elsewhere. – Mikko Marttila Apr 28 '22 at 08:57
  • 1
    This is the route I decided to go down. Highly recommend plumber to anyone who stumbles on this, really easy to use. https://medium.com/tmobile-tech/r-can-api-c184951a24a3 I followed this series of articles to generate a dockerized api that I'm really happy with. Thanks! – AodhanOL Apr 29 '22 at 10:11