request: Construct and issue JSON-RPC requests

make_requestsR Documentation

Construct and issue JSON-RPC requests

Description

The functions powering all HTTP requests to openBIS are do_requests_serial() for sequential calls and do_requests_parallel() for asynchronous calls. Constructing requests for the JSON-RPC API of openBIS is done with the helper function make_requests() and a wrapper for single requests is available as make_request(). This convenience function calls make_requests() and returns the first element of the resulting list of length 1.

Usage

make_requests(urls, methods, params, ids = NULL, version = "2.0",
  n_con = 5L, finally = process_json, ...)

make_request(url, method, params, ...)

do_requests_serial(urls, bodies = vector("list", length(urls)),
  n_try = 2L, create_handle = create_default_handle,
  check = check_default_result, finally = identity, ...)

do_requests_parallel(urls, bodies = vector("list", length(urls)),
  n_con = 5L, n_try = 2L, create_handle = create_default_handle,
  check = check_default_result, finally = identity, ...)

process_json(x)

resolve_references(x)

Arguments

params

A list structure holding the arguments which, converted to JSON, will be used to call the supplied method. The @type entries will be generated from json_class attributes.

ids

Identifier(s) for the JSON-RPC request (defaults to a random string of length 7). Can be usually be ignored, as only single JSON-RPC requests are issued per HTTP request.

version

JSON-RPC protocol version to be used (defaults to "2.0".

n_con

The number of simultaneous connections.

finally

A function that is applied to the result entry of a successful JSON RPC request.

...

Further arguments to make_request() are passed to make_requests() and from make_requests() to do_requests_serial() or do_requests_parallel().

url, urls

Destination url(s), the request is sent to.

method, methods

The API method name(s).

bodies

Request bodies: a list where each entry is a list with slots id, jsonrpc, method and params.

n_try

Number of tries each request is performed in case of failed requests.

create_handle

A function that will receive a single entry of the bodies list at the time and should return a curl handle created by curl::new_handle().

check

A function that receives both the result of a request and the corresponding entry of the bodies list. Is expected to return NULL in which case the request is retried or a list with an entry named result.

x

A (possibly nested) list structure for which all @type fields are turned into class attributes and @id fields are recursively removed.

Details

Both do_requests_serial() and do_requests_parallel() take as urls argument a set of urls, either as character vector or list of unevaluated function calls which will be evaluated using base::eval() shortly before being used (this is used for urls that are only valid for a limited amount of time). The behavior of do_requests_*() can be customized with the three functions passed as arguments create_handle, check and finally together with the vector (of the same length as urls) passed as argument bodies.

The function passed as create_handle receives one entry at the time of the bodies object and is expected to return a curl handle created by curl::new_handle(). The check function receives as first argument the response of a single curl request alongside the corresponding entry of the bodies object. This function should check whether the request was successful or not, e.g. check the HTTP status code, size of the downloaded file, etc. In case of failure it should return a simpleError error object, created by base::simpleError() and in case of success it should return the response data, e.g. the content entry of a curl response. The third function, finally, is applied to the object returned by the check function (in case of success) and can be used to parse JSON, read a binary file, etc.

Both do_requests_serial() and do_requests_parallel() have the option of retrying failed requests and the number of allowed retries can be controlled with the argument n_try. Furthermore, do_requests_parallel() offers control over the number of simultaneous connections using the argument n_con. Only n_con requests are initially added to the curl multi handle and for each successful one an additional request is added. This implementation helps with urls that have a limited lifetime.

The function make_requests() is used to construct JSON-RPC requests. The arguments methods, params, ids and version are combined into one or several request objects according to the JSON-RPC specification which in turn are passed to do_requests_*(). The objects passed as methods and params should all be of the same length but in case any are of length 1, they will be base::rep()'ed to the required length. Care has to be taken that the list passed as params has the correct degree of nesting. As make_requests() iterates over the topmost list level, a single request should be wrapped in a list such that the topmost list level is of unit length. The function make_request() is a wrapper around make_requests() that does exactly this.

As part of the process_json() function, which is the default value passed as finally argument in make_requests(), @type fields are converted to json_class attributes, using as_json_class(). Additionally, @id fields, which may be referenced if an object is used multiple times, are recursively resolved using resolve_references() such that each object is self-contained.

Value

The return type of make_request()/make_requests() and do_requests_serial()/do_requests_parallel() depends on the callback functions passed as check and finally arguments. At default, make_request()/make_requests() return either a json_class (single object) or a json_vec (multiple objects), dependent on the number of resulting objects, while do_requests_serial()/do_requests_parallel() return a list of raw vectors, one per request.

See Also

Other utility functions: api_url, login_openbis

Examples


  tok <- login_openbis()

  # the function list_projects() is implemented as follows
  projects <- make_request(api_url(api_endpoint = "gis"),
                           "listProjects",
                           list(tok))
  print(projects[[1L]])
  # alternatively, using make_requests(), the params argument has to be a
  # list per request and the first entry of the returned list has to be
  # selected
  proj <- make_requests(api_url(api_endpoint = "gis"),
                        "listProjects",
                        list(list(tok)))
  identical(proj[[1L]][[1L]],
            projects[[1]])

  # without using make_request(), one can achieve the same result by
  # calling do_requests_serial() directly
  proj <- do_requests_serial(api_url(api_endpoint = "gis"),
                             list(
                               list(
                                 id = "foobar",
                                 jsonrpc = "2.0",
                                 method = "listProjects",
                                 params = list(tok)
                               )
                             ),
                             create_handle = infx:::create_request_handle,
                             check = infx:::check_request_result,
                             finally = process_json)
  identical(proj[[1L]][[1L]],
            projects[[1]])

  # the do_requests_*() functions can be used for any HTTP request
  req <- do_requests_serial("https://httpbin.org/headers")
  is.raw(req[[1L]])

  # in order to read the returned binary data, a function can be supplied
  # to do_requests_*() as finally argument

  process_json <- function(x) 
    jsonlite::prettify(rawToChar(x))

  req <- do_requests_serial("https://httpbin.org/headers",
                            finally = process_json)
  req[[1L]]

  # to customize the curl handle, a function can be supplied to
  # do_requests_*() as create_handle argument

  post_handle <- function(x)
    curl::handle_setheaders(
      curl::new_handle(postfields = charToRaw(jsonlite::toJSON(x))),
      "Content-Type" = "application/json"
    )
  process_json <- function(x) 
    jsonlite::fromJSON(rawToChar(x), simplifyDataFrame = FALSE)$json

  data <- list(a = "foo",
               b = "bar")

  req <- do_requests_serial("https://httpbin.org/post",
                            list(data),
                            create_handle = post_handle,
                            finally = process_json)

  # httpbin returns POST data, therefore
  identical(data, req[[1L]])

  logout_openbis(tok)



ropensci/infx documentation built on May 14, 2022, 5:51 p.m.