Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

httr2 done #268

Merged
merged 26 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7c9c15c
started httr2 integration work #237
sckott Jun 23, 2023
14a7552
Merge branch 'main' into httr2
sckott Jul 3, 2023
04fa138
Merge branch 'main' into httr2
sckott Jul 3, 2023
83dfa30
export RequestHandlerHttr2
sckott Jul 3, 2023
3e3a2ee
bmp version
sckott Sep 23, 2023
b318659
import httr2
sckott Sep 23, 2023
a11ea6e
remove --no-build-vignettes in R CMD INSTALL
sckott Oct 22, 2023
0af4766
add depends R >= 3.5 for data
sckott Oct 22, 2023
4eda024
add RequestHandlerHttr2 to pkgdown yaml
sckott Oct 23, 2023
50da391
add req_error to httr2 handler so that httr2 doesnt turn a http errro…
sckott Oct 23, 2023
0990d1c
compatabiilty for httr2 here and there
sckott Oct 23, 2023
199bf58
udpate docs to talk about all 3 http pkgs
sckott Oct 25, 2023
3cd9ef7
update readm.md
sckott Oct 25, 2023
f109dc1
woops, errant debug line
sckott Oct 25, 2023
60b87e1
tickle R check
sckott Oct 28, 2023
b8008ad
update man file for Cassette class
sckott Oct 31, 2023
a527d82
merged from main
sckott Jan 16, 2024
916fc4b
Merge branch 'main' into httr2
sckott Feb 4, 2024
1e94ca2
httr2: get last response with last_response after req_perform
sckott Jul 11, 2024
42bd3a1
httr2: fix status code retrieval
sckott Jul 11, 2024
eef94d9
httr2 response handling in Cassette class
sckott Jul 11, 2024
3ac66d2
uncomment commented out tests that now work
sckott Jul 11, 2024
e940bd1
fix a bunch of httr2 tests
sckott Jul 11, 2024
af0fd4c
update roxygen2 version
sckott Jul 11, 2024
fef3705
REVDEPCHECK
sckott Jul 16, 2024
085053a
REVDEPCHECK - use gh pat
sckott Jul 16, 2024
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 .github/workflows/revdep-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:

env:
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
GITHUB_PAT: ${{ secrets.GH_PAT }}

steps:
- uses: actions/checkout@v3
Expand Down
6 changes: 5 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ Language: en-US
LazyData: true
VignetteBuilder: knitr
Roxygen: list(markdown = TRUE)
Depends:
R (>= 3.5)
Imports:
crul (>= 0.8.4),
httr,
httr2,
webmockr (>= 0.8.0),
urltools,
yaml,
Expand All @@ -50,7 +53,8 @@ Suggests:
curl,
withr,
webfakes
Remotes: ropensci/webmockr@httr2
X-schema.org-applicationCategory: Web
X-schema.org-keywords: http, https, API, web-services, curl, mock, mocking, http-mocking, testing, testing-tools, tdd
X-schema.org-isPartOf: https://ropensci.org
RoxygenNote: 7.3.1
RoxygenNote: 7.3.2
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ rmd2md:
mv configuration.md configuration.Rmd

install: doc build
R CMD INSTALL --no-build-vignettes . && rm *.tar.gz
R CMD INSTALL . && rm *.tar.gz

build:
R CMD build --no-build-vignettes .
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export(Request)
export(RequestHandler)
export(RequestHandlerCrul)
export(RequestHandlerHttr)
export(RequestHandlerHttr2)
export(RequestMatcherRegistry)
export(Serializers)
export(UnhandledHTTPRequestError)
Expand Down Expand Up @@ -55,6 +56,8 @@ importFrom(crul,HttpClient)
importFrom(crul,mock)
importFrom(httr,content)
importFrom(httr,http_status)
importFrom(httr2,req_perform)
importFrom(httr2,resp_status_desc)
importFrom(urltools,url_compose)
importFrom(urltools,url_parse)
importFrom(utils,getParseData)
Expand Down
27 changes: 19 additions & 8 deletions R/cassette_class.R
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ Cassette <- R6::R6Class(
},

