Plumber: Send data frame to post request in body

Created on 17 Mar 2020  路  9Comments  路  Source: rstudio/plumber

I want a data frame to a @post request body, and do something (say, time series analysis) and return a data frame
Or maybe send JSON and inside the post function, convert it to a data frame and do something and return a data frame
I am new to plumber and am having trouble understanding this

novice low help wanted

All 9 comments

Converting to JSON is feasible but you have to handle these things by yourself - zero-row table, the Date attributes, etc.

So if you only want to pass the data.frame, a safer (probably better) way is to use the rds serializer.

plumber

#* @post /api
#* @serializer rds
function() {
  ...
}

users

out <- httr::POST(
  url,
  encode = "raw",
  body = body,
  httr::content_type("application/octet-stream"),
  ...
)
# you may need to check httr::status_code() == 200L 
# or if is.raw(httr::content(out)) is TRUE, first
base::unserialize(httr::content(out))

Thank you for your comment; but I have a query.
This is what I am doing:

#'@post /testdf
#'@serializer rds
function(req){
  data <- (req$postBody)
  return(ncol(data))
}

User:

data <- read.csv("XYZ.csv")

result <- POST(url = 'http://127.0.0.1:8000/testdf', body = data, encode = "raw"
                   httr::content_type("application/octet-stream"))

But it says this:
Error in body_raw(body) : is.raw(body) is not TRUE

Can you tell me what I am doing wrong here

Sorry, I didn't notice that you were asking "POSTING the data.frame". I misunderstood for "REQUSTING the data.frame". There're workarounds for this. I remembered https://github.com/ozean12/protopretzel uses this.

However, I don't have time to write an example for you. But if you really need it, I can make an example later.

I didn't find what I am looking for here at https://github.com/ozean12/protopretzel
Thanks for the help, though. If you could provide and example whenever you can, that'd be great. Thanks!

@mansi-aggarwal-2504 It's there actually. Here the example. Put the three files in the same folder. Run main.R to launch a server. Run client.R to test.

plumber.R

#* @post /api
#* @serializer rds
function(req) {
  req$robj
}

main.R

(A better example is this: https://github.com/ozean12/protopretzel/blob/master/R/protobuf_filter.R)

library(plumber)
x <- plumb("plumber.R")
x$filter("robj", function(req) {
  req$rook.input$rewind()
  req$robj <- unserialize(req$rook.input$read())
  plumber::forward()
})
x$run(debug = TRUE, port = 9999)

client.R

out <- httr::POST(
  "http://127.0.0.1:9999/api",
  encode = "raw",
  body = serialize(iris, NULL),
  httr::content_type("application/octet-stream")
)
# you may need to check httr::status_code() == 200L 
# or if is.raw(httr::content(out)) is TRUE, first
base::unserialize(httr::content(out))

What I get

image

That might be what you are looking for, you can try that, just replace with your hostname.
(requires plumber >= 0.4.7)

plumber.R

library(plumber)

#* Sort df
#* @param df
#* @json
#* @post /sortdfjson
function(df) {
  df[order(df$Height),]
}

#* Sort df
#* @param df
#* @serializer rds
#* @post /sortdfrds
function(df) {
  df[order(df$Height),]
}

entrypoint.R

library(plumber)
pr <- plumb("plumber.R")
pr$run()

In another R session (replace hostname:port). You basically put your data.frame in a json format and add a name (the name of your parameter) in front.

a <- paste0('{"df":',jsonlite::toJSON(trees), '}', sep = '')
class(a) <- "json"
req <- httr::POST(url = "http://127.0.0.1:3540/sortdfjson",
                  httr::accept_json(),
                  body = a,
                  httr::write_disk("response.json", overwrite = TRUE))
df1 <- jsonlite::fromJSON(httr::content(req, as = "text"))

req <- httr::POST(url = "http://127.0.0.1:3540/sortdfrds",
                  httr::accept_json(),
                  body = a,
                  httr::write_disk("response.rds", overwrite = TRUE))
df2 <- readRDS("response.rds")

On a clean installation of R 3.6.3, having just installed plumber 0.4.6 from CRAN, I tried to recreate the last example (with plumber.R and entrypoint.R). I get this error:

Error in parseBlock(lineNum, file) : No such @serializer registered: rds

I can use the html and json serializers, but it will not start with rds set. I'm happy to create a different issue if this isn't just me not understanding something additional I was supposed to do to set up the example.

You would at least need 0.4.7 to use rds serializer as it was added in #387 , really sorry for that.

You can either install from github with remotes::install_github("rstudio/plumber") or create your own rds serializer...

Thanks! No apology needed at all, the examples are extremely helpful.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jeffkeller87 picture jeffkeller87  路  6Comments

Jube-Dev picture Jube-Dev  路  3Comments

dmenne picture dmenne  路  4Comments

david-cortes picture david-cortes  路  3Comments

meztez picture meztez  路  4Comments