From f8a7dbf64923581415403372fd58045e32238652 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 6 Jan 2025 15:46:59 -0600 Subject: [PATCH] Soft deprecate `req_url_path_*()` Since `req_url_relative()` is a more general interface. And improve `req_url()` docs, links, and examples. Part of #625 --- NEWS.md | 1 + R/iterate-helpers.R | 2 +- R/iterate-responses.R | 12 +++-- R/iterate.R | 2 +- R/multi-req.R | 26 ++++------ R/req-auth-aws.R | 2 +- R/req-body.R | 2 +- R/req-cookies.R | 2 +- R/req-error.R | 2 +- R/req-perform-connection.R | 2 +- R/req-perform-stream.R | 2 +- R/req-promise.R | 31 ++++++----- R/req-template.R | 8 +-- R/req-url-path.R | 54 +++++++++++++++++++ R/req-url.R | 66 ++++++------------------ R/req.R | 2 +- R/resp-url.R | 2 +- R/resp.R | 2 +- man/req_perform_promise.Rd | 18 ++++--- man/req_url.Rd | 49 +++++++----------- man/req_url_path.Rd | 40 ++++++++++++++ man/resp_stream_raw.Rd | 2 +- tests/testthat/_snaps/req-url-path.md | 15 ++++++ tests/testthat/test-iterate.R | 8 +-- tests/testthat/test-req-cookies.R | 5 +- tests/testthat/test-req-perform-stream.R | 2 +- tests/testthat/test-req-perform.R | 4 +- tests/testthat/test-req-template.R | 12 ++++- tests/testthat/test-req-url-path.R | 57 ++++++++++++++++++++ tests/testthat/test-req-url.R | 38 -------------- 30 files changed, 290 insertions(+), 180 deletions(-) create mode 100644 R/req-url-path.R create mode 100644 man/req_url_path.Rd create mode 100644 tests/testthat/_snaps/req-url-path.md create mode 100644 tests/testthat/test-req-url-path.R diff --git a/NEWS.md b/NEWS.md index a9c408f0..2be86593 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # httr2 (development version) +* `req_url_path()` and `req_url_path_append()` are (soft) deprecated in favour of `req_url_relative()`. * `curl_transform()` will now use `req_body_json_modify()` for JSON data (#258). * `resp_stream_is_complete()` tells you if there is still data remaining to be streamed (#559). * New `url_modify()`, `url_modify_query()`, and `url_modify_relative()` make it easier to modify an existing url (#464). diff --git a/R/iterate-helpers.R b/R/iterate-helpers.R index 95a55a99..a84322df 100644 --- a/R/iterate-helpers.R +++ b/R/iterate-helpers.R @@ -26,7 +26,7 @@ #' @export #' @examples #' req <- request(example_url()) |> -#' req_url_path("/iris") |> +#' req_url_relative("/iris") |> #' req_throttle(10) |> #' req_url_query(limit = 50) #' diff --git a/R/iterate-responses.R b/R/iterate-responses.R index 09a82248..a9963f23 100644 --- a/R/iterate-responses.R +++ b/R/iterate-responses.R @@ -18,8 +18,8 @@ #' returns the data found inside that response as a vector or data frame. #' @examples #' reqs <- list( -#' request(example_url()) |> req_url_path("/ip"), -#' request(example_url()) |> req_url_path("/user-agent"), +#' request(example_url()) |> req_url_relative("/ip"), +#' request(example_url()) |> req_url_relative("/user-agent"), #' request(example_url()) |> req_template("/status/:status", status = 404), #' request("INVALID") #' ) @@ -29,10 +29,14 @@ #' resps |> resps_successes() #' #' # collect all their data -#' resps |> resps_successes() |> resps_data(\(resp) resp_body_json(resp)) +#' resps |> +#' resps_successes() |> +#' resps_data(\(resp) resp_body_json(resp)) #' #' # find requests corresponding to failure responses -#' resps |> resps_failures() |> resps_requests() +#' resps |> +#' resps_failures() |> +#' resps_requests() resps_successes <- function(resps) { resps[resps_ok(resps)] } diff --git a/R/iterate.R b/R/iterate.R index b61037a5..7ea72b68 100644 --- a/R/iterate.R +++ b/R/iterate.R @@ -88,7 +88,7 @@ #' @export #' @examples #' req <- request(example_url()) |> -#' req_url_path("/iris") |> +#' req_url_relative("/iris") |> #' req_throttle(10) |> #' req_url_query(limit = 5) #' diff --git a/R/multi-req.R b/R/multi-req.R index 9cb4beb4..7e578ae1 100644 --- a/R/multi-req.R +++ b/R/multi-req.R @@ -26,18 +26,18 @@ #' # Requesting these 4 pages one at a time would take 2 seconds: #' request_base <- request(example_url()) #' reqs <- list( -#' request_base |> req_url_path("/delay/0.5"), -#' request_base |> req_url_path("/delay/0.5"), -#' request_base |> req_url_path("/delay/0.5"), -#' request_base |> req_url_path("/delay/0.5") +#' request_base |> req_url_relative("/delay/0.5"), +#' request_base |> req_url_relative("/delay/0.5"), +#' request_base |> req_url_relative("/delay/0.5"), +#' request_base |> req_url_relative("/delay/0.5") #' ) #' # But it's much faster if you request in parallel #' system.time(resps <- req_perform_parallel(reqs)) #' #' # req_perform_parallel() will fail on error #' reqs <- list( -#' request_base |> req_url_path("/status/200"), -#' request_base |> req_url_path("/status/400"), +#' request_base |> req_url_relative("/status/200"), +#' request_base |> req_url_relative("/status/400"), #' request("FAILURE") #' ) #' try(resps <- req_perform_parallel(reqs)) @@ -49,7 +49,9 @@ #' resps |> resps_successes() #' #' # And the failed responses -#' resps |> resps_failures() |> resps_requests() +#' resps |> +#' resps_failures() |> +#' resps_requests() req_perform_parallel <- function(reqs, paths = NULL, pool = NULL, @@ -125,9 +127,9 @@ pool_run <- function(pool, perfs, on_error = "continue") { # signal (not error) that wraps the error. Here we catch that error and # handle it based on the value of `on_error` httr2_fail <- switch(on_error, - stop = function(cnd) cnd_signal(cnd$error), + stop = function(cnd) cnd_signal(cnd$error), continue = function(cnd) zap(), - return = function(cnd) NULL + return = function(cnd) NULL ) try_fetch( @@ -149,13 +151,11 @@ Performance <- R6Class("Performance", public = list( req = NULL, req_prep = NULL, path = NULL, - handle = NULL, resp = NULL, pool = NULL, error_call = NULL, progress = NULL, - initialize = function(req, path = NULL, progress = NULL, error_call = NULL) { self$req <- req self$path <- path @@ -172,7 +172,6 @@ Performance <- R6Class("Performance", public = list( curl::handle_setopt(self$handle, url = req$url) } }, - submit = function(pool = NULL) { if (!is.null(self$resp)) { # cached @@ -189,7 +188,6 @@ Performance <- R6Class("Performance", public = list( ) invisible(self) }, - succeed = function(res) { self$progress$update() req_completed(self$req_prep) @@ -220,7 +218,6 @@ Performance <- R6Class("Performance", public = list( signal("", error = self$resp, class = "httr2_fail") } }, - fail = function(msg) { self$progress$update() req_completed(self$req_prep) @@ -233,7 +230,6 @@ Performance <- R6Class("Performance", public = list( ) signal("", error = self$resp, class = "httr2_fail") }, - cancel = function() { # No handle if response was cached if (!is.null(self$handle)) { diff --git a/R/req-auth-aws.R b/R/req-auth-aws.R index 43f48e8e..c9f8179b 100644 --- a/R/req-auth-aws.R +++ b/R/req-auth-aws.R @@ -14,7 +14,7 @@ #' model_id <- "anthropic.claude-3-5-sonnet-20240620-v1:0" #' req <- request("https://bedrock-runtime.us-east-1.amazonaws.com") #' # https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html -#' req <- req_url_path_append(req, "model", model_id, "converse") +#' req <- req_template(req, "model/:model_id/converse") #' req <- req_body_json(req, list( #' messages = list(list( #' role = "user", diff --git a/R/req-body.R b/R/req-body.R index 6f63e675..f157a102 100644 --- a/R/req-body.R +++ b/R/req-body.R @@ -16,7 +16,7 @@ #' @returns A modified HTTP [request]. #' @examples #' req <- request(example_url()) |> -#' req_url_path("/post") +#' req_url_relative("/post") #' #' # Most APIs expect small amounts of data in either form or json encoded: #' req |> diff --git a/R/req-cookies.R b/R/req-cookies.R index 65e13159..211b5ba4 100644 --- a/R/req-cookies.R +++ b/R/req-cookies.R @@ -37,7 +37,7 @@ #' #' # Add a client side cookie #' request(example_url()) |> -#' req_url_path("/cookies/set") |> +#' req_url_relative("/cookies/set") |> #' req_cookie_preserve(path) |> #' req_cookies_set(snicker = "doodle") |> #' req_perform() |> diff --git a/R/req-error.R b/R/req-error.R index 008205e8..03114124 100644 --- a/R/req-error.R +++ b/R/req-error.R @@ -60,7 +60,7 @@ #' # Performing this request usually generates an error because httr2 #' # converts HTTP errors into R errors: #' req <- request(example_url()) |> -#' req_url_path("/status/404") +#' req_url_relative("/status/404") #' try(req |> req_perform()) #' # You can still retrieve it with last_response() #' last_response() diff --git a/R/req-perform-connection.R b/R/req-perform-connection.R index d8baf479..2c4c34ab 100644 --- a/R/req-perform-connection.R +++ b/R/req-perform-connection.R @@ -23,7 +23,7 @@ #' @export #' @examples #' req <- request(example_url()) |> -#' req_url_path("/stream-bytes/32768") +#' req_url_relative("/stream-bytes/32768") #' resp <- req_perform_connection(req) #' #' length(resp_stream_raw(resp, kb = 16)) diff --git a/R/req-perform-stream.R b/R/req-perform-stream.R index 0f9cd42e..b03225a7 100644 --- a/R/req-perform-stream.R +++ b/R/req-perform-stream.R @@ -29,7 +29,7 @@ #' TRUE #' } #' resp <- request(example_url()) |> -#' req_url_path("/stream-bytes/100000") |> +#' req_url_relative("/stream-bytes/100000") |> #' req_perform_stream(show_bytes, buffer_kb = 32) #' resp req_perform_stream <- function(req, diff --git a/R/req-promise.R b/R/req-promise.R index f157e134..e0e84e75 100644 --- a/R/req-promise.R +++ b/R/req-promise.R @@ -37,9 +37,11 @@ #' @examples #' \dontrun{ #' library(promises) -#' request_base <- request(example_url()) |> req_url_path_append("delay") +#' req <- request(example_url()) #' -#' p <- request_base |> req_url_path_append(2) |> req_perform_promise() +#' p <- req |> +#' req_url_relative("delay/1") |> +#' req_perform_promise() #' #' # A promise object, not particularly useful on its own #' p @@ -51,8 +53,12 @@ #' #' #' # Can run two requests at the same time -#' p1 <- request_base |> req_url_path_append(2) |> req_perform_promise() -#' p2 <- request_base |> req_url_path_append(1) |> req_perform_promise() +#' p1 <- req |> +#' req_url_relative("delay/1") |> +#' req_perform_promise() +#' p2 <- req |> +#' req_url_relative("delay/1") |> +#' req_perform_promise() #' #' p1 %...>% #' resp_url_path %...>% @@ -97,11 +103,11 @@ req_perform_promise <- function(req, ) } -PerformancePromise <- R6Class("PerformancePromise", inherit = Performance, +PerformancePromise <- R6Class("PerformancePromise", + inherit = Performance, public = list( resolve = NULL, reject = NULL, - initialize = function(req, resolve, reject, path = NULL, error_call = NULL) { progress <- create_progress_bar(config = FALSE) @@ -109,7 +115,6 @@ PerformancePromise <- R6Class("PerformancePromise", inherit = Performance, self$resolve <- resolve self$reject <- reject }, - submit = function(pool = NULL) { if (!is.null(self$resp)) { # cached @@ -119,7 +124,6 @@ PerformancePromise <- R6Class("PerformancePromise", inherit = Performance, super$submit(pool) ensure_pool_poller(pool, self$reject) }, - succeed = function(res) { tryCatch( { @@ -130,7 +134,6 @@ PerformancePromise <- R6Class("PerformancePromise", inherit = Performance, error = function(cnd) self$reject(cnd) ) }, - fail = function(msg) { tryCatch( super$fail(msg), @@ -138,11 +141,14 @@ PerformancePromise <- R6Class("PerformancePromise", inherit = Performance, error = function(cnd) self$reject(cnd) ) } - )) + ) +) ensure_pool_poller <- function(pool, reject) { monitor <- pool_poller_monitor(pool) - if (monitor$already_going()) return() + if (monitor$already_going()) { + return() + } poll_pool <- function(ready) { tryCatch( @@ -160,7 +166,8 @@ ensure_pool_poller <- function(pool, reject) { } else { monitor$ending() } - }, error = function(cnd) { + }, + error = function(cnd) { monitor$ending() reject(cnd) } diff --git a/R/req-template.R b/R/req-template.R index a16c2a94..603c711a 100644 --- a/R/req-template.R +++ b/R/req-template.R @@ -29,7 +29,7 @@ #' httpbin |> req_template("GET /bytes/{n}") #' #' # Existing path is preserved: -#' httpbin_test <- request(example_url()) |> req_url_path("/test") +#' httpbin_test <- request(example_url()) |> req_url_relative("/test") #' name <- "id" #' value <- "a3fWa" #' httpbin_test |> req_template("GET /set/{name}/{value}") @@ -56,7 +56,7 @@ req_template <- function(req, template, ..., .env = parent.frame()) { } path <- template_process(template, dots, .env) - req_url_path_append(req, path) + req_url_relative(req, path) } template_process <- function(template, @@ -99,7 +99,9 @@ template_val <- function(name, dots, env, error_call = caller_env()) { } template_vars <- function(x, type) { - if (type == "none") return(character()) + if (type == "none") { + return(character()) + } pattern <- switch(type, colon = ":([a-zA-Z0-9_]+)", diff --git a/R/req-url-path.R b/R/req-url-path.R new file mode 100644 index 00000000..a79dcd9d --- /dev/null +++ b/R/req-url-path.R @@ -0,0 +1,54 @@ +#' Modify URL path +#' +#' @description +#' `r lifecycle::badge("deprecated")` +#' +#' * `req_url_path()` modifies the path. +#' * `req_url_path_append()` adds to the path. +#' +#' Please use [req_url_relative()] instead. +#' +#' @inheritParams req_perform +#' @param ... For `req_url_path()` and `req_url_path_append()`: A sequence of +#' path components that will be combined with `/`. +#' @returns A modified HTTP [request]. +#' @export +#' @examples +#' req <- request("http://example.com/a/b/c") +#' +#' # OLD +#' req |> req_url_path("/d/e/f") +#' req |> req_url_path_append("d/e/f") +#' +#' # NEW +#' req |> req_url_relative("/d/e/f") +#' req |> req_url_relative("d/e/f") +req_url_path <- function(req, ...) { + lifecycle::deprecate_soft("1.1.0", "req_url_path()", "req_url_relative()") + + check_request(req) + path <- dots_to_path(...) + + req_url(req, url_modify(req$url, path = path)) +} + +#' @export +#' @rdname req_url_path +req_url_path_append <- function(req, ...) { + lifecycle::deprecate_soft("1.1.0", "req_url_path_append()", "req_url_relative()") + + check_request(req) + path <- dots_to_path(...) + + url <- url_parse(req$url) + url$path <- paste0(sub("/$", "", url$path), path) + + req_url(req, url_build(url)) +} + +dots_to_path <- function(...) { + path <- paste(c(...), collapse = "/") + # Ensure we don't add duplicate /s + # NB: also keeps "" unchanged. + sub("^([^/])", "/\\1", path) +} diff --git a/R/req-url.R b/R/req-url.R index c6898903..a69846cd 100644 --- a/R/req-url.R +++ b/R/req-url.R @@ -1,44 +1,38 @@ #' Modify request URL #' #' @description -#' * `req_url()` replaces the entire url -#' * `req_url_query()` modifies the components of the query -#' * `req_url_path()` modifies the path -#' * `req_url_path_append()` adds to the path -#' -#' Alternatively, to modify only a URL without creating a request, -#' you can instead use [url_modify()] and friends. +#' * `req_url()` replaces the entire URL. +#' * `req_url_relative()` changes the relative path. +#' * `req_url_query()` modifies individual query parameters. #' +#' @seealso +#' * To modify a URL without creating a request, see [url_modify()] and +#' friends. +#' * To use a template like `GET /user/{user}`, see [req_template()]. #' @inheritParams req_perform #' @param url New URL; completely replaces existing. -#' @param ... For `req_url_query()`: <[`dynamic-dots`][rlang::dyn-dots]> +#' @param ... <[`dynamic-dots`][rlang::dyn-dots]> #' Name-value pairs that define query parameters. Each value must be either #' an atomic vector or `NULL` (which removes the corresponding parameters). #' If you want to opt out of escaping, wrap strings in `I()`. -#' -#' For `req_url_path()` and `req_url_path_append()`: A sequence of path -#' components that will be combined with `/`. #' @returns A modified HTTP [request]. #' @export #' @examples -#' req <- request("http://example.com") -#' -#' # Change url components -#' req |> -#' req_url_path_append("a") |> -#' req_url_path_append("b") |> -#' req_url_path_append("search.html") |> -#' req_url_query(q = "the cool ice") -#' #' # Change complete url -#' req |> -#' req_url("http://google.com") +#' req <- request("http://example.com") +#' req |> req_url("http://google.com") #' #' # Use a relative url #' req <- request("http://example.com/a/b/c") #' req |> req_url_relative("..") #' req |> req_url_relative("/d/e/f") #' +#' # Modify individual query parameters +#' req <- request("http://example.com?a=1&b=2") +#' req |> req_url_query(a = 10) +#' req |> req_url_query(a = NULL) +#' req |> req_url_query(c = 3) +#' #' # Use .multi to control what happens with vector parameters: #' req |> req_url_query(id = 100:105, .multi = "comma") #' req |> req_url_query(id = 100:105, .multi = "explode") @@ -73,31 +67,3 @@ req_url_query <- function(.req, url <- url_modify_query(.req$url, ..., .multi = .multi, .space = .space) req_url(.req, url) } - -#' @export -#' @rdname req_url -req_url_path <- function(req, ...) { - check_request(req) - path <- dots_to_path(...) - - req_url(req, url_modify(req$url, path = path)) -} - -#' @export -#' @rdname req_url -req_url_path_append <- function(req, ...) { - check_request(req) - path <- dots_to_path(...) - - url <- url_parse(req$url) - url$path <- paste0(sub("/$", "", url$path), path) - - req_url(req, url_build(url)) -} - -dots_to_path <- function(...) { - path <- paste(c(...), collapse = "/") - # Ensure we don't add duplicate /s - # NB: also keeps "" unchanged. - sub("^([^/])", "/\\1", path) -} diff --git a/R/req.R b/R/req.R index bf1687ba..f2196e67 100644 --- a/R/req.R +++ b/R/req.R @@ -6,7 +6,7 @@ #' 1. Create a request object with `request(url)` (this function). #' 2. Define its behaviour with `req_` functions, e.g.: #' * [req_headers()] to set header values. -#' * [req_url_path()] and friends to modify the url. +#' * [req_url()] and friends to modify the url. #' * [req_body_json()] and friends to add a body. #' * [req_auth_basic()] to perform basic HTTP authentication. #' * [req_oauth_auth_code()] to use the OAuth auth code flow. diff --git a/R/resp-url.R b/R/resp-url.R index 42c67850..6f85977b 100644 --- a/R/resp-url.R +++ b/R/resp-url.R @@ -9,7 +9,7 @@ #' @export #' @examples #' resp <- request(example_url()) |> -#' req_url_path("/get?hello=world") |> +#' req_url_relative("/get?hello=world") |> #' req_perform() #' #' resp |> resp_url() diff --git a/R/resp.R b/R/resp.R index 1b31ab7b..e69ac3ed 100644 --- a/R/resp.R +++ b/R/resp.R @@ -136,7 +136,7 @@ print.httr2_response <- function(x, ...) { #' @export #' @examples #' resp <- request(example_url()) |> -#' req_url_path("/json") |> +#' req_url_relative("/json") |> #' req_perform() #' resp |> resp_raw() resp_raw <- function(resp) { diff --git a/man/req_perform_promise.Rd b/man/req_perform_promise.Rd index 0573a6d5..629c9e3d 100644 --- a/man/req_perform_promise.Rd +++ b/man/req_perform_promise.Rd @@ -49,11 +49,13 @@ is created but before it is actually requested. } } \examples{ -\dontrun{ +\dontshow{if (requireNamespace("promises")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} library(promises) -request_base <- request(example_url()) |> req_url_path_append("delay") +req <- request(example_url()) -p <- request_base |> req_url_path_append(2) |> req_perform_promise() +p <- req |> + req_url_relative("delay/2") |> + req_perform_promise() # A promise object, not particularly useful on its own p @@ -65,8 +67,12 @@ p \%...>\% # Can run two requests at the same time -p1 <- request_base |> req_url_path_append(2) |> req_perform_promise() -p2 <- request_base |> req_url_path_append(1) |> req_perform_promise() +p1 <- req |> + req_url_relative("delay/2") |> + req_perform_promise() +p2 <- req |> + req_url_relative("delay/1") |> + req_perform_promise() p1 \%...>\% resp_url_path \%...>\% @@ -80,5 +86,5 @@ p2 \%...>\% # See the [promises package documentation](https://rstudio.github.io/promises/) # for more information on working with promises -} +\dontshow{\}) # examplesIf} } diff --git a/man/req_url.Rd b/man/req_url.Rd index 9f5a50a7..a31ee8a6 100644 --- a/man/req_url.Rd +++ b/man/req_url.Rd @@ -4,8 +4,6 @@ \alias{req_url} \alias{req_url_relative} \alias{req_url_query} -\alias{req_url_path} -\alias{req_url_path_append} \title{Modify request URL} \usage{ req_url(req, url) @@ -18,23 +16,16 @@ req_url_query( .multi = c("error", "comma", "pipe", "explode"), .space = c("percent", "form") ) - -req_url_path(req, ...) - -req_url_path_append(req, ...) } \arguments{ \item{req, .req}{A httr2 \link{request} object.} \item{url}{New URL; completely replaces existing.} -\item{...}{For \code{req_url_query()}: <\code{\link[rlang:dyn-dots]{dynamic-dots}}> +\item{...}{<\code{\link[rlang:dyn-dots]{dynamic-dots}}> Name-value pairs that define query parameters. Each value must be either an atomic vector or \code{NULL} (which removes the corresponding parameters). -If you want to opt out of escaping, wrap strings in \code{I()}. - -For \code{req_url_path()} and \code{req_url_path_append()}: A sequence of path -components that will be combined with \code{/}.} +If you want to opt out of escaping, wrap strings in \code{I()}.} \item{.multi}{Controls what happens when a value is a vector: \itemize{ @@ -57,34 +48,27 @@ A modified HTTP \link{request}. } \description{ \itemize{ -\item \code{req_url()} replaces the entire url -\item \code{req_url_query()} modifies the components of the query -\item \code{req_url_path()} modifies the path -\item \code{req_url_path_append()} adds to the path +\item \code{req_url()} replaces the entire URL. +\item \code{req_url_relative()} changes the relative path. +\item \code{req_url_query()} modifies individual query parameters. } - -Alternatively, to modify only a URL without creating a request, -you can instead use \code{\link[=url_modify]{url_modify()}} and friends. } \examples{ -req <- request("http://example.com") - -# Change url components -req |> - req_url_path_append("a") |> - req_url_path_append("b") |> - req_url_path_append("search.html") |> - req_url_query(q = "the cool ice") - # Change complete url -req |> - req_url("http://google.com") +req <- request("http://example.com") +req |> req_url("http://google.com") # Use a relative url req <- request("http://example.com/a/b/c") req |> req_url_relative("..") req |> req_url_relative("/d/e/f") +# Modify individual query parameters +req <- request("http://example.com?a=1&b=2") +req |> req_url_query(a = 10) +req |> req_url_query(a = NULL) +req |> req_url_query(c = 3) + # Use .multi to control what happens with vector parameters: req |> req_url_query(id = 100:105, .multi = "comma") req |> req_url_query(id = 100:105, .multi = "explode") @@ -94,3 +78,10 @@ params <- list(a = "1", b = "2") req |> req_url_query(!!!params, c = "3") } +\seealso{ +\itemize{ +\item To modify a URL without creating a request, see \code{\link[=url_modify]{url_modify()}} and +friends. +\item To use a template like \code{GET /user/{user}}, see \code{\link[=req_template]{req_template()}}. +} +} diff --git a/man/req_url_path.Rd b/man/req_url_path.Rd new file mode 100644 index 00000000..1a13f386 --- /dev/null +++ b/man/req_url_path.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/req-url-path.R +\name{req_url_path} +\alias{req_url_path} +\alias{req_url_path_append} +\title{Modify URL path} +\usage{ +req_url_path(req, ...) + +req_url_path_append(req, ...) +} +\arguments{ +\item{req}{A httr2 \link{request} object.} + +\item{...}{For \code{req_url_path()} and \code{req_url_path_append()}: A sequence of +path components that will be combined with \code{/}.} +} +\value{ +A modified HTTP \link{request}. +} +\description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} +\itemize{ +\item \code{req_url_path()} modifies the path. +\item \code{req_url_path_append()} adds to the path. +} + +Please use \code{\link[=req_url_relative]{req_url_relative()}} instead. +} +\examples{ +req <- request("http://example.com/a/b/c") + +# OLD +req |> req_url_path("/d/e/f") +req |> req_url_path_append("d/e/f") + +# NEW +req |> req_url_relative("/d/e/f") +req |> req_url_relative("d/e/f") +} diff --git a/man/resp_stream_raw.Rd b/man/resp_stream_raw.Rd index 561b4257..2885233a 100644 --- a/man/resp_stream_raw.Rd +++ b/man/resp_stream_raw.Rd @@ -60,6 +60,6 @@ no event is currently available. (i.e. mime type `application/vnd.amazon.eventstream``). } -Use \code{resp_stream_is_complete()} to determine if there are further events +Use \code{resp_stream_is_complete()} to determine if there is further data waiting on the stream. } diff --git a/tests/testthat/_snaps/req-url-path.md b/tests/testthat/_snaps/req-url-path.md new file mode 100644 index 00000000..5a33191c --- /dev/null +++ b/tests/testthat/_snaps/req-url-path.md @@ -0,0 +1,15 @@ +# both now deprecated + + Code + . <- req_url_path(req) + Condition + Warning: + `req_url_path()` was deprecated in httr2 1.1.0. + i Please use `req_url_relative()` instead. + Code + . <- req_url_path_append(req) + Condition + Warning: + `req_url_path_append()` was deprecated in httr2 1.1.0. + i Please use `req_url_relative()` instead. + diff --git a/tests/testthat/test-iterate.R b/tests/testthat/test-iterate.R index 266ba43c..2419aee2 100644 --- a/tests/testthat/test-iterate.R +++ b/tests/testthat/test-iterate.R @@ -1,6 +1,6 @@ test_that("can perform multiple requests", { req <- request(example_url()) %>% - req_url_path("/iris") %>% + req_url_relative("/iris") %>% req_url_query(limit = 5) resps <- req_perform_iterative( @@ -15,7 +15,7 @@ test_that("can perform multiple requests", { test_that("can save results to disk", { req <- request(example_url()) %>% - req_url_path("/iris") %>% + req_url_relative("/iris") %>% req_url_query(limit = 5) dir <- withr::local_tempdir() @@ -33,7 +33,7 @@ test_that("can save results to disk", { test_that("user temination still returns data", { req <- request(example_url()) %>% - req_url_path("/iris") %>% + req_url_relative("/iris") %>% req_url_query(limit = 5) next_req <- function(resp, req) interrupt() @@ -46,7 +46,7 @@ test_that("user temination still returns data", { test_that("can retrieve all pages", { req <- request(example_url()) %>% - req_url_path("/iris") %>% + req_url_relative("/iris") %>% req_url_query(limit = 1) i <- 1 diff --git a/tests/testthat/test-req-cookies.R b/tests/testthat/test-req-cookies.R index 85d3cda4..ac9215e9 100644 --- a/tests/testthat/test-req-cookies.R +++ b/tests/testthat/test-req-cookies.R @@ -18,13 +18,12 @@ test_that("can read/write cookies", { resp_body_json() %>% .$cookies expect_mapequal(cookies, list(x = "a", y = "b", z = "c")) - }) test_that("can set cookies", { resp <- request(example_url()) %>% req_cookies_set(a = 1, b = 1) %>% - req_url_path("/cookies") %>% + req_url_relative("/cookies") %>% req_perform() expect_equal(resp_body_json(resp), list(cookies = list(a = "1", b = "1"))) @@ -33,7 +32,7 @@ test_that("can set cookies", { test_that("cookie values are usually escaped", { resp <- request(example_url()) %>% req_cookies_set(a = I("%20"), b = "%") %>% - req_url_path("/cookies") %>% + req_url_relative("/cookies") %>% req_perform() expect_equal(resp_body_json(resp), list(cookies = list(a = "%20", b = "%25"))) diff --git a/tests/testthat/test-req-perform-stream.R b/tests/testthat/test-req-perform-stream.R index b2ef3220..f3be14cc 100644 --- a/tests/testthat/test-req-perform-stream.R +++ b/tests/testthat/test-req-perform-stream.R @@ -1,5 +1,5 @@ test_that("req_stream() is deprecated", { - req <- request(example_url()) %>% req_url_path("/stream-bytes/100") + req <- request(example_url()) %>% req_url_relative("/stream-bytes/100") expect_snapshot( resp <- req_stream(req, identity, buffer_kb = 32) ) diff --git a/tests/testthat/test-req-perform.R b/tests/testthat/test-req-perform.R index 9576b25c..17810049 100644 --- a/tests/testthat/test-req-perform.R +++ b/tests/testthat/test-req-perform.R @@ -115,7 +115,7 @@ test_that("can cache requests with etags", { test_that("can cache requests with paths (cache-control)", { req <- request(example_url()) %>% - req_url_path("/cache/2") %>% + req_url_relative("/cache/2") %>% req_cache(withr::local_tempfile()) path1 <- withr::local_tempfile() @@ -147,7 +147,7 @@ test_that("can cache requests with paths (cache-control)", { test_that("can cache requests with paths (if-modified-since)", { req <- request(example_url()) %>% - req_url_path("/cache") %>% + req_url_relative("/cache") %>% req_cache(tempfile()) path1 <- tempfile() diff --git a/tests/testthat/test-req-template.R b/tests/testthat/test-req-template.R index 892970f0..543ce814 100644 --- a/tests/testthat/test-req-template.R +++ b/tests/testthat/test-req-template.R @@ -3,6 +3,16 @@ test_that("can set path", { expect_equal(req$url, "http://test.com/x") }) +test_that("respects relative path", { + req <- request("http://test.com/x/") + + req1 <- req %>% req_template("/y") + expect_equal(req1$url, "http://test.com/y") + + req2 <- req %>% req_template("y") + expect_equal(req2$url, "http://test.com/x/y") +}) + test_that("can set method and path", { req <- request("http://test.com") %>% req_template("PATCH /x") expect_equal(req$url, "http://test.com/x") @@ -19,7 +29,7 @@ test_that("can use args or env", { }) test_that("will append rather than replace path", { - req <- request("http://test.com/x") %>% req_template("PATCH /y") + req <- request("http://test.com/x/") %>% req_template("PATCH y") expect_equal(req$url, "http://test.com/x/y") }) diff --git a/tests/testthat/test-req-url-path.R b/tests/testthat/test-req-url-path.R new file mode 100644 index 00000000..bf526820 --- /dev/null +++ b/tests/testthat/test-req-url-path.R @@ -0,0 +1,57 @@ +test_that("both now deprecated", { + local_options(lifecycle_verbosity = "warning") + req <- request("http://example.com/x") + + expect_snapshot({ + . <- req_url_path(req) + . <- req_url_path_append(req) + }) +}) + + +test_that("automatically adds /", { + local_options(lifecycle_verbosity = "quiet") + + req1 <- request("http://example.com") + req2 <- request("http://example.com/") + + expect_equal(req_url_path(req1, "/index.html")$url, "http://example.com/index.html") + expect_equal(req_url_path(req1, "index.html")$url, "http://example.com/index.html") + expect_equal(req_url_path(req2, "/index.html")$url, "http://example.com/index.html") + expect_equal(req_url_path(req2, "index.html")$url, "http://example.com/index.html") + + expect_equal(req_url_path_append(req1, "index.html")$url, "http://example.com/index.html") + expect_equal(req_url_path_append(req1, "/index.html")$url, "http://example.com/index.html") + expect_equal(req_url_path_append(req2, "index.html")$url, "http://example.com/index.html") + expect_equal(req_url_path_append(req2, "/index.html")$url, "http://example.com/index.html") +}) + +test_that("can append multiple components", { + local_options(lifecycle_verbosity = "quiet") + + req <- request("http://example.com/x") + expect_equal(req_url_path(req, "a", "b")$url, "http://example.com/a/b") + expect_equal(req_url_path_append(req, "a", "b")$url, "http://example.com/x/a/b") +}) + +test_that("can handle empty path", { + local_options(lifecycle_verbosity = "quiet") + + req <- request("http://example.com/x") + expect_equal(req_url_path(req)$url, "http://example.com/") + expect_equal(req_url_path_append(req)$url, "http://example.com/x") + expect_equal(req_url_path(req, NULL)$url, "http://example.com/") + expect_equal(req_url_path_append(req, NULL)$url, "http://example.com/x") + + expect_equal(req_url_path(req, "")$url, "http://example.com/") + expect_equal(req_url_path_append(req, "")$url, "http://example.com/x") +}) + +test_that("can handle path vector", { + local_options(lifecycle_verbosity = "quiet") + + req <- request("http://example.com/x") + expect_equal(req_url_path(req, c("a", "b"))$url, "http://example.com/a/b") + expect_equal(req_url_path_append(req, c("a", "b"))$url, "http://example.com/x/a/b") + expect_equal(req_url_path_append(req, c("a", "b"), NULL)$url, "http://example.com/x/a/b") +}) diff --git a/tests/testthat/test-req-url.R b/tests/testthat/test-req-url.R index 759c33a8..f0af0eea 100644 --- a/tests/testthat/test-req-url.R +++ b/tests/testthat/test-req-url.R @@ -3,44 +3,6 @@ test_that("can override url", { expect_equal(req_url(req, "http://foo.com:10")$url, "http://foo.com:10") }) -test_that("automatically adds /", { - req1 <- request("http://example.com") - req2 <- request("http://example.com/") - - expect_equal(req_url_path(req1, "/index.html")$url, "http://example.com/index.html") - expect_equal(req_url_path(req1, "index.html")$url, "http://example.com/index.html") - expect_equal(req_url_path(req2, "/index.html")$url, "http://example.com/index.html") - expect_equal(req_url_path(req2, "index.html")$url, "http://example.com/index.html") - - expect_equal(req_url_path_append(req1, "index.html")$url, "http://example.com/index.html") - expect_equal(req_url_path_append(req1, "/index.html")$url, "http://example.com/index.html") - expect_equal(req_url_path_append(req2, "index.html")$url, "http://example.com/index.html") - expect_equal(req_url_path_append(req2, "/index.html")$url, "http://example.com/index.html") -}) - -test_that("can append multiple components", { - req <- request("http://example.com/x") - expect_equal(req_url_path(req, "a", "b")$url, "http://example.com/a/b") - expect_equal(req_url_path_append(req, "a", "b")$url, "http://example.com/x/a/b") -}) - -test_that("can handle empty path", { - req <- request("http://example.com/x") - expect_equal(req_url_path(req)$url, "http://example.com/") - expect_equal(req_url_path_append(req)$url, "http://example.com/x") - expect_equal(req_url_path(req, NULL)$url, "http://example.com/") - expect_equal(req_url_path_append(req, NULL)$url, "http://example.com/x") - - expect_equal(req_url_path(req, "")$url, "http://example.com/") - expect_equal(req_url_path_append(req, "")$url, "http://example.com/x") -}) - -test_that("can handle path vector", { - req <- request("http://example.com/x") - expect_equal(req_url_path(req, c("a", "b"))$url, "http://example.com/a/b") - expect_equal(req_url_path_append(req, c("a", "b"))$url, "http://example.com/x/a/b") - expect_equal(req_url_path_append(req, c("a", "b"), NULL)$url, "http://example.com/x/a/b") -}) test_that("can set query params", { req <- request("http://example.com/")