PROGRAMMING REST APIS

In this article we will explore how to handle file uploads in REST API frameworks. Earlier I have published a few articles related to REST APIs where we have covered all the Basics, and the Constraints to make an API Restful, and then a couple of hands-on (Part 1, Part 2 and Part 3).
This time, we are going to see something different. This does not really impact on the RestFul-ness of the API, but a useful feature to have while building an API system. i.e. handling of file uploads via an API request. This article is going to be short as there’s not much to explore in it. I’ve used Django Rest Framework to develop the APIs and Postman to test them.
Okay this is what the API looks like. Simple one, only a post method which accepts a request and returns the data in the request itself.

Hitting the above API, if we send raw data in JSON format (with Content-Type header set to application/json), the output contains exactly the same data that we are sending in the request. But when we hit the API with a file in the request (with Content-Type header set to image/jpeg), the response is ‘Unsupported Media type ‘image/jpeg’ in request’. So basically, API was able to understand the JSON data in the request, but not a file type of data.
Parsers
An API by Django REST Framework has a default set of parsers that it uses to detect the type of the data in the request. The list of parsers in are JSONParser, FormParser, MultiPartParser, and FileUploadParser. JSONParser parses the JSON data in a request, FormParser parses the HTML form data in a request, MultiPartParser parses the HTML form data with file in a request, and FileUploadParser parses the file data in raw format. In this article, we are going to explore the MultiPartParser and the FileUploadParser.
How Django RF knows which Parser to use?
Well, let’s take a look at the default list of parsers that the API is using to understand the request type.
The default parsers here in our API are JSONParser, FormParser and MultiPartParser. API determines the parser to use by looking into the Content-Type field in the header of the request. i.e. The API looked into the Content-Type for the first request, which was application/json and hence selected the JSONParser, whereas for the second request with Content-Type image/jpeg, the API had no parser in the default list available. That’s why it threw the message saying ‘Unsupported media type’.
Well, there was a MultiPartParser available, but it did not solve our purpose. Let’s see why.
MultiPartParser
This parser is used to handle file uploads in a HTML form. This is different from our case above, as in our case the request had a raw file, not a HTML form.

The API above is debugged at runtime to see how MultiPartParser works. This parser is enabled by default, so if we hit the API with a file in a form-data, then the backend will be able to understand the content type in the request. Hence, request.data produces the querydict with filename and its format in the output.
Well, if we are uploading a file from the web, then this is the way to go. But what I was looking for was uploading a Raw file.
FileUploadParser
For a raw file, we need to use FileUploadParser in our API. And as it’s not there in the default set of parsers, and we need to tell our API manually to use this.

In the code snippet, we see that the default parser is changed to a list containing only FileUploadParser now. And there was no error as well, as the API was able to understand the data in the request. Still I had to do one more update here in the client side, i.e. there is no way the API is going to get the name of the file, so it won’t be able to access the file, unless we have a way of providing the name externally. So we add another header for the file name like this: ‘Content-Disposition: attachment; filename=healthy_leaves_1.png’.
This made sure that the API gets to know the name of the file, and gets access to it from the request.
Well, this only ensures that the API knows that the request has a file type of data in it. Backend still needs to handle the specific file uploads depending on their types. Like in the request above, we are sending an image file. To read this, we still need to use the Image libraries available in Python.

Conclusion
Well, that’s it for this article. This was again a part of the Rest Api series that I have published earlier. We explored two different ways to handle file uploads in a REST API, MultiPartParser, which can be used to handle a file upload from the web, and FileUploadParser, which can be used to handle raw file uploads.
Thank you.
References: