r语言 - 如何动态地将 curl 变量发送到水管工函数?



我想根据任意数量的输入变量动态调用管道工API。我需要将 curl 输入映射到函数名称的输入。例如,如果函数具有输入hicurl -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: R6n"}

在实践中,我真正想做的是加载我的 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.framen"}

内部管道工将请求中的参数与函数中的参数名称匹配。您可以使用special参数来浏览请求中的所有args。如果您有一个名为req的参数,它将为您提供一个包含整个请求元数据的环境,其中一个是req$args。然后你可以解析。前两个参数是对特殊参数reqres的自引用。它们是环境,不应序列化。我不建议执行任何生产代码中显示的内容,因为它会使 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 --header "Content-Type: application/json" 
--request POST 
--data '{"df_in":{"hi":2, "othercrap":4}}' 
http://listen_address

当请求正文以"{"开头时,管道工将使用jsonlite:fromJSON解析正文的内容,并使用解析的对象的名称映射到函数中的参数。

目前,github 上的 CRAN 和主分支都无法通过 swagger api 正确处理此问题,但它可以通过 curl 或其他直接调用方法正常工作。我相信下一个水管工版本将处理所有这些以及更多。

在这里看到一个类似的答案:https://github.com/rstudio/plumber/issues/512#issuecomment-605735332

最新更新