How to upload a file with required parameters to an API with the httr package?

I want to upload a file to a web API. According to the documentation, I need to pass a POST request to an upload url, including a list of required upload parameters as well as the file.

The API is private, so I can't share a reproducible example, but I'm struggling to format the final POST request.

Attempt 1: Error: All components of body must be named

upload_content <- httr::content(upload_resp)
upload_url <- upload_content$upload_url
upload_params <- c(upload_content$upload_params, httr::upload_file(file_name))
httr::POST(upload_url, body = list(upload_params))

Attempt 2: Error: All components of body must be named

upload_content <- httr::content(upload_resp)
upload_url <- upload_content$upload_url
upload_params <- upload_content$upload_params
httr::POST(upload_url, body = list(upload_params, httr::upload_file(file_name)))

Attempt 3: Status 400: Bad Request

upload_content <- httr::content(upload_resp)
upload_url <- upload_content$upload_url
upload_params <- c(upload_content$upload_params, httr::upload_file(file_name))
httr::POST(upload_url, body = list(upload_params))

How do I append the file to the upload parameters? And how should I format the body of the POST request?

Are you familiar with Postman? It's a very useful GUI for working with HTTP requests. I love httr, but sometimes things are easier to debug with Postman. Read more here: https://www.getpostman.com/.

Here's the business end of googledrive::drive_upload():

We're using some package-specific wrappers to form and make requests (via httr) but above is the heart of the matter re: handling the body.

1 Like

Thanks Jenny! Before I try and work through the googledrive wrappers, do I need to make two separate calls to httr::upload_file()? One for the parameters and meta-data, and one for the file itself?

Unashamed to say I forked googledrive just to insert print statements at various intervals. Alas, for all my efforts I still get a 400 status code.

What's bizarre is that I can successfully upload an empty .pdf or .txt file if I omit httr::upload_file from the request entirely.

I also should have included this earlier, but what I need to replicate is this:

curl '<upload_url>' \
     -F 'key=/users/1234/files/profile_pic.jpg' \
     <any other parameters specified in the upload_params response>
     -F 'file=@my_local_file.jpg'

Hi @daranzolin

Have you seen this SO post? https://stackoverflow.com/a/27372246/5000201

I'd make a guess to say your code would look like:

url <- "your url here"
params <- list('form[key]' = "/users/1234/files/profile_pic.jpg", 'form[file]'="file=@my_local_file.jpg")
response <- POST(url, body = params)

That's just from my understanding of your question (I'm assuming I've missed out some other parameters)

Edit: Doing a search on https://cran.r-project.org/web/packages/httr/vignettes/quickstart.html for 'Request body' also describes a option for encoding the parameters:

r <- POST(url, body = body, encode = "form")

For those still interested, I got this hacky solution to work:

  upload_params <- upload_content$upload_params
  upload_params[[length(upload_params) + 1]] <- httr::upload_file(file_name)
  names(upload_params)[[length(upload_params)]] <- "file"
  invisible(httr::POST(url = upload_url,
             body = upload_params))

Thanks everyone!

1 Like