Skip to content

Commit

Permalink
Soft deprecate req_url_path_*()
Browse files Browse the repository at this point in the history
Since `req_url_relative()` is a more general interface. And improve `req_url()` docs, links, and examples.

Part of #625
  • Loading branch information
hadley committed Jan 6, 2025
1 parent cd9786d commit f8a7dbf
Show file tree
Hide file tree
Showing 30 changed files with 290 additions and 180 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -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).
Expand Down
2 changes: 1 addition & 1 deletion R/iterate-helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)
#'
Expand Down
12 changes: 8 additions & 4 deletions R/iterate-responses.R
Original file line number Diff line number Diff line change
Expand Up @@ -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")
#' )
Expand All @@ -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)]
}
Expand Down
2 changes: 1 addition & 1 deletion R/iterate.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)
#'
Expand Down
26 changes: 11 additions & 15 deletions R/multi-req.R
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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,
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand All @@ -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
Expand All @@ -189,7 +188,6 @@ Performance <- R6Class("Performance", public = list(
)
invisible(self)
},

succeed = function(res) {
self$progress$update()
req_completed(self$req_prep)
Expand Down Expand Up @@ -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)
Expand All @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion R/req-auth-aws.R
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion R/req-body.R
Original file line number Diff line number Diff line change
Expand Up @@ -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 |>
Expand Down
2 changes: 1 addition & 1 deletion R/req-cookies.R
Original file line number Diff line number Diff line change
Expand Up @@ -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() |>
Expand Down
2 changes: 1 addition & 1 deletion R/req-error.R
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion R/req-perform-connection.R
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion R/req-perform-stream.R
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
31 changes: 19 additions & 12 deletions R/req-promise.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 %...>%
Expand Down Expand Up @@ -97,19 +103,18 @@ 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)

super$initialize(req = req, path = path, progress = progress, error_call = error_call)
self$resolve <- resolve
self$reject <- reject
},

submit = function(pool = NULL) {
if (!is.null(self$resp)) {
# cached
Expand All @@ -119,7 +124,6 @@ PerformancePromise <- R6Class("PerformancePromise", inherit = Performance,
super$submit(pool)
ensure_pool_poller(pool, self$reject)
},

succeed = function(res) {
tryCatch(
{
Expand All @@ -130,19 +134,21 @@ PerformancePromise <- R6Class("PerformancePromise", inherit = Performance,
error = function(cnd) self$reject(cnd)
)
},

fail = function(msg) {
tryCatch(
super$fail(msg),
httr2_fail = function(cnd) self$reject(cnd$error),
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()

Check warning on line 150 in R/req-promise.R

View check run for this annotation

Codecov / codecov/patch

R/req-promise.R#L149-L150

Added lines #L149 - L150 were not covered by tests
}

poll_pool <- function(ready) {
tryCatch(
Expand All @@ -160,7 +166,8 @@ ensure_pool_poller <- function(pool, reject) {
} else {
monitor$ending()
}
}, error = function(cnd) {
},
error = function(cnd) {

Check warning on line 170 in R/req-promise.R

View check run for this annotation

Codecov / codecov/patch

R/req-promise.R#L169-L170

Added lines #L169 - L170 were not covered by tests
monitor$ending()
reject(cnd)
}
Expand Down
8 changes: 5 additions & 3 deletions R/req-template.R
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand All @@ -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,
Expand Down Expand Up @@ -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_]+)",
Expand Down
54 changes: 54 additions & 0 deletions R/req-url-path.R
Original file line number Diff line number Diff line change
@@ -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)
}
Loading

0 comments on commit f8a7dbf

Please sign in to comment.