A Third-Party Integration in JavaScript

Nowadays, almost any third party application has some kind of backend API where you can interact, or an external JavaScript library that you can load and use, depending on the service.
However, sometimes you have to deal with a third-party integration in javascript, and very limited applications, with a lack of APIs support, and/or documentation.

For instance, a few weeks ago I had to integrate a new shipping method in the checkout process of an eshop. Basically, the user had to go to the carrier website, and select a pick up place. There wasn’t any API where I could retrieve the available places, so the user actually had to interact to the external website.
The available options for the integration were:

  • Redirect the user to the carrier’s page when he selects the specific carrier, and pass a callback URL. Then, once user selects the pick up place, the carrier’s page would redirect back the user, passing all the selected data by GET.
  • Open an iframe when the user selects the carrier as shipping method, passing a callback URL. Then, when the user has chosen the place, the carrier’s page would redirect the parent window to the given callback.

Neither of them were desirable at all, as the first one would require the user to temporarily leave the eshop, and the second one would require to refresh or move to another page, and we have a one-step checkout process.

After discarding the first option, I was wondering how could I retrieve the user’s data from the carrier’s page without refreshing the page, because on the shipping method step, the user had almost finished fulfilling the checkout form, and we needed to preserve all his data.
Firstly, I thought of performing an ajax petition to save the user’s data on session before opening the iframe, and then retrieve them on the page refresh. I didn’t like it at all, though it would probably work, so I discarded it. I had a look at the carrier’s page to see how did they perform the callback redirection. This is the interesting part:

if(parent!=null){
		parent.location=url;
	}else{
		location.href=url;
}

Basically, if the parent window is defined, its location is changed, otherwise, the current window is changed.

Although I don’t like the iframes, I thought that if i put the carrier’s iframe inside another iframe, then, its parent would be my iframe and not the main page, so the checkout page wouldn’t be refreshed and I just would need to retrieve the data.
It seemed a very hackie but “acceptable” solution, so it worth trying. Unfortunately, I realized that chrome and firefox (I didn’t bother to try IE) wouldn’t like it. It seems that it’s not allowed/safe that an iframe attempts to change it’s parent’s location, if it’s an iframe as well. After some research I figured out that I had to think of another way.

I tried to find an alternative way, such as trying to capture iframe’s calls to its parent with javascript, or triggering an event before the window.location was modified, but I had no luck. Eventually, I found that there is an event triggered when the url hash changes (ie: mypage.com/ => mypage.com/#whatever). Maybe I could send the current url as callback concatenated with the character “#”, so when the iframe attempts to change the parent location, it would actually be changing the hash and I would be able to capture the data avoiding refreshing the page.
It seemed a good idea, taking into account the circunstances, so I tried it, but unluckily, as the callback URL is provided by GET, the “#” was being interpreted as hash of the carrier’s url, and the callback variable wasn’t actually containing the “#” character, so the redirection didn’t work as I expected. I mean, the iframe was like this:

<iframe src="carrierspage.com/blablabla?callbackurl=http://mysite.com/checkoutpage#" height="240" width="320"></iframe>

I wanted that the value of callbackurl (on the carrier’s page) was something like “http://mysite.com/checkoutpage#”
But it was actually “http://mysite.com/checkoutpage”, because the “#” was being interpreted as part of the carrier’s page.

After some unsuccessful attempts, I tried url-encoding the character “#”:

<iframe src="carrierspage.com/blablabla?callbackurl=http://mysite.com/checkoutpage%23" height="240" width="320"></iframe>

Voila! It worked smoothly, when the user picked up a place, all the data was being added to the hash of the checkout page, and I just needed to parse the data by JavaScript.

I created a function that would be triggered on the event window.onhashchange, performing the parsing of the url’s hash, clearing the URL, and more uninteresting stuff that is out of the scope of this post.

It was almost finished. I was proud of my -hackie but working- achievement, but then I tested it on IE7. Everything seemed to work, but the onhaschange event.
After some research I discovered that this event is not supported on IE7. Many people suggest an acceptable approach, which consist in constantly checking the location with a timer interval. It’s not so beautiful, but well, it’s IE7.

Finally, I ended up combining both solutions: If the browser is IE7, set the timerinterval and wait for changes on the URL, otherwise wait until the onhaschange event is triggered.

That’s it, I hope it can help you if sometime you get stuck in a similar situation.

Please, remember that any suggestions/improvements/alternatives are more than welcomed.