#' @description record an http interaction (doesn't write to disk)
#' @param x an crul or httr response object, with the request at `$request`
#' @param x a crul, httr, or httr2 response object, with the request at `$request`
#' @return nothing returned
record_http_interaction = function(x) {
int <- self$make_http_interaction(x)
Expand Down Expand Up @@ -619,9 +619,12 @@ Cassette <- R6::R6Class(
},

#' @description Make an `HTTPInteraction` object
#' @param x an crul or httr response object, with the request at `$request`
#' @param x A crul, httr, or httr2 response object, with the request at `$request`
#' @return an object of class [HTTPInteraction]
make_http_interaction = function(x) {
# for httr2, duplicate `body` slot in `content`
if (inherits(x, "httr2_response")) x$content <- x$body

# content must be raw or character
assert(unclass(x$content), c('raw', 'character'))
new_file_path <- ""
Expand All @@ -646,7 +649,7 @@ Cassette <- R6::R6Class(
} else { # crul
webmockr::pluck_body(x$request)
},
headers = if (inherits(x, "response")) {
headers = if (inherits(x, c("response", "httr2_response"))) {
as.list(x$request$headers)
} else {
x$request_headers
Expand All @@ -659,9 +662,17 @@ Cassette <- R6::R6Class(
response <- VcrResponse$new(
status = if (inherits(x, "response")) {
c(list(status_code = x$status_code), httr::http_status(x))
} else unclass(x$status_http()),
headers = if (inherits(x, "response")) x$headers else x$response_headers,
body = if (is.raw(x$content)) {
} else if (inherits(x, "httr2_response")) {
list(status_code = x$status_code, message = httr2::resp_status_desc(x))
} else {
unclass(x$status_http())
},
headers = if (inherits(x, c("response", "httr2_response"))) {
x$headers
} else {
x$response_headers
},
body = if (is.raw(x$content) || is.null(x$content)) {
if (can_rawToChar(x$content)) rawToChar(x$content) else x$content
} else {
stopifnot(inherits(unclass(x$content), "character"))
Expand Down Expand Up @@ -754,6 +765,6 @@ empty_cassette_message <- function(x) {
c(
sprintf("Empty cassette (%s) deleted; consider the following:\n", x),
" - If an error occurred resolve that first, then check:\n",
" - vcr only supports crul & httr; requests w/ curl, download.file, etc. are not supported\n",
" - If you are using crul/httr, are you sure you made an HTTP request?\n")
" - vcr only supports crul, httr & httr2; requests w/ curl, download.file, etc. are not supported\n",
" - If you are using crul/httr/httr2, are you sure you made an HTTP request?\n")
}
7 changes: 5 additions & 2 deletions R/request_class.R
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Request <- R6::R6Class(
fields = NULL,
#' @field output (various) request output details, disk, memory, etc
output = NULL,
#' @field policies (various) http policies, used in httr2 only
policies = NULL,

#' @description Create a new `Request` object
#' @param method (character) the HTTP method (i.e. head, options, get,
Expand All @@ -62,12 +64,12 @@ Request <- R6::R6Class(
#' @param disk (boolean), is body a file on disk
#' @param fields (various) post fields
#' @param output (various) output details
#' @param policies (various) http policies, used in httr2 only
#' @param skip_port_stripping (logical) whether to strip the port.
#' default: `FALSE`
#' @return A new `Request` object
initialize = function(method, uri, body, headers, opts, disk,
fields, output, skip_port_stripping = FALSE) {

fields, output, policies, skip_port_stripping = FALSE) {
if (!missing(method)) self$method <- tolower(method)
if (!missing(body)) {
if (inherits(body, "list")) {
Expand All @@ -93,6 +95,7 @@ Request <- R6::R6Class(
if (!missing(disk)) self$disk <- disk
if (!missing(fields)) self$fields <- fields
if (!missing(output)) self$output <- output
if (!missing(policies)) self$policies <- policies
},

#' @description Convert the request to a list
Expand Down
115 changes: 115 additions & 0 deletions R/request_handler-httr2.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#' @title RequestHandlerHttr2
#' @description Methods for the httr2 package, building on [RequestHandler]
#' @export
#' @param request The request from an object of class `HttpInteraction`
#' @examples \dontrun{
#' # GET request
#' library(httr2)
#' req <- request("https://hb.opencpu.org/post") %>%
#' req_body_json(list(foo = "bar"))
#' x <- RequestHandlerHttr2$new(req)
#' # x$handle()
#'
#' # POST request
#' library(httr2)
#' mydir <- file.path(tempdir(), "testing_httr2")
#' invisible(vcr_configure(dir = mydir))
#' req <- request("https://hb.opencpu.org/post") %>%
#' req_body_json(list(foo = "bar"))
#' use_cassette(name = "testing3", {
#' response <- req_perform(req)
#' }, match_requests_on = c("method", "uri", "body"))
#' use_cassette(name = "testing3", {
#' response2 <- req_perform(req)
#' }, match_requests_on = c("method", "uri", "body"))
#' }
RequestHandlerHttr2 <- R6::R6Class(
"RequestHandlerHttr2",
inherit = RequestHandler,

public = list(
#' @description Create a new `RequestHandlerHttr2` object
#' @param request The request from an object of class `HttpInteraction`
#' @return A new `RequestHandlerHttr2` object
initialize = function(request) {
if (!length(request$method)) {
request$method <- webmockr:::req_method_get_w(request)
}
self$request_original <- request
self$request <- {
Request$new(request$method, request$url,
webmockr::pluck_body(request), request$headers,
fields = request$fields, opts = request$options,
policies = request$policies)
}
self$cassette <- tryCatch(current_cassette(), error = function(e) e)
}
),

private = list(
# make a `vcr` response
response_for = function(x) {
VcrResponse$new(
list(status_code = x$status_code, description = httr2::resp_status_desc(x)),
x$headers,
x$body,
"",
super$cassette$cassette_opts
)
},

# these will replace those in
on_ignored_request = function(request) {
# perform and return REAL http response
# * make real request
# * run through response_for() to make vcr response, store vcr response
# * give back real response

# real request
webmockr::httr2_mock(FALSE)
on.exit(webmockr::httr2_mock(TRUE), add = TRUE)
tmp2 <- httr2::req_perform(request)

# run through response_for()
self$vcr_response <- private$response_for(tmp2)

# return real response
return(response)
},

on_stubbed_by_vcr_request = function(request) {
# print("------- on_stubbed_by_vcr_request -------")
# return stubbed vcr response - no real response to do
serialize_to_httr2(request, super$get_stubbed_response(request))
},

on_recordable_request = function(request) {
# print("------- on_recordable_request -------")
# do real request - then stub response - then return stubbed vcr response
# real request
webmockr::httr2_mock(FALSE)
on.exit(webmockr::httr2_mock(TRUE), add = TRUE)
xx <- self$request_original %>%
httr2::req_error(is_error = function(resp) FALSE)
# print(xx)
tryCatch(httr2::req_perform(xx), error = function(e) e)
tmp2 <- httr2::last_response()
# print("------- after the req_perform -------")

response <- webmockr::build_httr2_response(self$request_original, tmp2)

# make vcr response | then record interaction
self$vcr_response <- private$response_for(response)
cas <- tryCatch(current_cassette(), error = function(e) e)
if (inherits(cas, "error")) stop("no cassette in use")
response$request <- self$request_original
response$request$method <- webmockr:::req_method_get_w(response$request)
cas$record_http_interaction(response)

# return real response
# print("------- before return -------")
return(response)
}
)
)

37 changes: 37 additions & 0 deletions R/serialize_to_httr2.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# generate actual httr2 response
# request <- httr2::request("https://hb.opencpu.org/301")
#
serialize_to_httr2 <- function(request, response) {
# request
req <- webmockr::RequestSignature$new(
method = request$method,
uri = request$uri,
options = list(
body = request$body %||% NULL,
headers = request$headers %||% NULL,
proxies = NULL,
auth = NULL,
disk = if (inherits(response$body, "httr2_path")) response$body %||% NULL,
fields = request$fields %||% NULL,
output = request$output %||% NULL
)
)

# response
resp <- webmockr::Response$new()
resp$set_url(request$uri)
resp$set_body(response$body, inherits(response$body, "httr2_path"))
resp$set_request_headers(request$headers, capitalize = FALSE)
resp$set_response_headers(response$headers, capitalize = FALSE)
resp$set_status(status = response$status$status_code %||% 200)

# generate httr2 response
webmockr::build_httr2_response(as_httr2_request(req), resp)
}

as_httr2_request <- function(x) {
structure(list(url = x$url$url, method = toupper(x$method),
headers = x$headers, body = x$body, fields = x$fields,
options = x$options, policies = x$policies),
class = "httr2_request")
}
1 change: 1 addition & 0 deletions R/vcr-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#' @importFrom urltools url_parse url_compose
#' @importFrom crul HttpClient mock
#' @importFrom httr http_status content
#' @importFrom httr2 resp_status_desc req_perform
#' @importFrom webmockr pluck_body
## usethis namespace: end
NULL
Expand Down
1 change: 1 addition & 0 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Check out the [HTTP testing book](https://books.ropensci.org/http-testing/) and

* [crul][]
* [httr](https://httr.r-lib.org/)
* [httr2](https://httr2.r-lib.org/)

## Getting Started

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Check out the [HTTP testing book](https://books.ropensci.org/http-testing/) and

* [crul][]
* [httr](https://httr.r-lib.org/)
* [httr2](https://httr2.r-lib.org/)

## Getting Started

Expand Down
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ reference:
- RequestHandler
- RequestHandlerCrul
- RequestHandlerHttr
- RequestHandlerHttr2
- RequestMatcherRegistry
- Serializers
- serializer_fetch
Expand Down
4 changes: 2 additions & 2 deletions man/Cassette.Rd

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

5 changes: 5 additions & 0 deletions man/Request.Rd

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

Loading
Loading