Используя R's Plumber - создайте конечную точку GET для размещения данных в формате CSV, а не JSON
Я думаю, что это хорошая быстрая демонстрация библиотеки R для сантехников в целом, но в основном я изо всех сил стараюсь обслуживать данные в формате CSV
Я работаю с пакетом водопроводчика R для размещения конечной точки API для некоторых моих спортивных данных. В настоящее время у меня есть некоторые данные, которые собирают итоги побед для бейсбольных команд MLB, которым я пытаюсь служить. Используя сантехника, у меня установлены следующие 2 скрипта:
setupAPI.R: устанавливает мой API с двумя конечными точками GET:
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: файл 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: Конечная точка http://127.0.0.1:8000/shareprices_json, по-видимому, странным образом возвращает JSON длины 1 с JSON в строке в качестве единственного элемента в возвращаемом JSON.
Короче говоря, теперь я вижу, что мне нужно просто возвращать фрейм данных, а не toJSON(фрейм данных), чтобы иметь данные в формате JSON для хоста конечной точки, однако я до сих пор не знаю, как обрабатывать эти данные в формате CSV. Возможно ли это у сантехника? Как должен выглядеть оператор return в функциях в setupAPI.R? Любая помощь приветствуется!
2 ответа
Здесь вам нужно две хитрости:
- Вы можете обойти сериализацию на конечной точке, возвращая объект ответа напрямую. Больше документов здесь
- Вы можете указать тело ответа, изменяя
res$body
,
Вы можете объединить эти две идеи для создания конечной точки, например:
#' @get /data.csv
function(res) {
con <- textConnection("val","w")
write.csv(iris, con)
close(con)
res$body <- paste(val, collapse="\n")
res
}
Обратите внимание, что сантехник бесплатно делает для вас приятные вещи, например, устанавливает соответствующие заголовки HTTP для ваших ответов JSON. Если вы отправляете ответ самостоятельно, вы все это делаете самостоятельно, поэтому вам нужно убедиться, что вы установили соответствующие заголовки, чтобы научить своих клиентов API, как они должны интерпретировать этот ответ.
Просто разместив эти ответы, если кому-нибудь поможет!
Ответ от Джеффа работает отлично, но становится очень медленным, когда вам нужно вернуть большой CSV-файл. У меня были проблемы с застреванием в 22 МБ файле.
Более быстрое решение, если вы ранее записали CSV на диск, это использовать include_file
функция (документы здесь):
В качестве примера:
#* @get /iris_csv
getIrisCsv <- function(req, res) {
filename <- "/tmp/iris.csv"
write.csv(iris, filename, row.names = FALSE)
include_file(filename, res, "text/csv")
}
Итак, это зависит от вашего варианта использования:
- Если вы возвращаете небольшой CSV и не хотите записывать его на диск: воспользуйтесь решением Джеффа
- Если ваш CSV среднего или большого размера (> 2 МБ) или у вас уже есть на диске: используйте
include_file
решение
Надеюсь, поможет!