Skip to content

Commit

Permalink
Merge commit '6b085735f37a34130c5c27213faec78825ebc86e'
Browse files Browse the repository at this point in the history
#Conflicts:
#	NEWS.md
  • Loading branch information
hadley committed Oct 20, 2023
2 parents 3ffa126 + 6b08573 commit 7da9dda
Show file tree
Hide file tree
Showing 86 changed files with 630 additions and 379 deletions.
14 changes: 14 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@
token has expired, then httr2 will now re-run the entire flow to get
you a new token (#349).

* `resp_body_json()` and `resp_body_xml()` now caches the parsed values so
that you can use them repeatedly without worrying about the performance cost.

* `req_url_query()` gains a `.multi` parameter that controls what happens when
you supply multiple values in a vector. The default will continue to error
but you can use `.multi = "comma"` to separate with commas, `"pipe"` to
separate with `|`, and `"explode"` to generate one parameter for each
value (e.g. `?a=1&a=2`) (#350).

* The httr2 examples now only run on R 4.2 and later so that we can use
the base pipe and lambda syntax (#345).

* `curl_translate()` now uses the base pipe.

* OAuth docs have been clarified to encourage the use of `req_oauth_*()`,
not `oauth_*()` (#330). This includes a new `vignette("oauth")` which
gives many more details about how OAuth works and how to use it with
Expand Down
6 changes: 5 additions & 1 deletion R/curl.R
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ curl_translate <- function(cmd, simplify_headers = TRUE) {
}
steps <- add_curl_step(steps, "req_perform", main_args = perform_args, keep_if_empty = TRUE)

out <- paste0(steps, collapse = " %>% \n ")
out <- paste0(steps, collapse = paste0(pipe(), "\n "))
out <- paste0(out, "\n")

if (clip) {
Expand All @@ -86,6 +86,10 @@ curl_translate <- function(cmd, simplify_headers = TRUE) {
structure(out, class = "httr2_cmd")
}

pipe <- function() {
if (getRversion() >= "4.1.0") " |> " else " %>% "
}

#' @export
print.httr2_cmd <- function(x, ...) {
cat(x)
Expand Down
12 changes: 6 additions & 6 deletions R/multi-req.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@
#' # 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_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")
#' )
#' # But it's much faster if you request in parallel
#' system.time(resps <- req_perform_parallel(reqs))
#'
#' reqs <- list(
#' request_base %>% req_url_path("/status/200"),
#' request_base %>% req_url_path("/status/400"),
#' request_base |> req_url_path("/status/200"),
#' request_base |> req_url_path("/status/400"),
#' request("FAILURE")
#' )
#' # req_perform_parallel() will always succeed
Expand Down
2 changes: 1 addition & 1 deletion R/oauth-flow-auth-code.R
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
#' )
#' }
#'
#' request("https://api.github.com/user") %>%
#' request("https://api.github.com/user") |>
#' req_auth_github()
req_oauth_auth_code <- function(req,
client,
Expand Down
2 changes: 1 addition & 1 deletion R/oauth-flow-client-credentials.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#' )
#' }
#'
#' request("https://example.com") %>%
#' request("https://example.com") |>
#' req_auth()
req_oauth_client_credentials <- function(req,
client,
Expand Down
2 changes: 1 addition & 1 deletion R/oauth-flow-device.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#' )
#' }
#'
#' request("https://api.github.com/user") %>%
#' request("https://api.github.com/user") |>
#' req_auth_github()
req_oauth_device <- function(req,
client,
Expand Down
2 changes: 1 addition & 1 deletion R/oauth-flow-jwt.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#' )
#' }
#'
#' request("https://example.com") %>%
#' request("https://example.com") |>
#' req_auth()
req_oauth_bearer_jwt <- function(req,
client,
Expand Down
2 changes: 1 addition & 1 deletion R/oauth-flow-password.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#' )
#' }
#' if (interactive()) {
#' request("https://example.com") %>%
#' request("https://example.com") |>
#' req_auth()
#' }
req_oauth_password <- function(req,
Expand Down
2 changes: 1 addition & 1 deletion R/oauth-flow-refresh.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#' @examples
#' client <- oauth_client("example", "https://example.com/get_token")
#' req <- request("https://example.com")
#' req %>% req_oauth_refresh(client)
#' req |> req_oauth_refresh(client)
req_oauth_refresh <- function(req,
client,
refresh_token = Sys.getenv("HTTR2_REFRESH_TOKEN"),
Expand Down
28 changes: 13 additions & 15 deletions R/paginate.R
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@
#' @examples
#' page_size <- 40
#'
#' request(example_url()) %>%
#' req_url_path("/iris") %>%
#' req_url_query(limit = page_size) %>%
#' request(example_url()) |>
#' req_url_path("/iris") |>
#' req_url_query(limit = page_size) |>
#' req_paginate_page_index(
#' page_index = function(req, page) {
#' req %>% req_url_query(page_index = page)
#' req |> req_url_query(page_index = page)
#' },
#' parse_resp = function(resp) {
#' parsed <- resp_body_json(resp)
Expand Down Expand Up @@ -131,12 +131,12 @@ req_paginate <- function(req,
#' @examples
#' page_size <- 40
#'
#' req_flowers <- request(example_url()) %>%
#' req_url_path("/iris") %>%
#' req_url_query(limit = page_size) %>%
#' req_flowers <- request(example_url()) |>
#' req_url_path("/iris") |>
#' req_url_query(limit = page_size) |>
#' req_paginate_page_index(
#' page_index = function(req, page) {
#' req %>% req_url_query(page_index = page)
#' req |> req_url_query(page_index = page)
#' },
#' parse_resp = function(resp) {
#' parsed <- resp_body_json(resp)
Expand Down Expand Up @@ -225,17 +225,15 @@ req_perform_iteratively <- function(req,
#' @return Generates the next request in an iterative request,
#' or `NULL` if there are no more pages to return.
#' @examples
#' req_flowers <- request(example_url()) %>%
#' req_url_path("/iris") %>%
#' req_url_query(limit = 40) %>%
#' req_flowers <- request(example_url()) |>
#' req_url_path("/iris") |>
#' req_url_query(limit = 40) |>
#' req_paginate_page_index(
#' page_index = function(req, page) {
#' req %>% req_url_query(page_index = page)
#' }
#' page_index = \(req, page) req |> req_url_query(page_index = page)
#' )
#' req_flowers$url
#'
#' resp <- req_flowers %>% req_perform()
#' resp <- req_flowers |> req_perform()
#' next_req <- iterate_next_request(req_flowers, resp)
#' next_req$url
iterate_next_request <- function(req, parsed) {
Expand Down
4 changes: 2 additions & 2 deletions R/progress.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
#' or downloaded.
#' @export
#' @examples
#' req <- request("https://r4ds.s3.us-west-2.amazonaws.com/seattle-library-checkouts.csv") %>%
#' req <- request("https://r4ds.s3.us-west-2.amazonaws.com/seattle-library-checkouts.csv") |>
#' req_progress()
#'
#' \dontrun{
#' path <- tempfile()
#' req %>% req_perform(path = path)
#' req |> req_perform(path = path)
#' }
req_progress <- function(req, type = c("down", "up")) {
type <- arg_match(type)
Expand Down
8 changes: 4 additions & 4 deletions R/req-auth.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
#' @returns A modified HTTP [request].
#' @export
#' @examples
#' req <- request("http://example.com") %>% req_auth_basic("hadley", "SECRET")
#' req <- request("http://example.com") |> req_auth_basic("hadley", "SECRET")
#' req
#' req %>% req_dry_run()
#' req |> req_dry_run()
#'
#' # httr2 does its best to redact the Authorization header so that you don't
#' # accidentally reveal confidential data. Use `redact_headers` to reveal it:
#' print(req, redact_headers = FALSE)
#' req %>% req_dry_run(redact_headers = FALSE)
#' req |> req_dry_run(redact_headers = FALSE)
#'
#' # We do this because the authorization header is not encrypted and the
#' # so password can easily be discovered:
Expand Down Expand Up @@ -48,7 +48,7 @@ req_auth_basic <- function(req, username, password = NULL) {
#' @returns A modified HTTP [request].
#' @export
#' @examples
#' req <- request("http://example.com") %>% req_auth_bearer_token("sdaljsdf093lkfs")
#' req <- request("http://example.com") |> req_auth_bearer_token("sdaljsdf093lkfs")
#' req
#'
#' # httr2 does its best to redact the Authorization header so that you don't
Expand Down
22 changes: 11 additions & 11 deletions R/req-body.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,36 @@
#' a `Content-Type` header.
#' @returns A modified HTTP [request].
#' @examples
#' req <- request(example_url()) %>%
#' req <- request(example_url()) |>
#' req_url_path("/post")
#'
#' # Most APIs expect small amounts of data in either form or json encoded:
#' req %>%
#' req_body_form(x = "A simple text string") %>%
#' req |>
#' req_body_form(x = "A simple text string") |>
#' req_dry_run()
#'
#' req %>%
#' req_body_json(list(x = "A simple text string")) %>%
#' req |>
#' req_body_json(list(x = "A simple text string")) |>
#' req_dry_run()
#'
#' # For total control over the body, send a string or raw vector
#' req %>%
#' req_body_raw("A simple text string") %>%
#' req |>
#' req_body_raw("A simple text string") |>
#' req_dry_run()
#'
#' # There are two main ways that APIs expect entire files
#' path <- tempfile()
#' writeLines(letters[1:6], path)
#'
#' # You can send a single file as the body:
#' req %>%
#' req_body_file(path) %>%
#' req |>
#' req_body_file(path) |>
#' req_dry_run()
#'
#' # You can send multiple files, or a mix of files and data
#' # with multipart encoding
#' req %>%
#' req_body_multipart(a = curl::form_file(path), b = "some data") %>%
#' req |>
#' req_body_multipart(a = curl::form_file(path), b = "some data") |>
#' req_dry_run()
#' @name req_body
#' @aliases NULL
Expand Down
6 changes: 3 additions & 3 deletions R/req-cache.R
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@
#' "master/inst/extdata/penguins.csv"
#' )
#' # Here I set debug = TRUE so you can see what's happening
#' req <- request(url) %>% req_cache(tempdir(), debug = TRUE)
#' req <- request(url) |> req_cache(tempdir(), debug = TRUE)
#'
#' # First request downloads the data
#' resp <- req %>% req_perform()
#' resp <- req |> req_perform()
#'
#' # Second request retrieves it from the cache
#' resp <- req %>% req_perform()
#' resp <- req |> req_perform()
req_cache <- function(req,
path,
use_on_error = FALSE,
Expand Down
14 changes: 7 additions & 7 deletions R/req-cookies.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
#' @export
#' @examples
#' path <- tempfile()
#' httpbin <- request(example_url()) %>%
#' httpbin <- request(example_url()) |>
#' req_cookie_preserve(path)
#'
#' # Manually set two cookies
#' httpbin %>%
#' req_template("/cookies/set/:name/:value", name = "chocolate", value = "chip") %>%
#' req_perform() %>%
#' httpbin |>
#' req_template("/cookies/set/:name/:value", name = "chocolate", value = "chip") |>
#' req_perform() |>
#' resp_body_json()
#'
#' httpbin %>%
#' req_template("/cookies/set/:name/:value", name = "oatmeal", value = "raisin") %>%
#' req_perform() %>%
#' httpbin |>
#' req_template("/cookies/set/:name/:value", name = "oatmeal", value = "raisin") |>
#' req_perform() |>
#' resp_body_json()
#'
#' # The cookie path has a straightforward format
Expand Down
18 changes: 9 additions & 9 deletions R/req-error.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#'
#' ```
#' tryCatch(
#' req %>% req_perform() %>% resp_body_json(),
#' req |> req_perform() |> resp_body_json(),
#' httr2_http_404 = function(cnd) NULL
#' )
#' ```
Expand All @@ -36,7 +36,7 @@
#'
#' ```R
#' withCallingHandlers(
#' req %>% req_perform() %>% resp_body_json(),
#' req |> req_perform() |> resp_body_json(),
#' httr2_http_404 = function(cnd) {
#' rlang::abort("Couldn't find user", parent = cnd)
#' }
Expand All @@ -59,29 +59,29 @@
#' @examples
#' # Performing this request usually generates an error because httr2
#' # converts HTTP errors into R errors:
#' req <- request(example_url()) %>%
#' req <- request(example_url()) |>
#' req_url_path("/status/404")
#' try(req %>% req_perform())
#' try(req |> req_perform())
#' # You can still retrieve it with last_response()
#' last_response()
#'
#' # But you might want to suppress this behaviour:
#' resp <- req %>%
#' req_error(is_error = function(resp) FALSE) %>%
#' resp <- req |>
#' req_error(is_error = \(resp) FALSE) |>
#' req_perform()
#' resp
#'
#' # Or perhaps you're working with a server that routinely uses the
#' # wrong HTTP error codes only 500s are really errors
#' request("http://example.com") %>%
#' req_error(is_error = function(resp) resp_status(resp) == 500)
#' request("http://example.com") |>
#' req_error(is_error = \(resp) resp_status(resp) == 500)
#'
#' # Most typically you'll use req_error() to add additional information
#' # extracted from the response body (or sometimes header):
#' error_body <- function(resp) {
#' resp_body_json(resp)$error
#' }
#' request("http://example.com") %>%
#' request("http://example.com") |>
#' req_error(body = error_body)
#' # Learn more in https://httr2.r-lib.org/articles/wrapping-apis.html
req_error <- function(req,
Expand Down
Loading

0 comments on commit 7da9dda

Please sign in to comment.