render html from httr::POST inside shiny app?

plumber
httr
#1

Is it possible to render the html that i get from httr::POST inside a shiny app? For example, suppose I have the following plumber api:

library(plumber)
library(threejs)

#* Returns threejs htmlwidget 
#* @param data json with x y z
#* @post /threejs
#* @serializer htmlwidget
threejs <- function(data){
  scatterplot3js(data$x,data$y,data$z, color=rainbow(length(data$z)))
}

Using httr i can use that api to generate a plot:

library(shiny)
library(jsonlite)
library(httr)

z <- seq(-10, 10, 0.01)
x <- cos(z)
y <- sin(z)

response <- httr::POST(url = 'http://127.0.0.1:9601/threejs', 
                       body = list(data = list(x = x,
                                   y = y,
                                   z = z)), 
                       encode="json")

cat(content(response, "text"), file="temp.html")

Is there a way to render that inside a shiny app? I tried the following

library(shiny)
library(jsonlite)
library(httr)

z <- seq(-10, 10, 0.01)
x <- cos(z)
y <- sin(z)

response <- httr::POST(url = 'http://127.0.0.1:9601/threejs', 
                       body = list(data = list(x = x,
                                   y = y,
                                   z = z)), 
                       encode="json")

# cat(content(response, "text"), file="temp.html")


#ui
ui <- fluidPage(
  
  # Application title
  titlePanel("Testing Plumber"),
  
  sidebarLayout(
    sidebarPanel(
    ),
    
    mainPanel(
      tags$html(HTML(content(response, "text")))
    )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  
}

# Run the application 
shinyApp(ui = ui, server = server)

Alas, it does not work as. Thanks for the help!

0 Likes

#2

This seems like a lot of round trip data passing. What is your end goal? Why not render the widget locally and display with htmlwidgets::shinyRenderWidget?


If you must use the plumber api...

I'd look into having a www folder for your shiny application.

Save the output into the www folder and serve that saved file as an iframe.

0 Likes

#3

Thanks @barret, I'm doing this purely as a learning exercise.

0 Likes

#4

Np! Happy learning!


My ideal shiny/plumber/htmlwidget setup would be...

  • Have a shiny app that knows only about the categories of the data... enough to make the UI
  • Make an iframe for the htmlwidget to appear
    • Maybe make this in a renderUI?
  • Change the iframe location to call the plumber API
  • Have the API return a full htmlwidget within that iframe.

Benefits:

  • Shiny will scale really well as the data is not duplicated in memory for each user
  • The data is housed in one location (plumber API)
    • The underlying data can be VERY large, which may not be suitable for a shiny app, but is ok for an R process to solve.
  • The API inner workings can be updated without redeploying the shiny application.

Disadvantages:

  • Two working applications must communicate with each other
  • The data and UI are separated from each other.
0 Likes

#5

Thanks, this is the part I don't really understand how to implement.

In my example content(response, "text") returns a full htmlwidget. Alas, I'm not sure how to change my simple shiny app to add the iframe and render that widget. Could you point me in the right direction?

0 Likes

#6

Use renderUI with an iframe

This is assuming the data is in the plumber API, not Shiny. Also the API should be a GET (rather than a POST) to work with iframes.

#ui
ui <- fluidPage(
  
  # Application title
  titlePanel("Testing Plumber"),
  
  sidebarLayout(
    sidebarPanel(),
    
    mainPanel(
      # ui output goes here
      uiOutput("widget")
    )
  )
)

server <- function(input, output) {
  # Set widget here
  output$widget <- renderUI({
    tags$iframe(
      # this src location could be dynamic
      src = "http://127.0.0.1:9601/threejs"
    )
  })

}

shinyApp(ui = ui, server = server)

Hope it helps!


** Code untested

1 Like

#7

Thanks, this is very useful. My last question is whether is possible to use httr instead of "http://127.0.0.1:9601/threejs". The reason I ask is that I imagine that passing arguments with httr is the best way of making src dynamic. I tried the following:

response <- httr::GET(url = 'http://127.0.0.1:9878/threejs', 
                       encode="json") %>% 
  httr::content("text")

which did not work. If httr is not possible, how would you pass arguments to the plumber api? the only other way i can think of doing it is with glue

0 Likes