diff --git a/NAMESPACE b/NAMESPACE index feedca9..2b9d1a1 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,6 +2,11 @@ S3method(.add_body,json) S3method(.add_body,multipart) +S3method(.as_nectar_auth,"NULL") +S3method(.as_nectar_auth,"function") +S3method(.as_nectar_auth,default) +S3method(.as_nectar_auth,list) +S3method(.as_nectar_auth,nectar_auth) S3method(.as_nectar_request,default) S3method(.as_nectar_request,httr2_request) S3method(.as_nectar_request,nectar_request) @@ -12,6 +17,8 @@ S3method(resp_tidy,default) S3method(resp_tidy,httr2_response) S3method(resp_tidy,list) S3method(resp_tidy,nectar_responses) +export(auth_api_key) +export(auth_prepare) export(choose_pagination_fn) export(compact_nested_list) export(do_if_fn_defined) diff --git a/R/aaa-shared_params.R b/R/aaa-shared_params.R index b82cd1e..6cb7e53 100644 --- a/R/aaa-shared_params.R +++ b/R/aaa-shared_params.R @@ -6,14 +6,15 @@ #' where a request is coming from. We automatically include information about #' your package and nectar, but use this to provide additional details. #' Default `NULL`. -#' @param api_key (`length-1 character`) The API key to use. +#' @param api_key (`length-1 character` or `NULL`) The API key to use. If this +#' value is `NULL`, the key will be removed from the request. If this value is +#' `NA` or an empty string, the request is returned unchanged when the +#' prepared auth is applied. #' @param arg (`length-1 character`) 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. -#' @param auth_args (`list`) An optional list of arguments to the `auth_fn` -#' function. -#' @param auth_fn (`function`) A function to use to authenticate the request. By -#' default (`NULL`), no authentication is performed. +#' @param auth (`nectar_auth` or `NULL`) Authentication prepared with +#' [auth_prepare()]. By default (`NULL`), no authentication is performed. #' @param base_url (`length-1 character`) 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. @@ -35,6 +36,8 @@ #' other than `GET` or `POST`, supply it. Case is ignored. #' @param mime_type (`length-1 character`) The mime type of any files present in #' the body. Some APIs allow you to leave this as NULL for them to guess. +#' @param location (`length-1 character`) Where the API key should be passed. +#' One of `"header"` (default), `"query"`, or `"cookie"`. #' @param name (`length-1 character`) The name of a package or other thing to #' add to or remove from the user agent string. #' @param pagination_fn (`function`) A function that takes the previous response @@ -44,7 +47,8 @@ #' [httr2::iterate_with_offset()]. This function will be extracted from the #' request by [req_perform_opinionated()] and passed on as `next_req` to #' [httr2::req_perform_iterative()]. -#' @param parameter_name (`length-1 character`) The name to use for the API key. +#' @param parameter_name (`length-1 character`) The name of the parameter to use +#' in the header, query, or cookie. #' @param path (`character` or `list`) 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 diff --git a/R/auth_prepare.R b/R/auth_prepare.R new file mode 100644 index 0000000..9aab3bb --- /dev/null +++ b/R/auth_prepare.R @@ -0,0 +1,76 @@ +#' Prepare authentication independent of a request +#' +#' This constructor stores an authentication function and arguments so the same +#' authentication strategy can be reused across requests. +#' +#' @inheritParams .shared-params +#' @param auth_fn (`function`) A function to use to authenticate a request. +#' @param ... (`any`) Arguments to pass to `auth_fn`. +#' @returns A list with class `"nectar_auth"` and elements `auth_fn` and +#' `auth_args`. +#' @family opinionated auth functions +#' @export +#' +#' @examples +#' auth_prepare(req_auth_api_key, "X-API-Key", api_key = "my-api-key") +auth_prepare <- function(auth_fn, ..., call = rlang::caller_env()) { + auth_fn <- rlang::as_function(auth_fn, call = call) + .as_nectar_auth( + list(auth_fn = auth_fn, auth_args = rlang::list2(...)), + call = call + ) +} + +.as_nectar_auth <- function(auth, call = rlang::caller_env()) { + UseMethod(".as_nectar_auth") +} + +#' @export +.as_nectar_auth.nectar_auth <- function(auth, call = rlang::caller_env()) { + return(auth) +} + +#' @export +.as_nectar_auth.NULL <- function(auth, call = rlang::caller_env()) { + return(list(auth_fn = NULL, auth_args = list())) +} + +#' @export +.as_nectar_auth.function <- function(auth, call = rlang::caller_env()) { + .as_nectar_auth(list(auth_fn = auth), call = call) +} + +#' @export +.as_nectar_auth.list <- function(auth, call = rlang::caller_env()) { + if (!("auth_fn" %in% names(auth))) { + return(NextMethod()) + } + auth_args <- stbl::to_lst(auth$auth_args) %||% list() + if (setequal(names(auth), c("auth_fn", "auth_args"))) { + auth$auth_args <- auth_args + class(auth) <- "nectar_auth" + return(auth) + } + structure( + list( + auth_fn = auth$auth_fn, + auth_args = c( + auth_args, + auth[setdiff(names(auth), c("auth_fn", "auth_args"))] + ) + ), + class = "nectar_auth" + ) +} + +#' @export +.as_nectar_auth.default <- function(auth, call = rlang::caller_env()) { + .nectar_abort( + c( + "{.arg {auth}} must be `NULL` or a {.cls nectar_auth}.", + x = "{.arg {auth}} is {.obj_type_friendly {auth}}." + ), + subclass = "unsupported_auth_class", + call = call + ) +} diff --git a/R/req_auth_api_key.R b/R/req_auth_api_key.R index 839a88d..2239de5 100644 --- a/R/req_auth_api_key.R +++ b/R/req_auth_api_key.R @@ -6,15 +6,10 @@ #' #' @inheritParams .shared-params #' @inheritParams rlang::args_dots_empty -#' @param parameter_name (`length-1 character`) The name of the parameter to use -#' in the header, query, or cookie. -#' @param api_key (`length-1 character` or `NULL`) The API key to use. If this -#' value is `NULL`, the key will be removed from the request. If this value is -#' `NA` or an empty string, `req` is returned unchanged. -#' @param location (`length-1 character`) Where the API key should be passed. -#' One of `"header"` (default), `"query"`, or `"cookie"`. #' #' @inherit .shared-request return +#' @family opinionated auth functions +#' @family opinionated request functions #' @export #' #' @examples @@ -60,3 +55,35 @@ req_auth_api_key <- function( req <- rlang::exec(req_api_key_set, req, !!parameter_name := api_key) return(req) } + +#' Prepare API key authentication independent of a request +#' +#' This helper creates a reusable authentication object that can be passed to +#' [req_prepare()] via `auth`. +#' +#' @inheritParams .shared-params +#' @inheritParams rlang::args_dots_empty +#' @returns A list with class `"nectar_auth"` and elements `auth_fn` and +#' `auth_args`. +#' @family opinionated auth functions +#' @export +#' +#' @examples +#' auth_api_key("X-API-Key", api_key = "my-api-key") +auth_api_key <- function( + parameter_name, + ..., + api_key = NULL, + location = c("header", "query", "cookie"), + call = rlang::caller_env() +) { + rlang::check_dots_empty(call = call) + location <- rlang::arg_match(location, error_call = call) + auth_prepare( + req_auth_api_key, + parameter_name = parameter_name, + api_key = api_key, + location = location, + call = call + ) +} diff --git a/R/req_prepare.R b/R/req_prepare.R index 0144768..f716050 100644 --- a/R/req_prepare.R +++ b/R/req_prepare.R @@ -26,8 +26,7 @@ req_prepare <- function( mime_type = NULL, method = NULL, additional_user_agent = NULL, - auth_fn = NULL, - auth_args = list(), + auth = NULL, tidy_fn = NULL, tidy_args = list(), pagination_fn = NULL, @@ -48,7 +47,8 @@ req_prepare <- function( method = method, call = call ) - req <- do_if_fn_defined(req, auth_fn, !!!auth_args, call = call) + auth <- .as_nectar_auth(auth, call = call) + req <- do_if_fn_defined(req, auth$auth_fn, !!!auth$auth_args, call = call) if (length(pagination_fn)) { req <- req_pagination_policy(req, pagination_fn, call = call) } diff --git a/man/auth_api_key.Rd b/man/auth_api_key.Rd new file mode 100644 index 0000000..d98937a --- /dev/null +++ b/man/auth_api_key.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/req_auth_api_key.R +\name{auth_api_key} +\alias{auth_api_key} +\title{Prepare API key authentication independent of a request} +\usage{ +auth_api_key( + parameter_name, + ..., + api_key = NULL, + location = c("header", "query", "cookie"), + call = rlang::caller_env() +) +} +\arguments{ +\item{parameter_name}{(\verb{length-1 character}) The name of the parameter to use +in the header, query, or cookie.} + +\item{...}{These dots are for future extensions and must be empty.} + +\item{api_key}{(\verb{length-1 character} or \code{NULL}) The API key to use. If this +value is \code{NULL}, the key will be removed from the request. If this value is +\code{NA} or an empty string, the request is returned unchanged when the +prepared auth is applied.} + +\item{location}{(\verb{length-1 character}) Where the API key should be passed. +One of \code{"header"} (default), \code{"query"}, or \code{"cookie"}.} + +\item{call}{(\code{environment}) The environment from which a function was called, +e.g. \code{\link[rlang:caller_env]{rlang::caller_env()}} (the default). The environment will be mentioned +in error messages as the source of the error. This argument is particularly +useful for functions that are intended to be called as utilities inside +other functions.} +} +\value{ +A list with class \code{"nectar_auth"} and elements \code{auth_fn} and +\code{auth_args}. +} +\description{ +This helper creates a reusable authentication object that can be passed to +\code{\link[=req_prepare]{req_prepare()}} via \code{auth}. +} +\examples{ +auth_api_key("X-API-Key", api_key = "my-api-key") +} +\seealso{ +Other opinionated auth functions: +\code{\link[=auth_prepare]{auth_prepare()}}, +\code{\link[=req_auth_api_key]{req_auth_api_key()}} +} +\concept{opinionated auth functions} diff --git a/man/auth_prepare.Rd b/man/auth_prepare.Rd new file mode 100644 index 0000000..353233f --- /dev/null +++ b/man/auth_prepare.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/auth_prepare.R +\name{auth_prepare} +\alias{auth_prepare} +\title{Prepare authentication independent of a request} +\usage{ +auth_prepare(auth_fn, ..., call = rlang::caller_env()) +} +\arguments{ +\item{auth_fn}{(\code{function}) A function to use to authenticate a request.} + +\item{...}{(\code{any}) Arguments to pass to \code{auth_fn}.} + +\item{call}{(\code{environment}) The environment from which a function was called, +e.g. \code{\link[rlang:caller_env]{rlang::caller_env()}} (the default). The environment will be mentioned +in error messages as the source of the error. This argument is particularly +useful for functions that are intended to be called as utilities inside +other functions.} +} +\value{ +A list with class \code{"nectar_auth"} and elements \code{auth_fn} and +\code{auth_args}. +} +\description{ +This constructor stores an authentication function and arguments so the same +authentication strategy can be reused across requests. +} +\examples{ +auth_prepare(req_auth_api_key, "X-API-Key", api_key = "my-api-key") +} +\seealso{ +Other opinionated auth functions: +\code{\link[=auth_api_key]{auth_api_key()}}, +\code{\link[=req_auth_api_key]{req_auth_api_key()}} +} +\concept{opinionated auth functions} diff --git a/man/dot-shared-params.Rd b/man/dot-shared-params.Rd index ecb9631..bd2458c 100644 --- a/man/dot-shared-params.Rd +++ b/man/dot-shared-params.Rd @@ -9,17 +9,17 @@ where a request is coming from. We automatically include information about your package and nectar, but use this to provide additional details. Default \code{NULL}.} -\item{api_key}{(\verb{length-1 character}) The API key to use.} +\item{api_key}{(\verb{length-1 character} or \code{NULL}) The API key to use. If this +value is \code{NULL}, the key will be removed from the request. If this value is +\code{NA} or an empty string, the request is returned unchanged when the +prepared auth is applied.} \item{arg}{(\verb{length-1 character}) 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.} -\item{auth_args}{(\code{list}) An optional list of arguments to the \code{auth_fn} -function.} - -\item{auth_fn}{(\code{function}) A function to use to authenticate the request. By -default (\code{NULL}), no authentication is performed.} +\item{auth}{(\code{nectar_auth} or \code{NULL}) Authentication prepared with +\code{\link[=auth_prepare]{auth_prepare()}}. By default (\code{NULL}), no authentication is performed.} \item{base_url}{(\verb{length-1 character}) 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, @@ -49,6 +49,9 @@ other than \code{GET} or \code{POST}, supply it. Case is ignored.} \item{mime_type}{(\verb{length-1 character}) The mime type of any files present in the body. Some APIs allow you to leave this as NULL for them to guess.} +\item{location}{(\verb{length-1 character}) Where the API key should be passed. +One of \code{"header"} (default), \code{"query"}, or \code{"cookie"}.} + \item{name}{(\verb{length-1 character}) The name of a package or other thing to add to or remove from the user agent string.} @@ -60,7 +63,8 @@ using one of the iteration helpers described in request by \code{\link[=req_perform_opinionated]{req_perform_opinionated()}} and passed on as \code{next_req} to \code{\link[httr2:req_perform_iterative]{httr2::req_perform_iterative()}}.} -\item{parameter_name}{(\verb{length-1 character}) The name to use for the API key.} +\item{parameter_name}{(\verb{length-1 character}) The name of the parameter to use +in the header, query, or cookie.} \item{path}{(\code{character} or \code{list}) The route to an API endpoint. Optionally, a list or character vector with the path as one or more unnamed arguments diff --git a/man/req_auth_api_key.Rd b/man/req_auth_api_key.Rd index 98371af..234152a 100644 --- a/man/req_auth_api_key.Rd +++ b/man/req_auth_api_key.Rd @@ -23,7 +23,8 @@ in the header, query, or cookie.} \item{api_key}{(\verb{length-1 character} or \code{NULL}) The API key to use. If this value is \code{NULL}, the key will be removed from the request. If this value is -\code{NA} or an empty string, \code{req} is returned unchanged.} +\code{NA} or an empty string, the request is returned unchanged when the +prepared auth is applied.} \item{location}{(\verb{length-1 character}) Where the API key should be passed. One of \code{"header"} (default), \code{"query"}, or \code{"cookie"}.} @@ -54,3 +55,17 @@ req_auth_api_key(req, "api_key", api_key = "my-api-key", location = "query") # If `api_key` is NULL, the key is removed from the request req_auth_api_key(req, "X-API-Key", api_key = NULL) } +\seealso{ +Other opinionated auth functions: +\code{\link[=auth_api_key]{auth_api_key()}}, +\code{\link[=auth_prepare]{auth_prepare()}} + +Other opinionated request functions: +\code{\link[=req_init]{req_init()}}, +\code{\link[=req_modify]{req_modify()}}, +\code{\link[=req_pagination_policy]{req_pagination_policy()}}, +\code{\link[=req_prepare]{req_prepare()}}, +\code{\link[=req_tidy_policy]{req_tidy_policy()}} +} +\concept{opinionated auth functions} +\concept{opinionated request functions} diff --git a/man/req_init.Rd b/man/req_init.Rd index f30dfbc..4ff141b 100644 --- a/man/req_init.Rd +++ b/man/req_init.Rd @@ -46,6 +46,7 @@ req_init( } \seealso{ Other opinionated request functions: +\code{\link[=req_auth_api_key]{req_auth_api_key()}}, \code{\link[=req_modify]{req_modify()}}, \code{\link[=req_pagination_policy]{req_pagination_policy()}}, \code{\link[=req_prepare]{req_prepare()}}, diff --git a/man/req_modify.Rd b/man/req_modify.Rd index 3b4dfd8..5d0ebde 100644 --- a/man/req_modify.Rd +++ b/man/req_modify.Rd @@ -60,6 +60,7 @@ req_modify(req_base, query = c("param1" = "value1", "param2" = "value2")) } \seealso{ Other opinionated request functions: +\code{\link[=req_auth_api_key]{req_auth_api_key()}}, \code{\link[=req_init]{req_init()}}, \code{\link[=req_pagination_policy]{req_pagination_policy()}}, \code{\link[=req_prepare]{req_prepare()}}, diff --git a/man/req_pagination_policy.Rd b/man/req_pagination_policy.Rd index 41bfdb6..346810f 100644 --- a/man/req_pagination_policy.Rd +++ b/man/req_pagination_policy.Rd @@ -40,6 +40,7 @@ req_pagination_policy(req, httr2::iterate_with_offset("page")) } \seealso{ Other opinionated request functions: +\code{\link[=req_auth_api_key]{req_auth_api_key()}}, \code{\link[=req_init]{req_init()}}, \code{\link[=req_modify]{req_modify()}}, \code{\link[=req_prepare]{req_prepare()}}, diff --git a/man/req_prepare.Rd b/man/req_prepare.Rd index cd1a159..05b4eaf 100644 --- a/man/req_prepare.Rd +++ b/man/req_prepare.Rd @@ -13,8 +13,7 @@ req_prepare( mime_type = NULL, method = NULL, additional_user_agent = NULL, - auth_fn = NULL, - auth_args = list(), + auth = NULL, tidy_fn = NULL, tidy_args = list(), pagination_fn = NULL, @@ -53,11 +52,8 @@ where a request is coming from. We automatically include information about your package and nectar, but use this to provide additional details. Default \code{NULL}.} -\item{auth_fn}{(\code{function}) A function to use to authenticate the request. By -default (\code{NULL}), no authentication is performed.} - -\item{auth_args}{(\code{list}) An optional list of arguments to the \code{auth_fn} -function.} +\item{auth}{(\code{nectar_auth} or \code{NULL}) Authentication prepared with +\code{\link[=auth_prepare]{auth_prepare()}}. By default (\code{NULL}), no authentication is performed.} \item{tidy_fn}{(\code{function}) A function that will be invoked by \code{\link[=resp_tidy]{resp_tidy()}} to tidy the response.} @@ -97,6 +93,7 @@ req_prepare( } \seealso{ Other opinionated request functions: +\code{\link[=req_auth_api_key]{req_auth_api_key()}}, \code{\link[=req_init]{req_init()}}, \code{\link[=req_modify]{req_modify()}}, \code{\link[=req_pagination_policy]{req_pagination_policy()}}, diff --git a/man/req_tidy_policy.Rd b/man/req_tidy_policy.Rd index 5bf17af..a3d9bbf 100644 --- a/man/req_tidy_policy.Rd +++ b/man/req_tidy_policy.Rd @@ -40,6 +40,7 @@ req_tidy_policy(req, httr2::resp_body_json, list(simplifyVector = TRUE)) } \seealso{ Other opinionated request functions: +\code{\link[=req_auth_api_key]{req_auth_api_key()}}, \code{\link[=req_init]{req_init()}}, \code{\link[=req_modify]{req_modify()}}, \code{\link[=req_pagination_policy]{req_pagination_policy()}}, diff --git a/tests/testthat/test-auth_prepare.R b/tests/testthat/test-auth_prepare.R new file mode 100644 index 0000000..4af138a --- /dev/null +++ b/tests/testthat/test-auth_prepare.R @@ -0,0 +1,61 @@ +test_that("auth_prepare() constructs nectar_auth objects (#81)", { + test_result <- auth_prepare(req_auth_api_key, "parm", api_key = "my_key") + expect_s3_class(test_result, "nectar_auth") + expect_identical(test_result$auth_fn, req_auth_api_key) + expect_identical( + test_result$auth_args, + list("parm", api_key = "my_key") + ) +}) + +test_that(".as_nectar_auth() returns nectar_auth objects unchanged (#81)", { + test_input <- auth_prepare( + auth_fn = req_auth_api_key, + auth_args = list(parameter_name = "parm") + ) + test_result <- .as_nectar_auth(test_input) + expect_identical(test_result, test_input) +}) + +test_that(".as_nectar_auth() returns NULL auth_fn and empty auth_args for NULL input (#81)", { + test_result <- .as_nectar_auth(NULL) + expect_identical(test_result$auth_fn, NULL) + expect_identical(test_result$auth_args, list()) +}) + +test_that(".as_nectar_auth() errors for list without auth_fn (#81)", { + stbl::expect_pkg_error_classes( + .as_nectar_auth(list(auth_args = list(parameter_name = "parm"))), + "nectar", + class = "unsupported_auth_class" + ) +}) + +test_that(".as_nectar_auth() converts function input to nectar_auth (#81)", { + test_result <- .as_nectar_auth(req_auth_api_key) + expect_s3_class(test_result, "nectar_auth") + expect_identical(test_result$auth_fn, req_auth_api_key) + expect_identical(test_result$auth_args, list()) +}) + +test_that(".as_nectar_auth() merges auth_args with additional auth fields (#81)", { + test_result <- .as_nectar_auth(list( + auth_fn = req_auth_api_key, + auth_args = list(parameter_name = "parm"), + api_key = "my_key", + location = "query" + )) + expect_s3_class(test_result, "nectar_auth") + expect_identical( + test_result$auth_args, + list(parameter_name = "parm", api_key = "my_key", location = "query") + ) +}) + +test_that(".as_nectar_auth() errors for non-listable auth_args (#81)", { + stbl::expect_pkg_error_classes( + .as_nectar_auth(list(auth_fn = req_auth_api_key, auth_args = mean)), + "stbl", + class = "bad_function" + ) +}) diff --git a/tests/testthat/test-req_auth_api_key.R b/tests/testthat/test-req_auth_api_key.R index 31d7145..03e00aa 100644 --- a/tests/testthat/test-req_auth_api_key.R +++ b/tests/testthat/test-req_auth_api_key.R @@ -12,6 +12,20 @@ test_that("req_auth_api_key errors informatively with unused arguments", { ) }) +test_that("auth_api_key() prepares req_auth_api_key auth (#81)", { + test_result <- auth_api_key( + parameter_name = "parm", + api_key = "my_key", + location = "query" + ) + expect_s3_class(test_result, "nectar_auth") + expect_identical(test_result$auth_fn, req_auth_api_key) + expect_identical( + test_result$auth_args[c("parameter_name", "api_key", "location")], + list(parameter_name = "parm", api_key = "my_key", location = "query") + ) +}) + test_that("req_auth_api_key returns req unchanged if api_key is NA or empty (#76)", { req <- httr2::request("https://example.com") expect_identical(req, req_auth_api_key(req, "parm", api_key = NA_character_)) diff --git a/tests/testthat/test-req_prepare.R b/tests/testthat/test-req_prepare.R index bde0bfd..189f295 100644 --- a/tests/testthat/test-req_prepare.R +++ b/tests/testthat/test-req_prepare.R @@ -153,6 +153,27 @@ test_that("req_prepare() applies tidying", { ) }) +test_that("req_prepare() applies prepared auth (#81)", { + test_result <- req_prepare( + base_url = "https://example.com", + auth = auth_prepare(req_auth_api_key, "parm", api_key = "my_key") + ) + expect_in( + "parm", + names(test_result$headers) + ) +}) + +test_that("req_prepare() errors for unsupported auth objects (#81)", { + expect_error( + req_prepare( + base_url = "https://example.com", + auth = "not_auth" + ), + class = "nectar-error-unsupported_auth_class" + ) +}) + test_that(".as_nectar_request() fails gracefully for non-reqs", { test_obj <- 1 expect_nectar_error_snapshot( diff --git a/vignettes/nectar.Rmd b/vignettes/nectar.Rmd index ff90426..85d8231 100644 --- a/vignettes/nectar.Rmd +++ b/vignettes/nectar.Rmd @@ -27,9 +27,9 @@ The main entry point in nectar is `req_prepare()`. It wraps `httr2::request()` a Here we prepare a request to the Crossref `/works` endpoint. We ask for ten results per page (`rows = 10`), select only the "publisher" and "DOI" fields, tell `{httr2}` to concatenate the `select` parameter with commas (`.multi`), and set the `cursor` parameter to `"*"` to trigger cursor-based pagination: -## Authentication with `req_auth_api_key()` +## Authentication with `auth_api_key()` -Many APIs accept an optional key (or, as in Crossref's case, an email address) to identify your application and gain access to a higher rate limit. nectar provides `req_auth_api_key()` for this purpose. You can pass it through `req_prepare()` via the `auth_fn` and `auth_args` arguments: +Many APIs accept an optional key (or, as in Crossref's case, an email address) to identify your application and gain access to a higher rate limit. nectar provides `auth_api_key()` to prepare this authentication and pass it through `req_prepare()` via the `auth` argument: ```{r auth, eval = FALSE} req <- req_prepare( @@ -37,8 +37,7 @@ req <- req_prepare( query = list( rows = 10, cursor = "*", select = c("publisher", "DOI"), .multi = "comma" ), - auth_fn = req_auth_api_key, - auth_args = list("mailto", api_key = "your@email.com", location = "query") + auth = auth_api_key("mailto", api_key = "your@email.com", location = "query") ) ``` @@ -171,8 +170,7 @@ works <- function( req_prepare( "https://api.crossref.org/works", query = list(rows = rows, cursor = "*", select = select), - auth_fn = req_auth_api_key, - auth_args = list("mailto", api_key = mailto, location = "query"), + auth = auth_api_key("mailto", api_key = mailto, location = "query"), tidy_fn = resp_tidy_json, tidy_args = list(subset_path = c("message", "items")), pagination_fn = iterate_with_json_cursor(