Title: | A Framework for Web API Packages |
---|---|
Description: | An opinionated framework for use within api-wrapping R packages. |
Authors: | Jon Harmon [aut, cre, cph] , R Consortium [fnd] |
Maintainer: | Jon Harmon <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.0.0.9003 |
Built: | 2024-11-22 04:06:16 UTC |
Source: | https://github.com/jonthegeek/nectar |
This function implements an opinionated framework for making API calls. It is
intended to be used inside an API client package. It serves as a wrapper
around the req_
family of functions, such as httr2::request()
, as well as
httr2::req_perform()
and httr2::req_perform_iterative()
, and, by default,
httr2::resp_body_json()
.
call_api( base_url, ..., path = NULL, query = NULL, body = NULL, mime_type = NULL, method = NULL, security_fn = NULL, security_args = list(), response_parser = httr2::resp_body_json, response_parser_args = list(), next_req = NULL, max_reqs = Inf, max_tries_per_req = 3, user_agent = "nectar (https://nectar.api2r.org)" )
call_api( base_url, ..., path = NULL, query = NULL, body = NULL, mime_type = NULL, method = NULL, security_fn = NULL, security_args = list(), response_parser = httr2::resp_body_json, response_parser_args = list(), next_req = NULL, max_reqs = Inf, max_tries_per_req = 3, user_agent = "nectar (https://nectar.api2r.org)" )
base_url |
The part of the url that is shared by all calls to the API. In some cases there may be a family of base URLs, from which you will need to choose one. |
... |
These dots are for future extensions and must be empty. |
path |
The route to an API endpoint. Optionally, a list or character
vector with the path as one or more unnamed arguments (which will be
concatenated with "/") plus named arguments to |
query |
An optional list or character vector of parameters to pass in
the query portion of the request. Can also include a |
body |
An object to use as the body of the request. If any component of
the body is a path, pass it through |
mime_type |
A character scalar indicating the mime type of any files present in the body. Some APIs allow you to leave this as NULL for them to guess. |
method |
If the method is something other than GET or POST, supply it. Case is ignored. |
security_fn |
A function to use to authenticate the request. By default
( |
security_args |
An optional list of arguments to the |
response_parser |
A function to parse the server response ( |
response_parser_args |
An optional list of arguments to pass to the
|
next_req |
An optional function that takes the previous response
( |
max_reqs |
The maximum number of separate requests to perform. Passed to
the max_reqs argument of |
max_tries_per_req |
The maximum number of times to attempt each
individual request. Passed to the |
user_agent |
A string to identify where this request is coming from. It's polite to set the user agent to identify your package, such as "MyPackage (https://mypackage.com)". |
The response from the API, parsed by the response_parser
.
req_setup()
, req_modify()
, req_perform_opinionated()
,
resp_parse()
, and do_if_fn_defined()
for finer control of the process.
Discard empty elements in nested lists.
compact_nested_list(lst)
compact_nested_list(lst)
lst |
A (nested) list to filter. |
The list, minus empty elements and branches.
x <- list( a = list( b = letters, c = NULL, d = 1:5 ), e = NULL, f = 1:3 ) compact_nested_list(x)
x <- list( a = list( b = letters, c = NULL, d = 1:5 ), e = NULL, f = 1:3 ) compact_nested_list(x)
When constructing API calls programmatically, you may encounter situations where an upstream task should indicate which function to apply. For example, one endpoint might use a special security function that isn't used by other endpoints. This function exists to make coding such situations easier.
do_if_fn_defined(x, fn = NULL, ...)
do_if_fn_defined(x, fn = NULL, ...)
x |
An object to potentially modify, such as a |
fn |
A function to apply to |
... |
Additional arguments to pass to |
The object, potentially modified.
build_api_req <- function(endpoint, security_fn = NULL, ...) { req <- httr2::request("https://example.com") req <- httr2::req_url_path_append(req, endpoint) do_if_fn_defined(req, security_fn, ...) } # Most endpoints of this API do not require authentication. unsecure_req <- build_api_req("unsecure_endpoint") unsecure_req$headers # But one endpoint requires secure_req <- build_api_req( "secure_endpoint", httr2::req_auth_bearer_token, "secret-token" ) secure_req$headers$Authorization
build_api_req <- function(endpoint, security_fn = NULL, ...) { req <- httr2::request("https://example.com") req <- httr2::req_url_path_append(req, endpoint) do_if_fn_defined(req, security_fn, ...) } # Most endpoints of this API do not require authentication. unsecure_req <- build_api_req("unsecure_endpoint") unsecure_req$headers # But one endpoint requires secure_req <- build_api_req( "secure_endpoint", httr2::req_auth_bearer_token, "secret-token" ) secure_req$headers$Authorization
Many APIs provide API keys that can be used to authenticate requests (or, often, provide other information about the user). This function helps to apply those keys to requests.
req_auth_api_key(req, ..., location = "header")
req_auth_api_key(req, ..., location = "header")
req |
A |
... |
Additional parameters depending on the location of the API key.
|
location |
Where the API key should be passed. One of |
A httr2::request()
object.
Modify the basic request for an API by adding a path and any other path-specific properties.
req_modify( req, ..., path = NULL, query = NULL, body = NULL, mime_type = NULL, method = NULL )
req_modify( req, ..., path = NULL, query = NULL, body = NULL, mime_type = NULL, method = NULL )
req |
A |
... |
These dots are for future extensions and must be empty. |
path |
The route to an API endpoint. Optionally, a list or character
vector with the path as one or more unnamed arguments (which will be
concatenated with "/") plus named arguments to |
query |
An optional list or character vector of parameters to pass in
the query portion of the request. Can also include a |
body |
An object to use as the body of the request. If any component of
the body is a path, pass it through |
mime_type |
A character scalar indicating the mime type of any files present in the body. Some APIs allow you to leave this as NULL for them to guess. |
method |
If the method is something other than GET or POST, supply it. Case is ignored. |
A httr2::request()
object.
req_base <- req_setup( "https://example.com", user_agent = "my_api_client (https://my.api.client)" ) req <- req_modify(req_base, path = c("specific/{path}", path = "endpoint")) req req <- req_modify(req, query = c("param1" = "value1", "param2" = "value2")) req
req_base <- req_setup( "https://example.com", user_agent = "my_api_client (https://my.api.client)" ) req <- req_modify(req_base, path = c("specific/{path}", path = "endpoint")) req req <- req_modify(req, query = c("param1" = "value1", "param2" = "value2")) req
This function ensures that a request has httr2::req_retry()
applied, and
then performs the request, using either httr2::req_perform_iterative()
(if
a next_req
function is supplied) or httr2::req_perform()
(if not).
req_perform_opinionated( req, ..., next_req = NULL, max_reqs = 2, max_tries_per_req = 3 )
req_perform_opinionated( req, ..., next_req = NULL, max_reqs = 2, max_tries_per_req = 3 )
req |
The first request to perform. |
... |
These dots are for future extensions and must be empty. |
next_req |
An optional function that takes the previous response
( |
max_reqs |
The maximum number of separate requests to perform. Passed to
the max_reqs argument of |
max_tries_per_req |
The maximum number of times to attempt each
individual request. Passed to the |
A list of httr2::response()
objects, one for each request
performed.
This function implements an opinionated framework for preparing an API
request. It is intended to be used inside an API client package. It serves as
a wrapper around the req_
family of functions, such as httr2::request()
.
req_prepare( base_url, ..., path = NULL, query = NULL, body = NULL, mime_type = NULL, method = NULL, user_agent = "nectar (https://nectar.api2r.org)" )
req_prepare( base_url, ..., path = NULL, query = NULL, body = NULL, mime_type = NULL, method = NULL, user_agent = "nectar (https://nectar.api2r.org)" )
base_url |
The part of the url that is shared by all calls to the API. In some cases there may be a family of base URLs, from which you will need to choose one. |
... |
These dots are for future extensions and must be empty. |
path |
The route to an API endpoint. Optionally, a list or character
vector with the path as one or more unnamed arguments (which will be
concatenated with "/") plus named arguments to |
query |
An optional list or character vector of parameters to pass in
the query portion of the request. Can also include a |
body |
An object to use as the body of the request. If any component of
the body is a path, pass it through |
mime_type |
A character scalar indicating the mime type of any files present in the body. Some APIs allow you to leave this as NULL for them to guess. |
method |
If the method is something other than GET or POST, supply it. Case is ignored. |
user_agent |
A string to identify where this request is coming from. It's polite to set the user agent to identify your package, such as "MyPackage (https://mypackage.com)". |
A httr2::request()
object.
For a given API, the base_url
and user_agent
will almost always be the
same. Use this function to prepare that piece of the request once for easy
reuse.
req_setup(base_url, ..., user_agent = "nectar (https://nectar.api2r.org)")
req_setup(base_url, ..., user_agent = "nectar (https://nectar.api2r.org)")
base_url |
The part of the url that is shared by all calls to the API. In some cases there may be a family of base URLs, from which you will need to choose one. |
... |
These dots are for future extensions and must be empty. |
user_agent |
A string to identify where this request is coming from. It's polite to set the user agent to identify your package, such as "MyPackage (https://mypackage.com)". |
A httr2::request()
object.
req_setup("https://example.com") req_setup( "https://example.com", user_agent = "my_api_client (https://my.api.client)" )
req_setup("https://example.com") req_setup( "https://example.com", user_agent = "my_api_client (https://my.api.client)" )
httr2
provides two methods for performing requests: httr2::req_perform()
,
which returns a single httr2::response()
object, and
httr2::req_perform_iterative()
, which returns a list of httr2::response()
objects. This function automatically determines whether a single response or
multiple responses have been returned, and parses the responses
appropriately.
resp_parse(resp, ...) ## Default S3 method: resp_parse( resp, ..., arg = rlang::caller_arg(resp), call = rlang::caller_env() ) ## S3 method for class 'httr2_response' resp_parse(resp, ..., response_parser = httr2::resp_body_json)
resp_parse(resp, ...) ## Default S3 method: resp_parse( resp, ..., arg = rlang::caller_arg(resp), call = rlang::caller_env() ) ## S3 method for class 'httr2_response' resp_parse(resp, ..., response_parser = httr2::resp_body_json)
resp |
A single |
... |
Additional arguments passed on to the |
arg |
An argument name as a string. This argument will be mentioned in error messages as the input that is at the origin of a problem. |
call |
The execution environment of a currently running function, e.g. caller_env(). The function will be mentioned in error messages as the source of the error. See the call argument of abort() for more information. |
response_parser |
A function to parse the server response ( |
The response parsed by the response_parser
. If resp
was a list,
the parsed responses are concatenated when possible. Unlike
httr2::resps_data, this function does not concatenate raw vector
responses.
Calls to APIs often require a string argument. This function ensures that
those arguments are length-1, non-NA
character vectors, or length-1,
non-NA
vectors that can be coerced to character vectors. This is intended
to ensure that calls to the API will not fail with predictable errors, thus
avoiding unnecessary internet traffic.
stabilize_string( x, ..., regex = NULL, arg = rlang::caller_arg(x), call = rlang::caller_env() )
stabilize_string( x, ..., regex = NULL, arg = rlang::caller_arg(x), call = rlang::caller_env() )
x |
The argument to stabilize. |
... |
Arguments passed on to
|
regex |
Character scalar. An optional regex pattern to compare the
value(s) of |
arg |
An argument name as a string. This argument will be mentioned in error messages as the input that is at the origin of a problem. |
call |
The execution environment of a currently
running function, e.g. |
x
coerced to a length-1 character vector, if possible.
stabilize_string("a") stabilize_string(1.1) x <- letters try(stabilize_string(x)) x <- NULL try(stabilize_string(x)) x <- character() try(stabilize_string(x)) x <- NA try(stabilize_string(x))
stabilize_string("a") stabilize_string(1.1) x <- letters try(stabilize_string(x)) x <- NULL try(stabilize_string(x)) x <- character() try(stabilize_string(x)) x <- NA try(stabilize_string(x))
This function normalizes a URL by adding a trailing slash to the base if it is missing. It is mainly for testing and other comparisons.
url_normalize(url)
url_normalize(url)
url |
A URL to normalize. |
A normalized URL
identical( url_normalize("https://example.com"), url_normalize("https://example.com/") ) identical( url_normalize("https://example.com?param=value"), url_normalize("https://example.com/?param=value") )
identical( url_normalize("https://example.com"), url_normalize("https://example.com/") ) identical( url_normalize("https://example.com?param=value"), url_normalize("https://example.com/?param=value") )
Append zero or more path elements to a URL without duplicating "/"
characters. Based on httr2::req_url_path_append()
.
url_path_append(url, ...)
url_path_append(url, ...)
url |
A URL to modify. |
... |
Path elements to append, as strings. |
A modified URL.
url_path_append("https://example.com", "api", "v1", "users") url_path_append("https://example.com/", "/api", "/v1", "/users") url_path_append("https://example.com/", "/api/v1/users")
url_path_append("https://example.com", "api", "v1", "users") url_path_append("https://example.com/", "/api", "/v1", "/users") url_path_append("https://example.com/", "/api/v1/users")