4

我认为这是 R 的水管工库的一个很好的快速演示,但主要是我正在努力以 csv 格式提供数据

我正在使用 R 的水管工包来托管我的一些运动数据的 API 端点。目前,我有一些数据可以获取我正在尝试服务的 MLB 棒球队的获胜总数。使用管道工,我设置了以下 2 个脚本:

setupAPI.R:使用两个 GET 端点设置我的 API:

library(plumber)
library(jsonlite)

# load in some test sports data to host
mydata = structure(list(Team = structure(c(8L, 20L, 7L, 28L, 2L, 30L, 
23L, 1L, 6L, 19L), .Label = c("Angels", "Astros", "Athletics", 
"Blue Jays", "Braves", "Brewers", "Cardinals", "Cubs", "Diamondbacks", 
"Dodgers", "Giants", "Indians", "Mariners", "Marlins", "Mets", 
"Nationals", "Orioles", "Padres", "Phillies", "Pirates", "Rangers", 
"Rays", "Red Sox", "Reds", "Rockies", "Royals", "Tigers", "Twins", 
"White Sox", "Yankees"), class = "factor"), GamesPlayed = c(162L, 
162L, 162L, 162L, 162L, 162L, 162L, 162L, 162L, 162L), CurrentWins = c(92L, 
75L, 83L, 85L, 101L, 91L, 93L, 80L, 86L, 66L)), .Names = c("Team", 
"GamesPlayed", "CurrentWins"), row.names = c(NA, 10L), class = "data.frame")

# create a GET request for shareprices (in JSON format)
#* @get /shareprices_json
getSPs <- function(){ 
  return(toJSON(mydata))
}

# create a GET request for MLB shareprices (in CSV format)
#* @get /shareprices_csv
csvSPs <- function(){
  return(mydata)
}

# run both functions (i think needed for the endpoints to work)   
getSPs()
csvSPs()

RunAPI.R:plumb 的 setupAPI.R,获取本地托管的端点

library(plumber)
r <- plumb("setupAPI.R") 
r$run(port=8000)

. . .

在我的控制台中运行 RunAPI.R 代码后,当我转到端点时,我的http://127.0.0.1:8000/shareprices_csv端点显然返回了一个 JSON 对象,而我的http://127.0.0.1 :8000/shareprices_json端点似乎奇怪地返回了一个长度为 1 的 JSON,其中一个字符串中的 JSON 作为返回的 JSON 中的唯一元素。

简而言之,我现在可以看到我应该简单地返回数据帧,而不是返回 JSON(数据帧),让端点托管 JSON 格式的数据,但是我仍然不知道如何以 CSV 格式提供这些数据。这在水管工中可能吗?setupAPI.R 中的函数中的 return 语句应该是什么样的?任何帮助表示赞赏!

4

2 回答 2

4

这里有两个技巧:

  1. 您可以通过直接返回响应对象来绕过端点上的序列化。更多文档在这里
  2. 您可以通过 mutating 指定响应的主体res$body

您可以结合这两个想法来创建一个端点,例如:

#' @get /data.csv
function(res) {
  con <- textConnection("val","w")
  write.csv(iris, con)
  close(con)

  res$body <- paste(val, collapse="\n")
  res
}

请注意,管道工免费为您做了一些好事,例如为您的 JSON 响应设置适当的 HTTP 标头。如果您要自己发送响应,那么您需要自己处理所有这些,因此您需要确保设置适当的标头来教您的 API 客户端应如何解释此响应。

于 2018-03-07T15:27:17.533 回答
4

如果对任何人有帮助,只需发布​​此答案!

Jeff 的响应非常有效,但是当您必须返回一个大的 CSV 文件时会变得非常慢。我遇到了被 22 MB 文件卡住的问题。

如果您之前将 CSV 写入磁盘,一个更快的解决方案是使用函数(此处include_file的文档):

举个例子:

#* @get /iris_csv
getIrisCsv <- function(req, res) {
    filename <- file.path(tempdir(), "iris.csv")
    write.csv(iris, filename, row.names = FALSE)
    include_file(filename, res, "text/csv")
}

因此,这取决于您的用例:

  • 如果您要返回一个小 csv 并且您不想将其写入磁盘:使用 Jeff 的解决方案
  • 如果您的 CSV 是中型或大型 (> 2MB) 或者您已经在磁盘上:使用include_file解决方案

希望能帮助到你!

于 2018-04-11T11:37:12.830 回答