Is there a REST specification for uploading files?

15

I have a question almost a month on the subject. At certain point in my application, the user can upload to a library of files.

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

The question that arises in this case is the following: For registration in the database for this file, I also need the other information. And, since the requests usually use the JSON content-type, I wonder how the file would be sent, since JSON has a certain limitation on the characters that can be included in it.

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 the example above, for creating 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 the problems:

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

The basic64 problem is that it increases (and much) the size of the file, making it unfeasible in my case, since we will allow uploading of videos.

2) Use multipart/form-data , sending the file normally, as it does in form requests, and attaching the other data previously mentioned in a "json" field, sending that data as a JSON (serialized) string.

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--

In my opinion, this is not the standard that is already being used in all other requests, which is content-type: application/json , in addition to being a gambiarra of good sows.

3) Separate the file upload logic from the media data upload.

That seemed to me the most enjoyable, and from the little I read and talked about, it seemed more organized. But I've never done anything like that, having no implementation experience, and I'm not sure if this is a REST pattern.

One of the tips I saw, for example, was uploading the file, returning the ID of that upload, to be used to send the "extra data" for creating the resource on the server for that file. p>

My question is:

  • From the above options, which one would be closest to REST?

  • If it is feasible to implement the third option, is there any default, to set the content-type of the file and what type of response status could I return?

I would like some examples about the third option, since of all of these, was the only one I did not implement, and I have no idea how to do something similar.

    
asked by anonymous 22.10.2018 / 16:15

2 answers

7
  

Is there a REST specification for uploading files?

More or less, WebDAV , which may be considered proto-REST.

  
  • From the above options, which one would be closest to REST?
  •   

I prefer the option 3 because it makes life easier for the programmer in certain ways. Although it's the hardest option.

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

  • Request POST /api/midias to add the metadata, initializing with empty file contents. Being request Content-Type: application/json , response Content-Type: application/json .
  • Request POST /api/midias/1/conteudo to add the contents of the file. Being request Content-Type: see answer below, response Content-Type: application/json . The number 1 means the media ID.
  • So the download of the file itself would be through GET /api/midias/1/conteudo , and GET /api/midias/1 to query metadata.

      
    • If it is feasible to implement the third option, there is some pattern,   to define the content-type of the file and what type of   Could I return?
    •   

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

        
    30.12.2018 / 20:53
    6

    Short answer: no . HTTP supports direct upload, and REST specifies URLs - that's what's going to get closer.

    As for your options, perhaps the most interesting thing there is something that looks like your third option, but in reverse order: you do a JSON POST with file metadata - name, and size, inclusive - and receive a URL in the response that can be used to upload the entire file.

    Upload, in turn, you do as an HTTP post from the file - it does not need 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 has yet another advantage that I do not visit the HTTP specifications, 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 video file, in several separate requests - retransmitting those that fail.

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

    I had started to write this answer - I went to do a quick search to confirm that HTTP posts with a pure file are allowed, and I ended up getting an article about uploads with REST - and the author made more or less the same considerations that I did here - that is, it seems to be a sensible path. (And that still allows for future type upgrades - the feature of breaking the file into parts and doing segment uploads does not need to be implemented at first.)

    Article: link

        
    31.12.2018 / 19:13