Is there a REST specification for uploading files?

Asked

Viewed 3,144 times

17

I’ve been having second thoughts about it for almost a month. In certain to my application, the user can upload to a file library.

This upload needs to be recorded in a table called midias, where, in addition to the file path, I also need extra data such as name, description, file permission, and metadata information such as file size and extension.

The question that arises in this case is the following: For the record in the database referring to this file, I also need the other information. And, as the requests usually use the content-type JSON, I wonder how the file would be sent then, since the JSON have some limitation as to the characters that can be included in the same.

Hypothetical example:

POST /api/midias/
Content-Type: application/json

{
    "nome" : "Flor",
    "descricao" : "A flor azul encontrada na 
    "tipo_acesso" : 1,
    "extensao" : "jpg",
    "tamanho"  : 5225,
    "arquivo"  : ???????
}

That is, according to example above, to create the resource in my API, in addition to the media information, I also needed to send the binary file, to upload.

Now let’s get down to business:

1) The first way I tried was to send the binary of a file via JSON even, converting the file binary to base64.

Base64’s problem is that it increases (and greatly) the file size, making it unviable in my case, since we will allow uploading videos.

2) Use the multipart/form-data, sending the file normally, as is done in form requests, and attaching the other data cited above in a field "json", sending this data as a string JSON (serialized).

Example:

POST / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: __atuvc=34%7C7; permanent=0; _gitlab_session=226ad8a0be43681acf38c2fab9497240; __profilin=p%3Dt; request_method=GET
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266
Content-Length: 554

-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="json"

{"nome" : "Flor", "descricao" : "..."}
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain

Content of a.txt.

-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<!DOCTYPE html><title>Content of a.html.</title>

-----------------------------9051914041544843365972754266--

As far as I can see, this is outside the standard that is already being used in all other requests, which is the content-type: application/json, as well as being a very dirty girl.

3) Separate file upload logic from media data upload.

This seemed the most pleasant and, from what I read and talked about, seemed more organized. But I’ve never done anything like this, having no implementation experience, and I also don’t know if this is a standard in REST.

One of the tips I saw, for example, was to upload the file, return the ID this upload, to be used in sending the "extra data" to create the resource on the server referring to this file.

My question is:

  • Of the above options, which one would be closer to REST?

  • If it is feasible to implement the third option, there is some standard to define the content-type file and what kind of response status I could return?

I would like to have a few examples on the third option, since it was the only one I did not implement, and I have no idea how to do something similar.

  • 2

    In my view, the third option can cause a serious problem: inconsistency or data anomaly. Allowing data to be entered by parties has some problems, what if the device shuts down after the first request and before starting the second? How it will be validated so that a malicious user does not register several times a part only of the data, which can cause some 404 and ordinary users do not understand anything

  • 2

    @Guilhermecostamilam but the idea was actually to create, for example, a table that would assign the upload to a user. I would return the id of that "upload" for the user to associate it to the "metadata" that would need to be sent along with the file, After creating the resource data, it would move the file on the server to where it wanted, since the new request would inform the id of that file and then delete the resource from the old file created.

  • 1

    That would make the feature more complicated, what if he sends the file and doesn’t pass the metadata later? Will you keep a useless file on your server? Will you create a routine to delete those that exceed 24 hours? I’m not saying it’s the worst, but the most complex, maybe a simpler alternative is preferable

  • 1

    I was in doubt, send the data json by the body of the request has limit? It escapes from the standard Rest?

2 answers

7

There is a REST specification for uploading files?

Sort of, Webdav, which can be considered proto-REST.

  • Of the above options, which one would be closer to REST?

I prefer the option 3, because it facilitates the life of the programmer in certain aspects. Despite being the most laborious option.

In that specific case, the API has the role of managing the file. It could be done this way:

  1. Requisition POST /api/midias to add metadata, initiating with empty file content. Being request Content-Type: application/json, sponse Content-Type: application/json.
  2. Requisition POST /api/midias/1/conteudo to add the contents of the file. Being request Content-Type: see answer below, sponse Content-Type: application/json. Number 1 means the media ID.

Thus, the download of the file itself, would be through GET /api/midias/1/conteudo, and GET /api/midias/1 to consult metadata.


  • If it is feasible to implement the third option, there is some standard, to define the content-type of the file and what kind of status reply I could return?

To /api/midias/1/conteudo would use multipart/form-data or/and application/octet-stream(which is simpler). But if the file has the MIME type itself, it is worth the attempt (it may complicate the CORS configuration later). Return status the same way as your other Apis. If you are 200 for success, and 400 to error, why would it be different in this case?

7

Short answer: nay. HTTP supports direct upload, and REST specifies Urls - this is what will get closer.

As for your options, maybe the most interesting thing is something that looks like your third option, but in reverse order: you make a JSON POST with the file metadata - name, and size, including - and receive, in the reply, a URL that can be used to upload the complete file.

Upload, in turn, you do as an HTTP post of the file - it doesn’t have to be multi-part encoded - you can simply send the normal http headers -

Content-Type: image/jpeg
Content-Length: XXXX

followed by your file - the entire "body" of the HTTP message will be the contents of the file. This method still has another advantage - I haven’t visited the HTTP specifications for a long time, but I believe it is possible to put in the header that you are "continuing a previous request" and an "offset" - and therefore send a large file, such as a video file, in several separate requests - relaying those that fail.

You haven’t mentioned which language/framework you’re using on the server side, but I believe the vast majority allow you to have a "lower level" view that interprets the headers and the HTTP cup themselves. The URL itself will already include a token that you relate to in the database with the previous JSON post - so you know: what the file is related to, and if the person using this address is authorized to do so (just be a randomized token in the URL- it will serve at the same time as identifier and authorization for the file).

I had started to write this answer - I went to do a quick search to confirm if HTTP posts with a pure file are allowed, and I ended up coming up with an article about uploads with REST - and the author made more or less the same considerations I did here - I mean, it seems like a sensible way to go. (And that still allows future upgrades type - the Feature to break the file into pieces and do segment uploads need not be implemented at first).

The article: https://philsturgeon.uk/api/2016/01/04/http-rest-api-file-uploads/

Browser other questions tagged

You are not signed in. Login or sign up in order to post.