sajad torkamani

The problem

Suppose you have a REST API endpoint at https://api.example.com/article that accepts a JSON payload like this:

{
  "title": "Some title...",
  "body": "Some body..."
}

Suppose you now need to also accept a featuredImage field that allows your API clients to upload a file. How can you support such a field in an endpoint that currently accepts only JSON? You have three options.

The options

1. Base64 encode the file (JSON request)

Keep the request payload as JSON but but require the featuredImage field as a base64 encoded string. API clients will have to base64 encode the string before sending and the server will have to decode the string to obtain the file contents.

2. Send the file and JSON in a multipart/form-data request (multipart/form-data request)

Change the request payload to multipart/form-data and send the file as a standard file field and the JSON data in a separate JSON-stringified string. So you might have JavaScript like this:

const formData = new FormData()
formData.append('file', someFile)
formData.append('json', JSON.stringify(someJsObject))

3. Store the file on the server and use its ID in the JSON payload (JSON request)

Make two requests. First, store the file on the server – perhaps using a generic endpoint like POST /media-objects with a multipart/form-data request. Have this endpoint return the ID of the file that just stored.

Next, call your JSON endpoint and pass in the ID of the stored file to associate the resource with the file. So perhaps with a request payload like the below where featuredImageId would have come from your first request.

{
  "title": "Some title...",
  "body": "Some body...",
  "featuredImageId": 123
}

My preferred option

I prefer option #3 from above as it means both the client and server code are still dealing with JSON for the main endpoint. Parsing a lot of JSON from a multipart/form-data on the server can introduce subtle bugs related to parsing and mapping string fields to the correct field types of your entities (e.g., PHP / Python data types). It might also mean you can’t use easily your framework’s JSON mapping features.

Related links