Posting a File and Associated Data to a RESTful WebService preferably as JSON

In an application I am developing RESTful API and we want the client to send data as JSON. Part of this application requires the client to upload a file (usually an image) as well as information about the image. I'm having a hard time tracking down how this happens in a single request. Is it possible to Base64 the file data into a JSON string? Am I going to need to perform 2 posts to the server? Should I not be using JSON for this? As a side note, we're using Grails on the backend and these services are accessed by native mobile clients (iPhone, Android, etc), if any of that makes a difference.

30.1k 19 19 gold badges 58 58 silver badges 97 97 bronze badges asked Nov 3, 2010 at 2:07 35.7k 21 21 gold badges 112 112 silver badges 219 219 bronze badges Send the metadata in the URL query string, instead of JSON. Commented Aug 8, 2017 at 15:49 Commented Mar 23, 2022 at 14:42 Does this answer your question? How do I upload a file with metadata using a REST web service? Commented May 24, 2022 at 18:14

11 Answers 11

I asked a similar question here:

You basically have three choices:

  1. Base64 encode the file, at the expense of increasing the data size by around 33%, and add processing overhead in both the server and the client for encoding/decoding.
  2. Send the file first in a multipart/form-data POST, and return an ID to the client. The client then sends the metadata with the ID, and the server re-associates the file and the metadata.
  3. Send the metadata first, and return an ID to the client. The client then sends the file with the ID, and the server re-associates the file and the metadata.
105 1 1 gold badge 1 1 silver badge 10 10 bronze badges answered Nov 3, 2010 at 2:59 38.1k 37 37 gold badges 143 143 silver badges 207 207 bronze badges

If I chose option 1, do I just include the Base64 content inside the JSON string? Or is there something more to it?

Commented Nov 3, 2010 at 3:06

Gregg, exactly as you've said, you would just include it as a property, and the value would be the base64-encoded string. This is probably the easiest method to go with, but might not be practical depending on the file size. For example, for our application, we need to send iPhone images that are 2-3 MB each. An increase of 33% is not acceptable. If you're sending only small 20KB images, that overhead might be more acceptable.

Commented Nov 3, 2010 at 3:14

I should also mention that the base64 encoding/decoding will also take some processing time. It might be the easiest thing to do, but it's certainly not the best.

Commented Nov 3, 2010 at 3:25 json with base64? hmm.. I'm thinking about sticking to multipart/form Commented May 16, 2013 at 0:12 Why it is deny to use multipart/form-data in one request? Commented Jul 16, 2015 at 6:34

You can send the file and data over in one request using the multipart/form-data content type:

In many applications, it is possible for a user to be presented with a form. The user will fill out the form, including information that is typed, generated by user input, or included from files that the user has selected. When the form is filled out, the data from the form is sent from the user to the receiving application.

The definition of MultiPart/Form-Data is derived from one of those applications.

"multipart/form-data" contains a series of parts. Each part is expected to contain a content-disposition header [RFC 2183] where the disposition type is "form-data", and where the disposition contains an (additional) parameter of "name", where the value of that parameter is the original field name in the form. For example, a part might contain a header:

Content-Disposition: form-data; name="user"

with the value corresponding to the entry of the "user" field.

You can include file information or field information within each section between boundaries. I've successfully implemented a RESTful service that required the user to submit both data and a form, and multipart/form-data worked perfectly. The service was built using Java/Spring, and the client was using C#, so unfortunately I don't have any Grails examples to give you concerning how to set up the service. You don't need to use JSON in this case since each "form-data" section provides you a place to specify the name of the parameter and its value.

The good thing about using multipart/form-data is that you're using HTTP-defined headers, so you're sticking with the REST philosophy of using existing HTTP tools to create your service.