← home← blog

Building a Backendless Web App in 2 Hours

02 Mar 2014

iHi.im →

Preamble

Jack Smith and myself made a web app a couple of years ago called iHi. It ran on a PHP/MySQL backend and some Google Maps driven JavaScript on the client. The user would hit the site, the PHP would allocate them a unique URL (stored in the database) and they could share the URL with friends, essentially sharing their location. The hosting expired on that site, so I pulled it offline and only just sat down last week to rewrite it with no database or backend to speak of.

I hope to show you a couple of tactics for writing backend-less apps below. Here goes.

Templating

The app itself is only 3 "views". A start view, a share view and a viewing view. Templating is a really fast, usable way to bring HTML rendering and control into your application. No more building up HTML strings directly in the JavaScript, but maintaining a separation of concerns so we can work on our HTML separately from our JavaScript logic/app code.

Stateful URLs

JavaScript apps which just replace content on the page when the user is switching context are just disappointing. The web is built on URLS, so let's keep that going in our application. A nice way to manage state in a single page JavaScript app is by the URL. Because we have no server-side logic, HTML5 PushState is out unfortunately, because as soon as the user refreshes the page, they're going to hit the server, and the server won't have any knowledge about the URLs we're going to set up. So our only option for routing is hash-based navigation, which we can listen out for changes in the JavaScript like so:

window.addEventListener('hashchange', router.init);

Every time we, programmatically, or the user, manually, changes the URL with a different hash value, we can handle that event and act upon it. The action, in this app's case, would be to process a new Google Maps instance and render the appropriate template into our main content area.

Storing data...in the URL!?

So, without a database to hold our data, what can we do? Well, we can encode it and store it in the URL, then when another user hits the link, we can parse the relevant data and show them the relevant map location. Because we have a "#" symbol in our URLs, I used the Bit.ly API to shorten our link for easy sharing purposes (I'll get onto that in a minute). We can take the first user's latitude and longitude from Google Maps/HTML5 Geolocation and pass it to Bit.ly like so:

var linkVal = 'http://' + window.location.host + '/%23location,data=' + JSON.stringify({
	longitude: data.longitude,
	latitude: data.latitude
});

This will be the link that the user will come into the app on (maybe from Twitter, or an email), which might look like:

http://ihi.im/#location,data={"longitude":-1.9388282,"latitude":52.079217}

Which we can easily parse to work out where they are (to plot them on the map from Google), like so:

var path = window.location.hash.slice(1),
    data = JSON.parse(decodeURIComponent(path.split('=')[1]));

A small gotcha with doing this method: without the decodeURIComponent method, iOS was converting the object in the URL to entities which weren't parse-able by JSON.parse(). Desktop browsers didn't seem to encode it, so we were fine, but the above code was required to make it work on iOS.

From this point, we have a lovely JavaScript object, ready to do what the hell we want with and we haven't spoke to any databases!

Bit.ly shortening API

Like I mentioned earlier, I used Bit.ly for easy URL sharing. The whole code to shorten a link through Bit.ly looks something like this:

var linkVal = 'http://' + window.location.host + '/%23location,data=' + JSON.stringify({
	longitude: data.longitude,
	latitude: data.latitude
});

var url = "http://api.bit.ly/v3/shorten?login=benhowdle89&apiKey=R_01f556645116f8620103c31e48d7f2a2&longUrl=" + linkVal + "&format=json",
    xhr = new XMLHttpRequest();

xhr.open('GET', url);
xhr.addEventListener('readystatechange', function() {
	if (xhr.readyState == 4 && xhr.status == 200) {
		var json = JSON.parse(xhr.responseText),
		    bitlyLink = json.data.url,
	}
});
xhr.send();

So we can quite easily use this new URL to populate a tweet intent link or a mailto link.

Misc

I hope you've seen a few tricks and tips to get you going building backend-less apps. They're a fun challenge and they make you think in totally new ways, ie. techniques aren't quite so mature and proven as server-side rendered applications.

A big ol' disclaimer should probably be (you've probably wondered it all the way down to here), of course iHi does run on a server (it's hosted on GitHub pages), but by "backendless", I mean that none of the logic is on the server and we don't use any databases; client-side techniques only around here.

Quite a few techniques above were inspired by Sacha Greif from his Side Project slides, so shout out to that.

Go play with the source on GitHub and play with the app itself - iHi.im.

Oh, and the "2 hours" part, although slightly link-baiting, is completely doable...just use some/all of the techniques above!

I'm available for hire

Hire me