Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composing multipart/form-data with a different Content-Type on each parts with Javascript (or Angular)

Wrong question asked, see my update below

I need to integrate my AngularJS Project with an existing RESTful API. These API consume POST request which upload a file, and also submit the form data in a request. Unfortunately, one of the form input requires to be in Content-Type: Application/json.

After search on the web, I could only POST with Content-Type: multipart/form-data in which each of the parts does not have a specific MIME. How can I compose my multipart/form-data with a different MIME for each parts in Javascript?

POST /api/v1/inventory Host: localhost:8000 Origin: http://localhost:9000 Content-Type: multipart/form-data; boundary=------border  ------border Content-Disposition: form-data; name="owner"  john doe ------border Content-Disposition: form-data; name="image"; filename="mybook.png" Content-Type: image/png   ------border Content-Disposition: form-data; name="items" Content-Type: application/json  {"name": "Book", "quantity": "12"} ------border-- 

Relevant References:

  1. https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects
  2. REST - HTTP Post Multipart with JSON
  3. http://code.activestate.com/recipes/578846-composing-a-postable-http-request-with-multipartfo/
  4. application/x-www-form-urlencoded or multipart/form-data?
  5. https://stackoverflow.com/a/9082243/764592

Update

Apologize for asking a wrong question. The original problem is that, I can see the server calling the logic something like,

func POST(req):      owner = req.owner // This is string      image = req.image // This is file object      itemQuantity = req.items.quantity // Items is an object with attribute quantity      itemName = req.items.name // Items is an object with attribute name 

I have also managed to figure out how to submit such a post request. I will post my answer below.

Once again sorry for asking a wrong question.

like image 482
Yeo Avatar asked Jul 02 '14 15:07

Yeo


People also ask

What is content type multipart form data?

multipart/form-data [RFC1867] The multipart/form-data content type is intended to allow information providers to express file upload requests uniformly, and to provide a MIME-compatible representation for file upload responses.

What content type is FormData?

Multipart/form-data is ideal for sending non-ASCII or binary data, and is the only content type that allows you to upload files. For more information about form data, see http://www.w3.org/TR/html401/interact/forms.html.

How is multipart form data encoded?

Multipart/form-data is one of the most used enctype/content type. In multipart, each of the field to be sent has its content type, file name and data separated by boundary from other field. No encoding of the data is necessary, because of the unique boundary. The binary data is sent as it is.

What is JavaScript FormData?

In JavaScript, a FormData object is a common way to create a bundle of data to send to the server using XMLHttpRequest or fetch. It replicates the functionality of the HTML form element. We can think of it as an array of arrays. There is one array for each element that we want to send to the server.


2 Answers

According to the documentation of FormData, you can append a field with a specific content type by using the Blob constructor:

var formData = new FormData();  formData.append('items', new Blob([JSON.stringify({     name: "Book",     quantity: "12" })], {     type: "application/json" })); 

After careful observation, it turns out that it will send the part as follows:

Content-Disposition: form-data; name="items"; filename="blob" Content-Type: text/json 

The only alternative, safe from building the whole request yourself is to pass a string value:

formData.append('items', '{"name": "Book", "quantity": "12"}'); 

This, unfortunately, doesn't set the Content-Type header.

like image 104
Ja͢ck Avatar answered Sep 19 '22 14:09

Ja͢ck


Mistake #1: I mistakenly assume that the items has to be a json, so that we can call its attribute.

Solution: To submit a multipart request that contain a file and an object like format is very simple.

form = new FormData(); form.append('items[name]', 'Book'); form.append('items[quantity]', 12); form.append('image', imageFile); form.append('owner', 'John Doe'); 

So thus the request header and body will looks something like this

POST /api/v1/inventory Host: localhost:8000 Origin: http://localhost:9000 Content-Type: multipart/form-data; boundary=------border  ------border Content-Disposition: form-data; name="owner"  john doe ------border Content-Disposition: form-data; name="image"; filename="mybook.png" Content-Type: image/png   ------border Content-Disposition: form-data; name="items[name]"  Book ------border Content-Disposition: form-data; name="items[quantity]"  12 ------border-- 
like image 44
Yeo Avatar answered Sep 17 '22 14:09

Yeo