diff --git a/NAMESPACE b/NAMESPACE index 4f2e74a..0c69173 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -24,7 +24,6 @@ importFrom(glue,glue_collapse) importFrom(httptest2,use_httptest2) importFrom(lubridate,now) importFrom(lubridate,parse_date_time) -importFrom(nectar,call_api) importFrom(nectar,stabilize_string) importFrom(purrr,discard) importFrom(purrr,imap) diff --git a/R/beekeeper-package.R b/R/beekeeper-package.R index c83493f..ccef5d8 100644 --- a/R/beekeeper-package.R +++ b/R/beekeeper-package.R @@ -19,7 +19,6 @@ #' @importFrom httptest2 use_httptest2 #' @importFrom lubridate now #' @importFrom lubridate parse_date_time -#' @importFrom nectar call_api #' @importFrom nectar stabilize_string #' @importFrom purrr discard #' @importFrom purrr imap diff --git a/R/generate_pkg-security.R b/R/generate_pkg-security.R index 70d5e00..93ed27a 100644 --- a/R/generate_pkg-security.R +++ b/R/generate_pkg-security.R @@ -2,7 +2,7 @@ security_data <- as_bk_data(security_schemes) if (length(security_data)) { security_data$security_file_path <- .bk_use_template( - template = "020-security.R", + template = "020-auth.R", data = c(security_data, api_abbr = api_abbr) ) security_data$security_signature <- .generate_security_signature( diff --git a/R/generate_pkg_main.R b/R/generate_pkg_main.R index b6990eb..01256c6 100644 --- a/R/generate_pkg_main.R +++ b/R/generate_pkg_main.R @@ -6,7 +6,7 @@ #' #' @param config_file The path to a beekeeper yaml file. #' @param pkg_agent A string to identify this package, for use in the -#' `user_agent` argument of [nectar::call_api()]. +#' `user_agent` argument of [nectar::req_setup()]. #' #' @return A character vector of paths to files that were added or updated, #' invisibly. diff --git a/inst/templates/010-call.R b/inst/templates/010-call.R index 1ec41c6..2172fbe 100644 --- a/inst/templates/010-call.R +++ b/inst/templates/010-call.R @@ -1,8 +1,14 @@ +# Set up the basic call once at package build. +{{api_abbr}}_req_base <- nectar::req_setup( + "{{base_url}}", + user_agent = "{{pkg_agent}}" +) + #' Call the {{api_title}} API #' #' Generate a request to an {{api_title}} endpoint. #' -#' @inheritParams nectar::call_api{{#security_arg_helps}} +#' @inheritParams nectar::req_modify{{#security_arg_helps}} #' @param {{name}} {{{description}}}{{/security_arg_helps}} #' #' @return The response from the endpoint. @@ -11,14 +17,14 @@ query = NULL, body = NULL, method = NULL{{#has_security}},{{{security_signature}}}{{/has_security}}) { - nectar::call_api( - base_url = "{{base_url}}", + req <- nectar::req_modify( + {{api_abbr}}_req_base, path = path, query = query, body = body, - method = method, - user_agent = "{{pkg_agent}}"{{#has_security}}, - security_fn = {{api_abbr}}_security, - security_args = list({{security_arg_list}}){{/has_security}} + method = method ) + {{#has_security}}req <- .{{api_abbr}}_req_auth(req, {{security_arg_list}}){{/has_security}} + resp <- nectar::req_perform_opinionated(req) + nectar::resp_parse(resp, response_parser = .{{api_abbr}}_response_parser) } diff --git a/inst/templates/020-security.R b/inst/templates/020-auth.R similarity index 78% rename from inst/templates/020-security.R rename to inst/templates/020-auth.R index 7034ae0..ff3f1b1 100644 --- a/inst/templates/020-security.R +++ b/inst/templates/020-auth.R @@ -6,10 +6,10 @@ # pass the same parameter in a header, possibly with a different name. Consult # the text description of authentication in your API documentation. -{{api_abbr}}_security <- function(req, {{security_arg_nulls}}) { +.{{api_abbr}}_req_auth <- function(req, {{security_arg_nulls}}) { {{#security_schemes}} if (!is.null({{arg_name}})) { - req <- {{api_abbr}}_security_{{name}}(req, {{arg_name}}) + req <- .{{api_abbr}}_req_auth_{{name}}(req, {{arg_name}}) } {{/security_schemes}} return(req) @@ -19,8 +19,8 @@ {{#description}} # {{description}} {{/description}} -{{api_abbr}}_security_{{name}} <- function(req, {{#api_key}}{{arg_name}}) { - nectar::security_api_key( +.{{api_abbr}}_req_auth_{{name}} <- function(req, {{#api_key}}{{arg_name}}) { + nectar::req_auth_api_key( req, location = "{{location}}", parameter_name = "{{parameter_name}}", diff --git a/man/generate_pkg.Rd b/man/generate_pkg.Rd index 52ea2c5..0487d99 100644 --- a/man/generate_pkg.Rd +++ b/man/generate_pkg.Rd @@ -13,7 +13,7 @@ generate_pkg( \item{config_file}{The path to a beekeeper yaml file.} \item{pkg_agent}{A string to identify this package, for use in the -\code{user_agent} argument of \code{\link[nectar:call_api]{nectar::call_api()}}.} +\code{user_agent} argument of \code{\link[nectar:req_setup]{nectar::req_setup()}}.} } \value{ A character vector of paths to files that were added or updated, diff --git a/tests/testthat/_fixtures/guru-010-call.R b/tests/testthat/_fixtures/guru-010-call.R index 814a2bb..61ca27b 100644 --- a/tests/testthat/_fixtures/guru-010-call.R +++ b/tests/testthat/_fixtures/guru-010-call.R @@ -1,8 +1,14 @@ +# Set up the basic call once at package build. +guru_req_base <- nectar::req_setup( + "https://api.apis.guru/v2", + user_agent = "TESTPKG (https://example.com)" +) + #' Call the APIs.guru API #' #' Generate a request to an APIs.guru endpoint. #' -#' @inheritParams nectar::call_api +#' @inheritParams nectar::req_modify #' #' @return The response from the endpoint. #' @export @@ -10,12 +16,14 @@ guru_call_api <- function(path, query = NULL, body = NULL, method = NULL) { - nectar::call_api( - base_url = "https://api.apis.guru/v2", + req <- nectar::req_modify( + guru_req_base, path = path, query = query, body = body, - method = method, - user_agent = "TESTPKG (https://example.com)" + method = method ) + + resp <- nectar::req_perform_opinionated(req) + nectar::resp_parse(resp, response_parser = .guru_response_parser) } diff --git a/tests/testthat/_fixtures/trello-010-call.R b/tests/testthat/_fixtures/trello-010-call.R index 48a475d..54ae1ec 100644 --- a/tests/testthat/_fixtures/trello-010-call.R +++ b/tests/testthat/_fixtures/trello-010-call.R @@ -1,8 +1,14 @@ +# Set up the basic call once at package build. +trello_req_base <- nectar::req_setup( + "https://trello.com/1", + user_agent = "TESTPKG (https://example.com)" +) + #' Call the Trello API #' #' Generate a request to an Trello endpoint. #' -#' @inheritParams nectar::call_api +#' @inheritParams nectar::req_modify #' @param key An API key provided by the API provider. This key is not clearly documented in the API description. Check the API documentation for details. #' @param token An API key provided by the API provider. This key is not clearly documented in the API description. Check the API documentation for details. #' @@ -13,14 +19,14 @@ trello_call_api <- function(path, body = NULL, method = NULL, key = Sys.getenv("TRELLO_KEY"), token = Sys.getenv("TRELLO_TOKEN")) { - nectar::call_api( - base_url = "https://trello.com/1", + req <- nectar::req_modify( + trello_req_base, path = path, query = query, body = body, - method = method, - user_agent = "TESTPKG (https://example.com)", - security_fn = trello_security, - security_args = list(key = key, token = token) + method = method ) + req <- .trello_req_auth(req, key = key, token = token) + resp <- nectar::req_perform_opinionated(req) + nectar::resp_parse(resp, response_parser = .trello_response_parser) } diff --git a/tests/testthat/_fixtures/trello-020-security.R b/tests/testthat/_fixtures/trello-020-auth.R similarity index 77% rename from tests/testthat/_fixtures/trello-020-security.R rename to tests/testthat/_fixtures/trello-020-auth.R index 49e45bb..ce22fd8 100644 --- a/tests/testthat/_fixtures/trello-020-security.R +++ b/tests/testthat/_fixtures/trello-020-auth.R @@ -6,19 +6,19 @@ # pass the same parameter in a header, possibly with a different name. Consult # the text description of authentication in your API documentation. -trello_security <- function(req, key = NULL, token = NULL) { +.trello_req_auth <- function(req, key = NULL, token = NULL) { if (!is.null(key)) { - req <- trello_security_api_key(req, key) + req <- .trello_req_auth_api_key(req, key) } if (!is.null(token)) { - req <- trello_security_api_token(req, token) + req <- .trello_req_auth_api_token(req, token) } return(req) } # An API key provided by the API provider. This key is not clearly documented in the API description. Check the API documentation for details. -trello_security_api_key <- function(req, key) { - nectar::security_api_key( +.trello_req_auth_api_key <- function(req, key) { + nectar::req_auth_api_key( req, location = "query", parameter_name = "key", @@ -27,8 +27,8 @@ trello_security_api_key <- function(req, key) { } # An API key provided by the API provider. This key is not clearly documented in the API description. Check the API documentation for details. -trello_security_api_token <- function(req, token) { - nectar::security_api_key( +.trello_req_auth_api_token <- function(req, token) { + nectar::req_auth_api_key( req, location = "query", parameter_name = "token", diff --git a/tests/testthat/_snaps/generate_pkg-paths.md b/tests/testthat/_snaps/generate_pkg-paths.md index d821aed..4315052 100644 --- a/tests/testthat/_snaps/generate_pkg-paths.md +++ b/tests/testthat/_snaps/generate_pkg-paths.md @@ -4,7 +4,7 @@ scrub_path(changed_files) Output [1] "/R/010-call.R" "/tests/testthat/test-010-call.R" - [3] "/R/020-security.R" "/R/paths-audit.R" + [3] "/R/020-auth.R" "/R/paths-audit.R" [5] "/tests/testthat/test-paths-audit.R" "/R/paths-legal.R" [7] "/tests/testthat/test-paths-legal.R" "/R/paths-debts.R" [9] "/tests/testthat/test-paths-debts.R" "/tests/testthat/setup.R" diff --git a/tests/testthat/test-generate_pkg-security.R b/tests/testthat/test-generate_pkg-security.R index ded6de8..c3bff50 100644 --- a/tests/testthat/test-generate_pkg-security.R +++ b/tests/testthat/test-generate_pkg-security.R @@ -28,7 +28,7 @@ test_that("generate_pkg() generates security functions", { ) config <- readLines(test_path("_fixtures", "trello_beekeeper.yml")) trello_rapid <- readRDS(test_path("_fixtures", "trello_rapid.rds")) - security_expected <- readLines(test_path("_fixtures", "trello-020-security.R")) + security_expected <- readLines(test_path("_fixtures", "trello-020-auth.R")) create_local_package() writeLines(config, "_beekeeper.yml") @@ -36,6 +36,6 @@ test_that("generate_pkg() generates security functions", { generate_pkg(pkg_agent = "TESTPKG (https://example.com)") - security_result <- scrub_testpkg(readLines("R/020-security.R")) + security_result <- scrub_testpkg(readLines("R/020-auth.R")) expect_identical(security_result, security_expected) }) diff --git a/vignettes/beekeeper.Rmd b/vignettes/beekeeper.Rmd index b473e94..99794ce 100644 --- a/vignettes/beekeeper.Rmd +++ b/vignettes/beekeeper.Rmd @@ -44,7 +44,7 @@ url("https://api.apis.guru/v2/openapi.yaml") |> api_abbr = "guru" ) -# Or for the FEC +# Or for the FEC API url("https://api.apis.guru/v2/specs/fec.gov/1.0/openapi.yaml") |> use_beekeeper( api_abbr = "fec" @@ -68,15 +68,21 @@ generate_pkg() ### 010-call.R -The main file generated for the package is `R/010-call.R`. +The first file generated for the package is `R/010-call.R`. This file defines a function that can be used to call the API. ```{r fec_call_api} +# Set up the basic call once at package build. +fec_req_base <- nectar::req_setup( + "https://api.open.fec.gov/v1", + user_agent = "fecapi (https://github.com/jonthegeek/fecapi)" +) + #' Call the OpenFEC API #' #' Generate a request to an OpenFEC endpoint. #' -#' @inheritParams nectar::call_api +#' @inheritParams nectar::req_modify #' @param api_key An API key provided by the API provider. This key is not #' clearly documented in the API description. Check the API documentation for #' details. @@ -88,28 +94,29 @@ fec_call_api <- function(path, body = NULL, method = NULL, api_key = Sys.getenv("FEC_API_KEY")) { - nectar::call_api( - base_url = "https://api.open.fec.gov/v1", + req <- nectar::req_modify( + fec_req_base, path = path, query = query, body = body, - method = method, - user_agent = "fecapi (https://github.com/jonthegeek/fecapi)", - security_fn = fec_security, - security_args = list(api_key = api_key) + method = method ) + req <- .fec_req_auth(req, api_key = api_key) + resp <- nectar::req_perform_opinionated(req) + nectar::resp_parse(resp, response_parser = .fec_response_parser) } ``` -Notice that the function includes API-key security arguments when appropriate! +Notice that the function includes API-key authentication arguments when appropriate! -### 020-security.R +### 020-auth.R -Security for the API is defined in `R/020-security.R`. +Security for the API is defined in `R/020-auth.R`. The initial version of this file works, but you may want to edit the automatic output. -In the case of the OpenFEC API, the description specifies three security schemes that overlap with one another: two that set an `api_key` in the query string, and one that sets an `X-Api-Key` field in the header. +In the case of the OpenFEC API, the description specifies three security schemes that overlap with one another: one that sets an `X-Api-Key` field in the header, and two that set an `api_key` in the query string. +The names of the generated functions are based on the names of the security schemes in the OpenAPI document. -```{r fec_security} +```{r fec_auth} # These functions were generated by the {beekeeper} package, based on # components@security_schemes from the source API description. You may want to # delete unused options. In addition, APIs often have additional security @@ -118,17 +125,19 @@ In the case of the OpenFEC API, the description specifies three security schemes # pass the same parameter in a header, possibly with a different name. Consult # the text description of authentication in your API documentation. -fec_security <- function(req, api_key) { - req <- fec_security_api_key_header_auth(req, api_key) - req <- fec_security_api_key_query_auth(req, api_key) - req <- fec_security_api_key(req, api_key) +.fec_req_auth <- function(req, api_key = NULL) { + if (!is.null(api_key)) { + req <- .fec_req_auth_api_key_header_auth(req, api_key) + req <- .fec_req_auth_api_key_query_auth(req, api_key) + req <- .fec_req_auth_api_key(req, api_key) + } return(req) } # An API key provided by the API provider. This key is not clearly documented in # the API description. Check the API documentation for details. -fec_security_api_key_header_auth <- function(req, api_key) { - nectar::security_api_key( +.fec_req_auth_api_key_header_auth <- function(req, api_key) { + nectar::req_auth_api_key( req, location = "header", parameter_name = "X-Api-Key", @@ -138,8 +147,8 @@ fec_security_api_key_header_auth <- function(req, api_key) { # An API key provided by the API provider. This key is not clearly documented in # the API description. Check the API documentation for details. -fec_security_api_key_query_auth <- function(req, api_key) { - nectar::security_api_key( +.fec_req_auth_api_key_query_auth <- function(req, api_key) { + nectar::req_auth_api_key( req, location = "query", parameter_name = "api_key", @@ -149,8 +158,8 @@ fec_security_api_key_query_auth <- function(req, api_key) { # An API key provided by the API provider. This key is not clearly documented in # the API description. Check the API documentation for details. -fec_security_api_key <- function(req, api_key) { - nectar::security_api_key( +.fec_req_auth_api_key <- function(req, api_key) { + nectar::req_auth_api_key( req, location = "query", parameter_name = "api_key", @@ -160,6 +169,7 @@ fec_security_api_key <- function(req, api_key) { ``` For the real package, I deleted the two `query` functions, since the `header` function is sufficient and slightly more secure. +I also renamed the `header` function from `.fec_req_auth_api_key_header_auth` to `.fec_req_auth_api_key_header` to remove the redundant `_auth`. ### test files