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

Error Serializing an R object in POST request #661

Closed
adanba opened this issue Aug 25, 2020 · 2 comments
Closed

Error Serializing an R object in POST request #661

adanba opened this issue Aug 25, 2020 · 2 comments

Comments

@adanba
Copy link

adanba commented Aug 25, 2020

Hi,
I try to create an API using Plumber 0.4.7.9000, this API will be consumed by an other R process.

The objectif is to send an R object (RDS, DataFrame, List) with a POST request and get a Transformation of this Object in response.

I got this errors but i don't know what i'm doing wrong ?!

Server Side :

  1. plumber.R
library(dplyr)

do_something <- function(df){
  message(class(df))
  df %>% head
}

#' @post /api
#' @serializer rds
function(req) {
  do_something(req$postBody)
}
  1. run.R
r <- plumb("plumber.R")
r$run(debug = TRUE, port = 8080)

Outputs Server Side :

Running plumber API at http://127.0.0.1:8080
Running swagger UI at http://127.0.0.1:8080/__docs__/
# Call 1
<simpleError in rawToChar(value): embedded nul in string: 'X\n\0\0\0\002\0\003\005\0\0\002\003\0\0\0\003\023\0\0\0\005\0\0\0\016\0\0\0\006@\024ffffff@\023\x99\x99\x99\x99\x99\x9a@\022\xcc\xcc\xcc\xcc\xcc\xcd@\022ffffff@\024\0\0\0\0\0\0@\025\x99\x99\x99\x99\x99\x9a\0\0\0\016\0\0\0\006@\f\0\0\0\0\0\0@\b\0\0\0\0\0\0@\t\x99\x99\x99\x99\x99\x9a@\b\xcc\xcc\xcc\xcc\xcc\xcd@\f\xcc\xcc\xcc\xcc\xcc\xcd@\017333333\0\0\0\016\0\0\0\006?\xf6ffffff?\xf6ffffff?\xf4\xcc\xcc\xcc\xcc\xcc\xcd?\xf8\0\0\0\0\0\0?\xf6ffffff?\xfb333333\0\0\0\016\0\0\0\006?ə\x99\x99\x99\x99\x9a?ə\x99\x99\x99\x99\x9a?ə\x99\x99\x99\x99\x9a?ə\x99\x99\x99\x99\x9a?ə\x99\x99\x99\x99\x9a?\u0659\x99\x99\x99\x99\x9a\0\0\003\r\0\0\0\006\0\0\0\001\0\0\0\001\0\0\0\001\0\0\0\001\0\0\0\001\0\0\0\001\0\0\004\002\0\0\0\001\0\004\0\t\0\0\0\006levels\0\0\0\020\0\0\0\003\0\004\0\t\0\0\0\006setosa\0\004\0\t\0\0\0\nversicolor\0\004\0\t\0\0\0\tvirginica\0\0\004\002\0\0\0\001\0\004\0\t\0\0\0\005class\0\0\0\020\0\0\0\001\0\004\0\t\0\0\0\006factor\0\0\0\xfe\0\0\004\002\0\0\0\001\>
# Call 2
character
# Call 3
<simpleError in getRelevantArgs(allArgs, plumberExpression = private$func): Can't call a Plumber function with unnammed arguments. Missing names for argument(s) #3. Names of argument list was: "req,res,">

Client Side :

  1. Call 1 :
out_call_1 <- httr::POST(
  "http://127.0.0.1:8080/api",
  encode = "raw",
  body = base::serialize( iris %>% head, NULL),
  httr::content_type("application/rds")
)
base::unserialize(httr::content(out_call_1))

Outputs Client Side :

$error
[1] "500 - Internal server error"

$message
[1] "Error in rawToChar(value): embedded nul in string: 'X\\n\\0\\0\\0\\002\\0\\003\\005\\0\\0\\002\\003\\0\\0\\0\\003\\023\\0\\0\\0\\005\\0\\0\\0\\016\\0\\0\\0\\006@\\024ffffff@\\023\\x99\\x99\\x99\\x99\\x99\\x9a@\\022\\xcc\\xcc\\xcc\\xcc\\xcc\\xcd@\\022ffffff@\\024\\0\\0\\0\\0\\0\\0@\\025\\x99\\x99\\x99\\x99\\x99\\x9a\\0\\0\\0\\016\\0\\0\\0\\006@\\f\\0\\0\\0\\0\\0\\0@\\b\\0\\0\\0\\0\\0\\0@\\t\\x99\\x99\\x99\\x99\\x99\\x9a@\\b\\xcc\\xcc\\xcc\\xcc\\xcc\\xcd@\\f\\xcc\\xcc\\xcc\\xcc\\xcc\\xcd@\\017333333\\0\\0\\0\\016\\0\\0\\0\\006?\\xf6ffffff?\\xf6ffffff?\\xf4\\xcc\\xcc\\xcc\\xcc\\xcc\\xcd?\\xf8\\0\\0\\0\\0\\0\\0?\\xf6ffffff?\\xfb333333\\0\\0\\0\\016\\0\\0\\0\\006?ə\\x99\\x99\\x99\\x99\\x9a?ə\\x99\\x99\\x99\\x99\\x9a?ə\\x99\\x99\\x99\\x99\\x9a?ə\\x99\\x99\\x99\\x99\\x9a?ə\\x99\\x99\\x99\\x99\\x9a?\\u0659\\x99\\x99\\x99\\x99\\x9a\\0\\0\\003\\r\\0\\0\\0\\006\\0\\0\\0\\001\\0\\0\\0\\001\\0\\0\\0\\001\\0\\0\\0\\001\\0\\0\\0\\001\\0\\0\\0\\001\\0\\0\\004\\002\\0\\0\\0\\001\\0\\004\\0\\t\\0\\0\\0\\006levels\\0\\0\\0\\020\\0\\0\\0\\003\\0\\004\\0\\t\\0\\0\\0\\006setosa\\0\\004\\0\\t\\0\\0\\0\\nversicolor\\0\\004\\0\\t\\0\\0\\0\\tvirginica\\0\\0\\004\\002\\0\\0\\0\\001\\0\\004\\0\\t\\0\\0\\0\\005class\\0\\0\\0\\020\\0\\0\\0\\001\\0\\004\\0\\t\\0\\0\\0\\006factor\\0\\0\\0\\xfe\\0\\0\\004\\002\\0\\0\\0\\001\\\n"
  1. Call 2 :
