如何动态地将 curl 变量发送到水管工函数?
How to send curl variables to plumber function dynamically?
我想根据任意数量的输入变量动态调用管道工 API。我需要将 curl 输入映射到函数名称的输入。例如,如果函数有一个输入 hi
,那么 curl -s --data 'hi=2'
意味着 hi=2
应该作为输入参数传递给函数。这可以直接在 R 中使用 match.call()
完成,但是在通过管道工 API.
调用它时失败了
取函数
#' @post /API
#' @serializer unboxedJSON
tmp <- function(hi) {
out <- list(hi=hi)
out <- toJSON(out, pretty = TRUE, auto_unbox = TRUE)
return(out)
}
tmp(hi=2)
out: {hi:2}
然后
curl -s --data 'hi=10' http://127.0.0.1/8081/API
out: {\n \"hi\": \"2\"\n}
一切看起来都很好。但是,取函数
#' @post /API
#' @serializer unboxedJSON
tmp <- function(...) {
out <- match.call() %>%
as.list() %>%
.[2:length(.)] # %>%
out <- toJSON(out, pretty = TRUE, auto_unbox = TRUE)
return(out)
}
tmp(hi=2)
out: {hi:2}
然后
curl -s --data 'hi=10' http://127.0.0.1/8081/API
out: {"error":"500 - Internal server error","message":"Error: No method asJSON S3 class: R6\n"}
在实践中,我真正想做的是加载我的 ML 模型来预测水管工的分数 API。例如
model <- readRDS('model.rds') # Load model as a global variable
predict_score <- function(...) {
df_in <- match.call() %>%
as.list() %>%
.[2:length(.)] %>%
as.data.frame()
json_out <- list(
score_out = predict(model, df_in) %>%
toJSON(., pretty = T, auto_unbox = T)
return(json_out)
}
此函数在 运行 本地时按预期工作,但 运行 通过 API 通过 curl -s --data 'var1=1&var2=2...etc' http://listen_address
我收到以下错误:{"error":"500 - Internal server error","message":"Error in as.data.frame.default(x[[i]], optional = TRUE): cannot coerce class \"c(\"PlumberResponse\", \"R6\")\" to a data.frame\n"}
内部管道工将您请求中的参数与函数中的参数名称进行匹配。您可以使用 special
个参数来探索请求中的所有 args
个参数。如果您有一个名为 req
的参数,它将为您提供一个包含整个请求元数据的环境,其中之一是 req$args
。然后你可以解析。前两个参数是对特殊参数 req
和 res
的自引用。它们是环境,不应序列化。我不建议在任何生产代码中执行此处显示的操作,因为它会打开 api 滥用。
model <- readRDS('model.rds') # Load model as a global variable
#' @post /API
#' @serializer unboxedJSON
predict_score <- function(req) {
df_in <- as.data.frame(req$args[-(1:2)])
json_out <- list(
score_out = predict(model, df_in)
return(json_out)
}
但对于您的用例,我实际上建议使用一个名为 df_in 的参数。以下是您将如何设置它。
model <- readRDS('model.rds') # Load model as a global variable
#' @post /API
#' @param df_in
#' @serializer unboxedJSON
predict_score <- function(df_in) {
json_out <- list(
score_out = predict(model, df_in)
return(json_out)
}
然后用 curl
curl --header "Content-Type: application/json" \
--request POST \
--data '{"df_in":{"hi":2, "othercrap":4}}' \
http://listen_address
当请求主体以“{”开头时,管道工将使用jsonlite:fromJSON
解析主体内容,并使用解析对象的名称映射到函数中的参数。
目前 github 上的 CRAN 和 master 分支都不能通过 swagger api 正确处理这个问题,但它可以通过 curl 或其他直接调用方法正常工作。下一个管道工版本将处理所有这些,我相信更多。
在此处查看对此问题的类似答案:https://github.com/rstudio/plumber/issues/512#issuecomment-605735332
我想根据任意数量的输入变量动态调用管道工 API。我需要将 curl 输入映射到函数名称的输入。例如,如果函数有一个输入 hi
,那么 curl -s --data 'hi=2'
意味着 hi=2
应该作为输入参数传递给函数。这可以直接在 R 中使用 match.call()
完成,但是在通过管道工 API.
取函数
#' @post /API
#' @serializer unboxedJSON
tmp <- function(hi) {
out <- list(hi=hi)
out <- toJSON(out, pretty = TRUE, auto_unbox = TRUE)
return(out)
}
tmp(hi=2)
out: {hi:2}
然后
curl -s --data 'hi=10' http://127.0.0.1/8081/API
out: {\n \"hi\": \"2\"\n}
一切看起来都很好。但是,取函数
#' @post /API
#' @serializer unboxedJSON
tmp <- function(...) {
out <- match.call() %>%
as.list() %>%
.[2:length(.)] # %>%
out <- toJSON(out, pretty = TRUE, auto_unbox = TRUE)
return(out)
}
tmp(hi=2)
out: {hi:2}
然后
curl -s --data 'hi=10' http://127.0.0.1/8081/API
out: {"error":"500 - Internal server error","message":"Error: No method asJSON S3 class: R6\n"}
在实践中,我真正想做的是加载我的 ML 模型来预测水管工的分数 API。例如
model <- readRDS('model.rds') # Load model as a global variable
predict_score <- function(...) {
df_in <- match.call() %>%
as.list() %>%
.[2:length(.)] %>%
as.data.frame()
json_out <- list(
score_out = predict(model, df_in) %>%
toJSON(., pretty = T, auto_unbox = T)
return(json_out)
}
此函数在 运行 本地时按预期工作,但 运行 通过 API 通过 curl -s --data 'var1=1&var2=2...etc' http://listen_address
我收到以下错误:{"error":"500 - Internal server error","message":"Error in as.data.frame.default(x[[i]], optional = TRUE): cannot coerce class \"c(\"PlumberResponse\", \"R6\")\" to a data.frame\n"}
内部管道工将您请求中的参数与函数中的参数名称进行匹配。您可以使用 special
个参数来探索请求中的所有 args
个参数。如果您有一个名为 req
的参数,它将为您提供一个包含整个请求元数据的环境,其中之一是 req$args
。然后你可以解析。前两个参数是对特殊参数 req
和 res
的自引用。它们是环境,不应序列化。我不建议在任何生产代码中执行此处显示的操作,因为它会打开 api 滥用。
model <- readRDS('model.rds') # Load model as a global variable
#' @post /API
#' @serializer unboxedJSON
predict_score <- function(req) {
df_in <- as.data.frame(req$args[-(1:2)])
json_out <- list(
score_out = predict(model, df_in)
return(json_out)
}
但对于您的用例,我实际上建议使用一个名为 df_in 的参数。以下是您将如何设置它。
model <- readRDS('model.rds') # Load model as a global variable
#' @post /API
#' @param df_in
#' @serializer unboxedJSON
predict_score <- function(df_in) {
json_out <- list(
score_out = predict(model, df_in)
return(json_out)
}
然后用 curl
curl --header "Content-Type: application/json" \
--request POST \
--data '{"df_in":{"hi":2, "othercrap":4}}' \
http://listen_address
当请求主体以“{”开头时,管道工将使用jsonlite:fromJSON
解析主体内容,并使用解析对象的名称映射到函数中的参数。
目前 github 上的 CRAN 和 master 分支都不能通过 swagger api 正确处理这个问题,但它可以通过 curl 或其他直接调用方法正常工作。下一个管道工版本将处理所有这些,我相信更多。
在此处查看对此问题的类似答案:https://github.com/rstudio/plumber/issues/512#issuecomment-605735332