Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export(resp_stream_is_complete)
export(resp_stream_lines)
export(resp_stream_raw)
export(resp_stream_sse)
export(resp_timing)
export(resp_url)
export(resp_url_path)
export(resp_url_queries)
Expand Down
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)

* `resp_timing()` exposes timing information about the request measured by libcurl (@arcresu, #725).
* `req_url_query()` now re-calculates n lengths when using `.multi = "explode"` to avoid select/recycling issues (@Kevanness, #719).

# httr2 1.1.2
Expand Down
24 changes: 24 additions & 0 deletions R/resp-timing.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#' Extract timing data
#'
#' The underlying curl library measures how long different components of the
#' request take to complete. This function retrieves that information.
#'
#' @inheritParams resp_header
#' @returns Named numeric vector of timing information.
#' The names of the elements in this vector correspond to the names used
#' in [libcurl's `curl_easy_getinfo()` API][curl docs].
#' The most useful component is likely `"total"` (corresponding to
#' `CURLINFO_TOTAL_TIME`), the overall time in seconds to complete the
#' request including any redirects followed.
#'
#' [curl docs]: https://curl.se/libcurl/c/curl_easy_getinfo.html
#' @export
#' @examples
#' req <- request(example_url())
#' resp <- req_perform(req)
#' resp_timing(resp)
resp_timing <- function(resp) {
check_response(resp)

resp$timing
}
14 changes: 12 additions & 2 deletions R/resp.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#' which will be parsed using the standard rules, or a named list.
#' @param body Response, if any, contained in the response body.
#' For `response_json()`, a R data structure to serialize to JSON.
#' @param timing A named numeric vector giving the time taken by various
#' components.
#' @returns An HTTP response: an S3 list with class `httr2_response`.
#' @export
#' @examples
Expand All @@ -30,7 +32,8 @@
url = "https://example.com",
method = "GET",
headers = list(),
body = raw()
body = raw(),
timing = NULL
) {
check_number_whole(status_code, min = 100, max = 700)
check_string(url)
Expand All @@ -43,7 +46,8 @@
url = url,
status_code = as.integer(status_code),
headers = headers,
body = body
body = body,
timing = timing
)
}

Expand Down Expand Up @@ -76,13 +80,17 @@
status_code,
headers,
body,
timing = NULL,
request = NULL,
error_call = caller_env()
) {
check_string(method, call = error_call)
check_string(url, call = error_call)
check_number_whole(status_code, call = error_call)
check_request(request, allow_null = TRUE)
if (!is.null(timing) && !is_bare_numeric(timing)) {
stop_input_type(timing, "a numeric vector", allow_null = TRUE)

Check warning on line 92 in R/resp.R

View check run for this annotation

Codecov / codecov/patch

R/resp.R#L92

Added line #L92 was not covered by tests
}

headers <- as_headers(headers, error_call = error_call)
# ensure we always have a date field
Expand All @@ -97,6 +105,7 @@
status_code = status_code,
headers = headers,
body = body,
timing = timing,
request = request,
cache = new_environment()
),
Expand All @@ -111,6 +120,7 @@
status_code = curl_data$status_code,
headers = as_headers(curl_data$headers),
body = body,
timing = curl_data$times,
request = req
)

Expand Down
28 changes: 28 additions & 0 deletions man/resp_timing.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion man/response.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tests/testthat/test-req-perform.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ test_that("successful request returns expected response", {
expect_s3_class(resp$headers, "httr2_headers")
expect_type(resp$body, "raw")
expect_equal(resp$request, req)

expect_type(resp$timing, "double")
expect_true(all(resp$timing >= 0))
})

test_that("request updates last_response()", {
Expand Down
4 changes: 4 additions & 0 deletions tests/testthat/test-resp-timing.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
test_that("can extract request timing", {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arcresu I figured it was easier to just make the change than try to explain it further. And now that I've done it, I can express what I was picking up on more clearly: it's worth partitioning your test into two pieces, one that tests we are correctly setting the values, and one that tests we are correctly getting the values.

req <- response(timing = c(total = 1))
expect_equal(resp_timing(req), c(total = 1))
})
Loading