diff --git a/NAMESPACE b/NAMESPACE index 491c8342..afb2f560 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -96,6 +96,10 @@ export(resp_raw) export(resp_retry_after) export(resp_status) export(resp_status_desc) +export(resp_url) +export(resp_url_path) +export(resp_url_queries) +export(resp_url_query) export(response) export(secret_decrypt) export(secret_encrypt) diff --git a/NEWS.md b/NEWS.md index f44f05f6..502d930c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,12 @@ * New `req_cookie_file()` lets you use a file to share cookies across requests (#223). +* New `resp_url()`, `resp_url_path()`, `resp_url_queries()` and + `resp_url_query()` to extract various part of the response url (#57). + +* Progress bars displayed while waiting for some time to pass are now + more informative (#206). + * `url_build()` automatically adds leading `/` to `path` if missing (#276). * Cached responses now combine the headers of the new response with the headers diff --git a/R/req-cache.R b/R/req-cache.R index 4692fba5..1fff6983 100644 --- a/R/req-cache.R +++ b/R/req-cache.R @@ -15,7 +15,11 @@ #' [HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching). #' #' @inheritParams req_perform -#' @param path Path to cache directory +#' @param path Path to cache directory. +#' +#' httr2 doesn't provide helpers to manage the cache, but if you want to +#' empty it, you can use something like +#' `unlink(dir(cache_path, full.names = TRUE))`. #' @param use_on_error If the request errors, and there's a cache response, #' should `req_perform()` return that instead of generating an error? #' @param debug When `TRUE` will emit useful messages telling you about diff --git a/R/req-perform.R b/R/req-perform.R index 93cfab11..93558202 100644 --- a/R/req-perform.R +++ b/R/req-perform.R @@ -86,7 +86,7 @@ req_perform <- function( delay <- 0 while(tries < max_tries && Sys.time() < deadline) { - sys_sleep(delay) + sys_sleep(delay, "for retry backoff") n <- n + 1 resp <- tryCatch( diff --git a/R/req-throttle.R b/R/req-throttle.R index c96b067f..91a353c5 100644 --- a/R/req-throttle.R +++ b/R/req-throttle.R @@ -39,7 +39,7 @@ req_throttle <- function(req, rate, realm = NULL) { wait <- delay - (unix_time() - last) } - sys_sleep(wait) + sys_sleep(wait, "for throttling delay") throttle_touch(realm) wait } diff --git a/R/resp-url.R b/R/resp-url.R new file mode 100644 index 00000000..6fb84c71 --- /dev/null +++ b/R/resp-url.R @@ -0,0 +1,48 @@ +#' Get URL/components from the response +#' +#' * `resp_url()` returns the complete url. +#' * `resp_url_path()` returns the path component. +#' * `resp_url_query()` returns a single query component. +#' * `resp_url_queries()` returns the query component as a named list. +#' +#' @inheritParams resp_header +#' @export +#' @examples +#' req <- request("https://httr2.r-lib.org?hello=world") +#' +#' resp <- req_perform(req) +#' resp %>% resp_url() +#' resp %>% resp_url_path() +#' resp %>% resp_url_query() +resp_url <- function(resp) { + check_response(resp) + + resp$url +} + +#' @export +#' @rdname resp_url +resp_url_path <- function(resp) { + check_response(resp) + + url_parse(resp$url)$path +} + +#' @export +#' @rdname resp_url +#' @param name Query parameter name. +#' @param default Default value to use if query parameter doesn't exist. +resp_url_query <- function(resp, name, default = NULL) { + check_response(resp) + + resp_url_queries(resp)[[name]] %||% default +} + +#' @export +#' @rdname resp_url +resp_url_queries <- function(resp) { + check_response(resp) + + url_parse(resp$url)$query +} + diff --git a/R/utils.R b/R/utils.R index 7ead6fd6..fb8ee86c 100644 --- a/R/utils.R +++ b/R/utils.R @@ -40,8 +40,8 @@ modify_list <- function(.x, ..., error_call = caller_env()) { } -sys_sleep <- function(seconds, fps = 10, error_call = caller_env()) { - check_number_decimal(seconds, call = error_call) +sys_sleep <- function(seconds, task, fps = 10) { + check_number_decimal(seconds) if (seconds == 0) { return(invisible()) @@ -51,7 +51,7 @@ sys_sleep <- function(seconds, fps = 10, error_call = caller_env()) { signal("", class = "httr2_sleep", seconds = seconds) cli::cli_progress_bar( - format = "Waiting {round(seconds)}s to retry {cli::pb_bar}", + format = "Waiting {round(seconds)}s {task} {cli::pb_bar}", total = seconds * fps ) diff --git a/man/req_cache.Rd b/man/req_cache.Rd index 67616a7e..07dafdc0 100644 --- a/man/req_cache.Rd +++ b/man/req_cache.Rd @@ -9,7 +9,11 @@ req_cache(req, path, use_on_error = FALSE, debug = FALSE) \arguments{ \item{req}{A \link{request}.} -\item{path}{Path to cache directory} +\item{path}{Path to cache directory. + +httr2 doesn't provide helpers to manage the cache, but if you want to +empty it, you can use something like +\code{unlink(dir(cache_path, full.names = TRUE))}.} \item{use_on_error}{If the request errors, and there's a cache response, should \code{req_perform()} return that instead of generating an error?} diff --git a/man/resp_url.Rd b/man/resp_url.Rd new file mode 100644 index 00000000..7463937d --- /dev/null +++ b/man/resp_url.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/resp-url.R +\name{resp_url} +\alias{resp_url} +\alias{resp_url_path} +\alias{resp_url_query} +\alias{resp_url_queries} +\title{Get URL/components from the response} +\usage{ +resp_url(resp) + +resp_url_path(resp) + +resp_url_query(resp, name, default = NULL) + +resp_url_queries(resp) +} +\arguments{ +\item{resp}{An HTTP response object, as created by \code{\link[=req_perform]{req_perform()}}.} + +\item{name}{Query parameter name.} + +\item{default}{Default value to use if query parameter doesn't exist.} +} +\description{ +\itemize{ +\item \code{resp_url()} returns the complete url. +\item \code{resp_url_path()} returns the path component. +\item \code{resp_url_query()} returns a single query component. +\item \code{resp_url_queries()} returns the query component as a named list. +} +} +\examples{ +req <- request("https://httr2.r-lib.org?hello=world") + +resp <- req_perform(req) +resp \%>\% resp_url() +resp \%>\% resp_url_path() +resp \%>\% resp_url_query() +} diff --git a/tests/testthat/test-resp-url.R b/tests/testthat/test-resp-url.R new file mode 100644 index 00000000..91a1d30c --- /dev/null +++ b/tests/testthat/test-resp-url.R @@ -0,0 +1,11 @@ +test_that("can extract url components from a response", { + resp <- req_perform(request_test("/get?a=1&b=2")) + + expect_equal(resp_url(resp), paste0(example_url(), "get?a=1&b=2")) + expect_equal(resp_url_path(resp), "/get") + expect_equal(resp_url_queries(resp), list(a = "1", b = "2")) + + expect_equal(resp_url_query(resp, "a"), "1") + expect_equal(resp_url_query(resp, "c"), NULL) + expect_equal(resp_url_query(resp, "c", "x"), "x") +})