out_call_2 <- httr::POST(
  "http://127.0.0.1:8080/api",
  encode = "raw",
  body = base::serialize( iris %>% head, NULL, T),
  httr::content_type("application/rds")
)
base::unserialize(httr::content(out_call_2))

Outputs Client Side :

[1] "A\n2\n197888\n131840\n787\n5\n14\n6\n5.1\n4.9\n4.7\n4.6\n5\n5.4\n14\n6\n3.5\n3\n3.2\n3.1\n3.6\n3.9\n14\n6\n1.4\n1.4\n1.3\n1.5\n1.4\n1.7\n14\n6\n0.2\n0.2\n0.2\n0.2\n0.2\n0.4\n781\n6\n1\n1\n1\n1\n1\n1\n1026\n1\n262153\n6\nlevels\n16\n3\n262153\n6\nsetosa\n262153\n10\nversicolor\n262153\n9\nvirginica\n1026\n1\n262153\n5\nclass\n16\n1\n262153\n6\nfactor\n254\n1026\n1\n262153\n5\nnames\n16\n5\n262153\n12\nSepal.Length\n262153\n11\nSepal.Width\n262153\n12\nPetal.Length\n262153\n11\nPetal.Width\n262153\n7\nSpecies\n1026\n1\n262153\n9\nrow.names\n13\n2\nNA\n6\n1026\n767\n16\n1\n262153\n10\ndata.frame\n254"
  1. Call 3 :
out_call_3 <- httr::POST(
  "http://127.0.0.1:8080/api",
  encode = "raw",
  body = base::serialize( iris %>% head, NULL, T),
  httr::content_type("application/octet-stream")
)
base::unserialize(httr::content(out_call_3))

Outputs Client Side :

$error
[1] "500 - Internal server error"

$message
[1] "Error in getRelevantArgs(allArgs, plumberExpression = private$func): Can't call a Plumber function with unnammed arguments. Missing names for argument(s) #3. Names of argument list was: \"req,res,\"\n"

Environment Info :

> sessionInfo()
R version 3.5.0 (2018-04-23)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS  10.15.5

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] dplyr_0.8.3        plumber_0.4.7.9000 webutils_1.1      

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.4           pillar_1.4.2         compiler_3.5.0      
 [4] later_1.0.0          prettyunits_1.0.2    base64enc_0.1-3     
 [7] remotes_2.0.2        tools_3.5.0          testthat_2.3.1      
[10] digest_0.6.21        pkgbuild_1.0.2       pkgload_1.0.2       
[13] tibble_2.1.3         lifecycle_0.2.0      jsonlite_1.6.1      
[16] memoise_1.1.0.9000   pkgconfig_2.0.2      rlang_0.4.5         
[19] cli_1.0.0            rstudioapi_0.11      curl_4.3            
[22] yaml_2.2.0           yesno_0.1.0          swagger_3.20.3.99991
[25] withr_2.1.2          desc_1.2.0           fs_1.2.6            
[28] devtools_2.0.1       tidyselect_0.2.5     rprojroot_1.3-2     
[31] glue_1.3.2           R6_2.4.1             processx_3.2.0      
[34] sessioninfo_1.1.1    purrr_0.3.3          callr_3.0.0         
[37] magrittr_1.5         backports_1.1.2      ps_1.2.1            
[40] promises_1.1.0       usethis_1.4.0        assertthat_0.2.1    
[43] httpuv_1.5.2         stringi_1.4.6        crayon_1.3.4      

Is there an other way to do this whitout converting my R objet to a JSON and without writing the response to disk (ie as done by @meztez here) ?

Thank you for your help!

@meztez
Copy link
Collaborator

meztez commented Aug 25, 2020

Parser are not all available by default, only a select few. Parser rds has to be specified to be used. See ?parser_form

Parsers are optional. When unspecified, only the parser_json(), parser_octet(), parser_form() and parser_text() are available. You can use @parser parser tag to activate parsers per endpoint. Multiple parsers can be activated for the same endpoint using multiple @parser parser tags.

Here I use another req named object to get access to your parsed body arguments.

do_something <- function(df){
  message(class(df))
  df %>% head
}

#* @post /api
#* @parser rds
#* @serializer rds
function(req) {
  do_something(req$argsPostBody)
}

@adanba
Copy link
Author

adanba commented Aug 25, 2020

Thank you very much @meztez, using parser resolves my problem.

I post the complet solution, hope this help others.

Server Side :

plumber.R

library(plumber)
do_something <- function(df){
  message(class(df))
  df %>% head
}

#* My API
#* @parser rds
#* @serializer rds
#* @post /api
function(req) {
  do_something(req$argsPostBody)
}

Run.R

r <- plumb("./plumber.R")
r$run(debug = TRUE, port = 8080)

Client Side :

out_call <- httr::POST(
  "http://127.0.0.1:8080/api",
  encode = "raw",
  body = base::serialize(trees, NULL),
  httr::content_type("application/rds")
)
base::unserialize(httr::content(out_call))

Output :
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants