Skip to content

Conversation

@JosiahParry
Copy link

This PR closes #795 by adding an httr2_translate() function.

This function takes an httr2_request object and does its best to faithfully create the equivalent curl request while respecting headers, cookies, options, request type etc.

library(httr2)

request("https://httpbin.org/post") |>
  req_body_form(name = "value") |>
  httr2_translate() |>
  cat()
#> curl -X POST \
#>   -H "Content-Type: application/x-www-form-urlencoded" \
#>   -d "name=value" \
#>   "https://httpbin.org/post"

path <- tempfile()
writeLines("test content", path)
request("https://httpbin.org/post") |>
  req_body_file(path, type = "text/plain") |>
  httr2_translate() |>
  cat()
#> curl -X POST \
#>   -H "Content-Type: text/plain" \
#>   --data-binary "@/var/folders/wd/xq999jjj3bx2w8cpg7lkfxlm0000gn/T//Rtmp6Xs5Mq/file13ec039518760" \
#>   "https://httpbin.org/post"

request("https://httpbin.org/get") |>
  req_options(timeout = 30, verbose = TRUE, ssl_verifypeer = FALSE) |>
  httr2_translate() |>
  cat()
#> curl --max-time 30 \
#>   --verbose \
#>   --insecure \
#>   "https://httpbin.org/get"

request("https://httpbin.org/get") |>
  req_headers("Authorization" = obfuscated("ZdYJeG8zwISodg0nu4UxBhs")) |>
  httr2_translate() |>
  cat()
#> curl -H "Authorization: y" \
#>   "https://httpbin.org/get"

Created on 2025-08-20 with reprex v2.1.1

@JosiahParry
Copy link
Author

CI has been tamed. Please let me know if there is anything I can do to move this along! I'd quite like to be able to use it as a debug option in {arcgislayers} with something like:

if (isTRUE(getOption("arcgis.debug_curl")) {
    cat(httr2::httr2_translate(req))
}

This will help tremendously in getting reproducible examples from users as well as providing them to our distributed team of software engineers.

Thanks!

Comment on lines 167 to 169
if (length(cmd_parts) <= 2) {
paste(cmd_parts, collapse = " ")
} else {
Copy link
Member

Choose a reason for hiding this comment

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

Is this branch actually necessary?

Copy link
Author

Choose a reason for hiding this comment

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

This branch is used so that the output is compatible with curl_translate() if curl is on its own line curl_translate() fails to read the result.

Copy link
Member

Choose a reason for hiding this comment

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

I understand that but I think if remove the first branch then the results will still be the same.

I'd suggest renaming and refocussing cmd_parts to curl_args (i.e. adding curl and the url at the very end) to make this more clear.

@JosiahParry
Copy link
Author

Thank you so much for the feedback! I'll review this and make the requested changes.

headers <- req_get_headers(req, redacted = "reveal")

# if headers are present, add them using -H flag
if (!rlang::is_empty(headers)) {
Copy link
Member

Choose a reason for hiding this comment

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

Again, you don't need to first check if the vector is empty, if it is empty the for loop already doesn't do anything.

}
}

known_curl_opts <- c(
Copy link
Member

Choose a reason for hiding this comment

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

I'd suggest making this a separate function

# if the headers aren't empty AND the content-type header is set
# we use that instead of what is inferred from the request object
if (
!rlang::is_empty(headers) && ("content-type" %in% tolower(names(headers)))
Copy link
Member

Choose a reason for hiding this comment

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

If x is empty, then "foo" %in% x will always return FALSE.

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.

feat: httr2_translate()

2 participants