Have you ever stumbled upon the case of having files (pictures, documents, videos) related to one of your entities? If you have, you probably wondered what is the best way to send your JSON data and those files to the REST API. There are several approaches and each one has its advantages and disadvantages.
Let’s first define our business case. For example, we have an e-commerce platform with а modern architecture – REST API and Angular/React.js web application. We have products with simple characteristics like name, brand, color, size, price, etc. All those are easy to send as JSON from the web to your REST API. But we also have pictures and videos we want to attach to our products, which we want to attach while creating or editing the product.
Depending on the UI, you might have an option to work with all those independently. 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, a standard HTTP request takes one type of data as a body but here we deal with two of them. The simplest way to implement our functionality is to send several HTTP requests one after the other. First, we send our JSON, then the picture, and lastly the video. This is an example order. In reality, you may need to send them in a different order, but the idea remains the same.
- Simple to implement
- Synchronization between requests is needed – each request waits for the previous to finish before it is sent. 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.
- No need of synchronization – everything is sent together
- Transactional behaviour is easier to achieve. You still may 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).
- The complexity of implementation – it may vary depending on the used technologies
My weapon of choice for this situation is using Multipart HTTP requests. It may take longer to implement them initially, 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 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, my REST API is declared in the following way:
This snippet creates a REST API for POST that accepts product data as JSON, picture as binary 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 declare the call as type multipart/form-data, we add all parts and we are 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.
Simple JS code snippet that resolves the issue:
The key moment 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, you can subscribe to our newsletter. There are plenty of exciting stories coming up.