Multipart file upload in v 0.5+

Back in 0.3.9 we had the apistar.parsers.MultiPartParser which we could use for file uploads. I am a little in the dark now as to how to accept file uploads in the 0.5+ versions. Can anyone help?


I don’t know if this component still works but used to in 0.3.9.

FormFiles = Dict[str, FileStorage]

def get_file_array(request_data: http.RequestData) -> FormFiles:
    return {
        name: file_storage
        for name, file_storage in request_data.items()
        if isinstance(file_storage, FileStorage)

component = Component(FormFiles, init=get_file_array)

Is FileStorage in this case the werzeug.datastructures.FileStorage?

Yes, was it. Hope that still is.

Ok, finally had time to look at this. I went back to the 0.3.9 implementation and just updated it for APIStar >= 0.4.


How this relates to ?

(partially answering myself)

Here is what I was able to figure out by looking at the code and scratching my head:

@androiddrew’s Gist seems to resembles the code in codecs/multipart, I can’t say if it took inspiration from it or is it just a case of grate minds thinks alike.

Anyway, it seems that MultipartCodec is only used by RequestDataComponent but its’ resolve method has no type annotation, so I can’t really know what it returns. I can guess it has something to do with http.Request - The incoming request. Includes url, method, headers, and body attributes, but I can’t say for sure, and in any case I don’t know how to use it to deal with upload files.

What I would like to know is how to get the incoming multipart stream and read it in chunks.

Can anybody point to an example that do something similar?

see test.http line 75.
the value is a

When I wrote this I was still stuck in the 3.9 mode of thinking, so that is why I went back to the old implementation and just updated it. I think that is around the same time that the docs.apistar landed and since I didn’t see anything in there about codecs I wasn’t even considering poking around other modules.

I actually don’t know how to use these…still.

Ok, answered that pretty quickly. The RequestData component is simply what was decoded. I’d really like to see Codecs show up in the documentation. I think I am really missing out on a lot of stuff here. Any help would be much appreciated.


@jgirardet, thanks. The test and the link you pointed at was what I needed to have a solution for uploading a file.

This is however a low level solution, it forced me to scan the request data manually for the upload fields, and worst it does not indicate those fields in the generated API doc.

It seems to me that there should be an upload validator. Is this correct, and we need just one brave soul to implement it, or am I missing some fundamental point and that is the wrong way to do it?

And one more thing: my end-point accepts additional arguments, and thus the end-point’s doc say:

The request body should be "application/json" encoded, and should contain an object with the following attributes.

while AFAIK it should say "multipart/form-data" and not "application/json", and I can’t find in the documentation how to change this.

Have you filed an issue on the github page?

@androiddrew I hesitate to open an issue, before I have a strong belief that this is indeed an issue and not something that needed to be attributed to my stupidity or ignorance.

@chenl If it is invalid they close, or if they are unsure it remains opened until someone verify or close. I don’t bother with it.

This is how I did it.
I’ve tested it and it’s working.

def upload(request: http.Request, body: http.Body) -> dict:
        md = MultiPartCodec().decode(body, dict(request.headers))
        file_storage: FileStorage = md.get('file')
        filename = os.path.join(UPLOAD_FOLDER, str(file_storage.filename))

        return build_response(success=True, data="Upload complete")

    except Exception as all_exceptions:
        return build_response(error=str(all_exceptions))

Full code: apistar_multipart