【问题标题】:R: passing API request as an argument to a functionR:将 API 请求作为参数传递给函数
【发布时间】:2020-02-06 00:40:17
【问题描述】:

形成可以作为参数传递给函数的 API 请求的正确方法是什么? 该请求旨在在具有特定参数的另一个函数中构造。

请求示例如下:

library(httr)
GET("http://httpbin.org/get")

我想要的是两个功能

  • 一个用于构造请求,以及
  • 另一个用于发送。

思路是基于多个参数构造请求,包括POST/GET、headers、tokens,然后放到另一个函数中,这个函数负责安全发送请求。

我的尝试
一个简化的示例,显示了所需的结构(尽管它不能正常工作)。

# Function for sending the API request
fn <- function(request) {
  eval(request)
}

# Top function for constructing the request to be sent
fntop <- function(url, type) {
  url <- sprintf("%s%s", url, type)
  my_request <- expression(GET(url))

  fn(my_request)
}

第一个函数在收到直接请求时工作正常。

fn(GET("http://httpbin.org/get"))

但是,当从另一个函数调用包含变量的请求时,相同的函数不起作用

fntop(url = "http://httpbin.org/",
      type = "get")
# Error in as.character(url) : 
#  cannot coerce type 'closure' to vector of type 'character'

如何将包含变量作为参数的 API 请求传递给函数?

【问题讨论】:

  • 如果type被参数化了,这是否意味着你不会总是使用GET?如果是这样,请考虑httr::GET 函数本身可能也需要参数化。
  • 你能解释一下你到底想要做什么吗?这看起来有点像XY Problem。存储这样的表达式似乎很奇怪。存储稍后转换为函数调用的值列表可能更有意义。否则,至少使用 substitute()bquote() 构建表达式以供以后评估可能会更好。
  • @andrew_reece,确实,我想放置多个参数来形成请求。我刚刚做了一个非常简单的例子,只涉及两个参数。
  • @MrFlick,感谢您的回复。我已经扩展了一些解释。顶层函数fntop( )负责根据多个参数构造请求本身。它可能是具有不同内容的 GET/POST/PATCH。另一个函数fn( ) 只是为了安全地发送最终请求。在我的示例中,它只包含一行,但最终它可能会更复杂。

标签: r api httr


【解决方案1】:

与其存储表达式,不如存储表达式所需的数据。类似的东西

fnmake <- function(verb, url, ...) {
  list(verb=verb, params=list(url, ...))
}

然后编写一个可以获取该数据并执行调用的函数

fncall <- function(req) {
    call <- if(req$verb=="get") {
      "GET"
    } else if (req$verb=="post") {
      "POST"
    } else stop(paste("Unrecognized verb:", req$verb)
    do.call(call, req$params)
}

如果你想将它们组合成一个调用,

fnall <- function(...) {
   fncall(fnmake(...))
}

【讨论】:

  • 非常感谢@MrFlick。我实际上已经实施了相同的方法来解决我的问题。如果有办法以表达式的形式将完整的请求作为另一个函数的参数,我正在徘徊?