Plumber: Provide a clean way to upload files via an endpoint

Created on 28 Feb 2017  路  12Comments  路  Source: rstudio/plumber

Posting whole files to an endpoint, using the "multipart/formdata" enctype is not currently well supported.

It is possible to retrieve a posted file (see https://github.com/sellorm/plumber-uploader for an example), but this is hacky and fragile at best. This approach basically rips the file name and content from req$postBody.

It would be useful to have something like a req$FILES that could be parsed to obtain filenames and content, for processing by the endpoint author.

Not sure how you'd handle things like accepted file types, or max permitted file size and so on though.

Most helpful comment

Is there any problem with using Rook::Multipart for that? I've just tried doing:

#' @post /echo
function(req){
  list(formContents = Rook::Multipart$parse(req))
}

And it seems to work with curl -v -F foo=bar -F [email protected] http://localhost:8993/echo just fine.

All 12 comments

I had not seen your ticket when I sent some code for review yesterday (see #77). In my notes I suggest something that seems similar to what you are suggesting:

We move out all the code related to feather, so that the raw binary body is returned to be handles by the function written in the endpoint. We can return the name of the handle and the name of the file, as both are available in the multiparse object and the tmpfile location of the binary file (as set by tempfile())

That would pretty much do what you suggest right? If so I will change the submission to make it generic, so that it just returns the binary, to be handled by the endpoint.

My use case was different, but I think that any solution will end up being applicable to both use cases.

I think #77 is the ground work for this feature. This would be really nice but I think there's a decent chunk of work to get us there.

Is there any problem with using Rook::Multipart for that? I've just tried doing:

#' @post /echo
function(req){
  list(formContents = Rook::Multipart$parse(req))
}

And it seems to work with curl -v -F foo=bar -F [email protected] http://localhost:8993/echo just fine.

@liori So cool !!
And we can just get any kinds of data by doing like:

somefile <- readLines(con = formContents$upload$tempfile)

If the file is some kind of binary file, then we can do:

somefile <- readBin(con = formContents$upload$tempfile, "raw", 
                    n = file.size(formContents$upload$tempfile))

@liori @ZJUguquan How can i deal with multiple file from front end

Anyone on this thread aware of configuration settings that would control how large of a file we can upload using the techniques described here? I configured an app as described, which works for small files. But for larger files it just sort of hangs and never completes.

Do we know what annotation to be provided in R function to generate swagger with file upload support?

Thanks for the suggestion @liori .
Unfortunately i am doing sthg wrong it seems, see the following Picture.

1) First. i test if the plumber api works for another post request. Check,

2) Second, i check if the file i want to upload is available. Check,

3) Then i try to implement your idea. That doesnt work.

can you see what is wrong?

image

plumber.R

library(plumber)

#* @apiTitle Plumber Example API

#* Plot a histogram
#* @png
#* @get /plot
function() {
  rand <- rnorm(100)
  hist(rand)
}

#' @post /echo
function(req){
  list(formContents = Rook::Multipart$parse(req))
}

#* Return the sum of two numbers
#* @param a The first number to add
#* @param b The second number to add
#* @post /sum
function(a, b) {
  as.numeric(a) + as.numeric(b)
}

mime::parse_multipart() is a rewrite of Rook::Multipart$parse(). I have a working demo here: https://github.com/krlmlr/plumber-uploader/tree/f-multipart.

@krlmlr your uploader worked like a charm for excel files. Thanks!

Fixed in #532. Closing.

Please open a new issue and reference this one if you run into any issues! Thank you.

Was this page helpful?
0 / 5 - 0 ratings