Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send data frame to post request in body #512

Closed
mansi-aggarwal-2504 opened this issue Mar 17, 2020 · 9 comments · Fixed by #550
Closed

Send data frame to post request in body #512

mansi-aggarwal-2504 opened this issue Mar 17, 2020 · 9 comments · Fixed by #550
Labels
difficulty: novice Anyone could help effort: low < 1 day of work help wanted Solution is well-specified enough that any community member could fix

Comments

@mansi-aggarwal-2504
Copy link

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

@schloerke schloerke added difficulty: novice Anyone could help effort: low < 1 day of work help wanted Solution is well-specified enough that any community member could fix labels Mar 17, 2020
@shrektan
Copy link
Contributor

shrektan commented Mar 18, 2020

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))

@mansi-aggarwal-2504
Copy link
Author

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

@shrektan
Copy link
Contributor

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.

@mansi-aggarwal-2504
Copy link
Author

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!

@shrektan
Copy link
Contributor

shrektan commented Mar 19, 2020

@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

@meztez
Copy link
Collaborator

meztez commented Mar 30, 2020

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")

@davidtedfordholt
Copy link

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.

@meztez
Copy link
Collaborator

meztez commented Apr 29, 2020

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...

@davidtedfordholt
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: novice Anyone could help effort: low < 1 day of work help wanted Solution is well-specified enough that any community member could fix
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants