Have you ever stumbled upon the case of having files (pictures, documents, videos) related to one of your entities?
If the answer’s yes, you’ve probably wondered about the best way to send those files to the REST API along with your JSON data. There are several possible approaches – each with its own pros and cons.
First, let’s define our business case. Imagine we have an e-commerce platform with а modern architecture – REST API and Angular/React.js web application. We have products with simple characteristics such as name, brand, color, size, price, etc. Sending those to your REST API is easy. But we also have pictures and videos we want to attach to our products while editing them.
Depending on the UI, you might be able to work with all those independently. But let’s look at the other option. We have a wizard and all the data is available in the end. In this case, we have to follow the Atomicity principle – either all changes are successful or all should be reverted.
Use Two HTTP Requests – JSON and Binary
Typically, the body of a standard HTTP request contains one type of data. Here, though, we’re dealing with two of them. The simplest way to implement our function is to send several HTTP requests one after another. We send our JSON first, then the picture, and finally the video. This is an example -n reality, you may need to use a different order, but the idea remains the same.
Advantages:
- Simple to implement
Disadvantages:
- Synchronization between requests is needed – each request is only sent once the previous one is complete. Otherwise, you may have racing conditions in the backend – two modifications over the same object at the same time.
- Transactional behavior (either all changes are successful or data is reverted to the last consistent state) is difficult to achieve in this case – your REST API has already done the changes before the next request arrives.
Multipart HTTP Requests can Have Both Multiple Data Types in the Body and Multiple Data Objects
This is a more efficient way to approach the situation. We can have all of our data in the same request – JSON, picture, video.
Advantages:
- No need for synchronization – everything is sent together
- Transactional behavior is easier to achieve. You may still need to write additional logic to revert previous data changes if you store your binaries in а place other than your database (which is the commonly accepted best practice).
Disadvantages:
- The complexity of implementation – it may vary depending on the used technologies
My weapons of choice for this situation are Multipart HTTP requests. They may take longer to initially implement, but having a clearer idea of how to handle the transactions is worth it.
Easier Said Than Done?
In order to establish multipart request communication, we need to perform the following steps:
- Prepare the REST API to accept such requests – this may vary depending on the technology used.
- Create multipart requests in the Web application – it may also vary depending on the technology used, but my example is using plain JS, which should be easily converted.
Using Java and Spring boot, I declared my REST API like this:
This snippet creates a REST API for POST that accepts product data as JSON and picture and video as binary:
- @PostMapping defines the type of the reques
- MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE declare the accepted data type
- @RequestPart declares specific data type followed by Product (our class) or MultipartFile (Spring predefined class for binary objects)
Now we just declare the call as type multipart/form-data, we add all parts and we’re done?
Not quite. The problem is that by default, all parts of a multipart request are either string or binary. For those unfamiliar with Spring, in order to parse JSON into a Java object, you need to explicitly declare your request part as JSON (this will use the default parsing with Jackson). Otherwise, you will need to take your product as String and parse it yourself.
Here’s a simple JS code snippet that resolves the issue:
The key here is adding the type ‘application/json’. Here we just create a binary object from the JSON and the type and then append it to the request body.
If you are using Postman, you can simply choose Content Type for each request part.
Which approach would you choose?
If you find this article interesting and wish to read similar content, go ahead and subscribe to our newsletter. There are plenty of exciting stories coming up.