Design of cross domain POST API in Javascript

Hi There,

As all of you know that cross domain POST is not allowed in javascript. At Times few APIs require you to do POST, such APIs are extremely hard to use in pure javascript mashups. We can not move back to GET method because the input set is limited ( restricted by length of URL) on GET.  So in this article I am proposing a design of POST API which will be javascript friendly.

Lets say I am designing a API which requires "text"  as input in POST, and returns an JSON response.

                 API URL: http://api.xyz.com/myapi 
                 API Input:  text as POST field.
                 API Output: JSON object.

1) How client can invoke the API?
 of-course cross domain HTTPXMLrequest is not allowed
Another popular technique of  injecting script tag with callback to get cross domain JSON (jsonp) can not be used becuase it can only do GET request. so how to do a POST to differnet domain? Solution is you can use iframes.
  1. Create an iframe in javascript
  2. Create a form whose method is POST, action is API URL and target is the iframe.
  3. Create hidden input as "text" and assigned the value whatever you want.
  4. Submitted the form.

Here is the code

function crossDomainPost(url, text) {
    // Add the iframe with a unique name
    var iframe = document.createElement("iframe");
    var uniqueNameOfFrame = "sum";
    document.body.appendChild(iframe);
    iframe.style.display = "none";
    iframe.contentWindow.name = uniqueNameOfFrame;

    // construct a form with hidden inputs, targeting the iframe
    var form = document.createElement("form");
    form.target = uniqueNameOfFrame;
    form.action = url;
    form.method = "POST";

    // repeat for each parameter
    var input = document.createElement("input");
    input.type = "hidden";
    input.name = "text";
    input.value = text;
    form.appendChild(input);
    document.body.appendChild(form);

    form.submit();
}

2) How to read the output back?
Now since form is submitted in iframe, whatever is happening in iframe is not accesible to main window and vise versa due to cross origin restrictions imposed by browsers. So this is where you should follow my proposed design,
The API maker will return an HTML page with script block in it. Script block should send a message (HTML5 cross frame messaging API) to parent frame.
e. g. Output of API  goes like this.
<html>
<script>
var json={your-data}
window.parent.postMessage(json,"*");
</script>
</html>

This is how client will read in his javascript code
window.addEventListener("message", function (event) {
      my_callbac(event.data);
}, false);

Note: message posted is HTML5 API may not be available in many browsers. 


Thanks and enjoy!!!!!

7 comments:

  1. Hi there,
    I have a JSON object - how can I pass this to API using your iframe?

    ReplyDelete
  2. @LJ

    Stringify the JSON and pass it as text to crossDomainPost function.
    I am not sure whether I answered your question or not

    ReplyDelete
  3. Yes! Thanks, this works great.

    ReplyDelete
  4. In case you have HTTP page with some POSTs to HTTPS resources on the same server, and you are doing HTTPS POST request (which is cross domain, due to differing protocol only), it can be implemented that the iframe receives a 302 (Moved Temporarily) response with Location header that redirects the iframe to another location, a HTTP location, such as http://samedomain/getMeResponseForPreviousHttpsRequest, on the same domain/server, and that HTTP response contains the actual response data for the previous HTTPS request. Then you are allowed to read the contents of the iframe with main page javascript.

    ReplyDelete
  5. Thanks for the inspiration! But what if I want to set a http header? My problem is I am trying to use twitter api via javascript, but I need to post it with http header. Seems it's impossible?

    ReplyDelete
  6. @李世華
    No you can not set header by this method :(

    ReplyDelete
  7. There is a issue with this in IE. I get error Permision denied. I thought that was xss filter and turn it off, but i still get this errror. Please help? :(

    ReplyDelete

Your comment will inspire me, Please leave your comment