Guide to use multipart/form-data

To use multipart/form-data, the request needs to be structured to send different parts of the body separately or all the parts together. In Spring Boot. multipart requests are used for sending data of many different types separated by a boundary as part of a single HTTP request.

For different languages/frameworks the structuring process may differ and may depend on the libraries being used to create the request.

But generally to structure a request, the parts need to be set as per requirement and proper boundaries are needed to be set in between them.

Boundaries in multipart/form-data

A multipart request can contains fields of different types, these are separated by boundaries. Most libraries set these boundaries automatically but in come scenarios this process needs to be carried out manually.

This helps the server differentiate the different parts and parse them as per requirement but if done manually it must be unique within the request to avoid conflicts with the actual data.

Sending individual parts in a request

  • Using a high level library
    High level libraries like OkHttp handle multipart/form-data request automatically and can send all the parts or individual parts by handling the boundaries.

    • Sending single part using a library like OkHttp can be done as follows:

      val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("text", "sample data string") .build()

       

  • Using low level libraries
    To send individual parts in low level libraries where headers are not managed, the boundaries may needed to be set manually in code, an example is as follows:

    • Define a unique boundary string.

      String myCustomBoundary = "----myCustomBoundary";
    • Then the boundary can be added to the Content-Type header as follows:

      HttpURLConnection httpConnection= (HttpURLConnection) new URL("sample-url").openConnection(); connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + myCustomBoundary);
    • Alternatively one can insert the boundary string between the different parts of the request body

      • The boundary string must be a unique identifier

      • The boundary string must begin with 2 hyphens --at the start and towards the end.

         

Sending multiple parts in same request

Multiple parts are usually handled automatically in high level libraries like OkHttp, where the boundaries are set automatically as follows:

Once donr the request body can be sent as part of request

Sending of multiple parts using low level libraries where boundaries are not handled is explained here.

Content Disposition Header

This is an important header and must be included as part of each part of a multipart request, this is because the Content-Dispositionheader explains how data needs to be processed.

This header helps the server identify whether the part of request is a form or file field. Which can then be used to associate the parts to expected fields.

  • Content-Disposition for form data:

     

  • Content-Disposition for file data:

     

Here, the name is the field name expected by server, and filenameis used for files to let the server know with a default name.

Content-Type Header

Specifying Content-Typeheader for individul fields is optional but can be helpful when dealing with files or sending the data individually. And doing so ensures each part is interpreted correctly. Without explicit content type header, especially for non-text files, the server might misinterpret or improperly parse file data.

  • For text fields the Content-Typeheader is text/plain, and for specific types of data like JSON it is application/json, for other data types like XML this header can be set accordingly. If this header is not provided, servers default to text/plain, but setting it explicitly can help.

  • For files, specifying the Content-Type helps the server identify the file’s MIME type, for example:

    • Images are identified using image/jpeg

    • ZIP files are identified using application/zip

Data Encoding

This applies to text or string fields epecially for non ASCII languages containing special characters. For these fields UTF-8encoding is provided as part of header, because UTF-8 is most commonly used and supports almost all characters. Without specifying the character encoding, special characters might get misinterpreted.

String Length

Some servers have a default limit on the length of data sent via text fields in a multipart request. For such scenarios it is suggested to chunk large text into separate parts or fields.

Apache HttpClient in Java or OkHttp in Kotlin support multipart streaming, where data is sent in chunks without loading the entire text into memory at once.

Some other considerations when dealing with large strings of data are:

  • URL encoding: sometimes it is recommended to URL-encode text fields if they have special characters like hyphens, ampersands, etc as they can interfere with boundary parsing.

  • Whitespace and Line breaks: Leading or trailing whitespaces or line breaks may impact parsing of text fields as servers automatically trim these characters. Adding \r\ninstead enures clarity and proper separation.

  • MIME for structured data: When using structured data like JSON or XML use Content-Typeappropriately, for example application/jsonand application/xmlrespectively, as the servers default to text/plainin most cases.