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

Port all the underlying HTTP code to use httr2 #626

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

atheriel
Copy link

@atheriel atheriel commented Dec 3, 2024

This commit refactors bigrquery's internals to use httr2 instead of httr. I don't have a strong motivation for this change, other than the general belief that we should be trying to move packages to httr2 over time, and because it made bigrquery's internals a bit more modular.

One of the more visible consequences is that the OAuth tokens returned by bq_token() can no longer take the form of an httr request object; now they are simple bearer tokens instead. This should make it much easier to implement viewer-based credentials in the future.

However, it might break downstream packages that rely on the existing bq_token() return value.

I believe that most of these changes should be covered by the existing test suite.

This commit refactors `bigrquery`'s internals to use `httr2` instead of
`httr`. I don't have a strong motivation for this change, other than the
general belief that we should be trying to move packages to `httr2` over
time, and because it made `bigrquery`'s internals a bit more modular.

One of the more visible consequences is that the OAuth tokens returned
by `bq_token()` can no longer take the form of an `httr` request object;
now they are simple bearer tokens instead. This should make it much
easier to implement viewer-based credentials in the future.

However, it might break downstream packages that rely on the existing
`bq_token()` return value.

I believe that most of these changes should be covered by the existing
test suite.

Signed-off-by: Aaron Jacobs <[email protected]>
@jennybc
Copy link
Collaborator

jennybc commented Dec 3, 2024

I haven't delved into this, but am just passing by to say that I'd be interested in considering this move in the context of migrating gargle to httr2, which is also desirable and in the vague near-term future.

I realize that bigrquery only uses gargle for auth, but rolls its own request construction and response processing and that involves direct use of httr. gmailr is in a similar boat. googlesheets4 and googledrive use gargle for basically everything; they do depend on httr, but there's very little direct use. All of the tricky bits are mediated through gargle.

I think it would be good to form a coordinated plan of attack.

@atheriel
Copy link
Author

atheriel commented Dec 3, 2024

I think it would be good to form a coordinated plan of attack.

After going through one of these packages for this PR, my current thinking on this is that it will have to be done in multiple stages. httr2's model for tokens is totally incompatible with httr but aspects of how httr handles tokens (i.e. that they are stateful) are implicit in much of the design of gargle. We can't swap them out with the existing API contract.

Because of this, I think we'll need to do something like the following:

  1. Port downstream packages to use httr2 instead of httr, but leave their use of gargle largely intact.
  2. Add new abstraction mechanisms in gargle that align better with how httr2 sees the world and deprecate existing ones that strongly reflect httr's semantics. I'm thinking something like a new gargle::req_auth_google(...) function that looks at home in packages that use httr2's request-building APIs. Probably for some period of time gargle is going to have both httr and httr2 as direct dependencies.
  3. Port downstream packages to use these new auth APIs.
  4. Remove the old APIs from gargle and drop the use of httr entirely.

The other aspect of this is that I'd really like to get support for Posit Connect's viewer-based credentials into these packages, but I think a strategy that brings it to e.g. bigrquery first and then pushes some of the code into gargle later is more likely to be successful. Right now gargle strongly assumes that credentials are global to the R process, and unwinding that assumption will be nontrivial, I think.

Copy link
Member

@hadley hadley left a comment

Choose a reason for hiding this comment

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

Only a couple of tiny comments. Thanks for working on this!

req <- req_error(req, is_error = function(resp) {
resp_status(resp) != 404 && resp_status(resp) >= 400
})
resp <- req_perform(req)
Copy link
Member

Choose a reason for hiding this comment

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

In this case, I'd be tempted to drop the req_error() and instead use tryCatch(). Something like this:

tryCatch(
  { 
     req_perform(req)
     TRUE
  },
  httr2_http_404 = function(cnd) FALSE
})

)
invisible(process_request(req))
#' @importFrom httr2 req_body_json req_perform resp_body_json
bq_post <- function(url, body, query = NULL, token = bq_token()) {
Copy link
Member

Choose a reason for hiding this comment

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

Feels like we could probably weed out these specialised methods, since they're not so important with httr2's design. Probably not worth doing in this PR, but might be worth filing an issue so we remember to do it in the future?

content
} else {
jsonlite::fromJSON(rawToChar(content), simplifyVector = FALSE)
#' @importFrom httr2 request req_user_agent req_url_path_append req_method req_auth_bearer_token req_url_query req_error req_perform
Copy link
Member

Choose a reason for hiding this comment

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

I don't have any clear principle here, but it feels like you should either import all of httr2 or none of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants