Using Parse and Trigger.io for cross-platform apps without pain in the back-end

Your new mobile app looks beautiful. Great! But what about all the data storage, user accounts, push notifications and server-side goodness that will keep users coming back for more? Building all that back-end stuff from scratch can be a big job.

Luckily, you can wave away these problems by using Parse, who offer a complete back-end solution for mobile apps.

Trigger.io and Parse work great together. Use Trigger.io to build your native apps for iOS and Android, and also deploying to the web, by just writing HTML5 – and Parse to handle your back-end services. In fact, we’ve built Parse’s native libraries right into Trigger.io Forge so you can access their notification center integration from our JavaScript API.

Let’s take a look at how to set up Parse for your Forge apps. We’ll build a super simple iOS and Android photo sharing app that will allow

  • Uploading photos
  • Viewing a photo stream
  • Sending notifications when new photos are posted

We’ll do all this in a few lines of HTML and JavaScript. The project is hosted on github here.

Let’s get stuck in

To work with your JavaScript and CSS in the app, just include them in your index.html as you might in a normal website:

<link rel='stylesheet' href='css/parse-demo.css'>
<script type='text/javascript' src='js/lib/jquery.min.js'></script>
<script type='text/javascript' src='js/parse-demo.js'></script>

HTML pages don’t get much simpler than this:

<body>
    <button id='upload-photo'>Upload photo</button>
    <div id='photo-container'></div>
</body>

In our JavaScript we’ll set up an object to store our Parse account details (you’ll get these details when you sign up and create an app at parse.com). We’ll also store a name for our default photo stream, to make it easy to add extra streams later.

var config = {
    parseAppId: 'ggJShmbAJh7YTgviK3fpH4QdIIp9az6WMW03swf5',
    parseRestKey: 'Bqjru0vC610FCIl5isczzxjPlv5CsFe8uK0yztez',
    streamName: 'parse-demo'
};

Uploading photos

Let’s begin by looking at how to store photos in our Parse datastore. We first capture a photo using the forge.file.getImage API call.

forge.file.getImage({width: 500, height: 500}, function (file) {
    forge.file.imageURL(file, function (url) {
        $('#photo-container').prepend($('&lt;img&gt;').attr('src', url));
    });
    uploadPhotoFile(file);
});

This will prompt the user to take a photo from their camera or select one from an album. Rather than waiting to display it until the photo has been uploaded, we show it straight away by retrieving an internal url for the photo using forge.file.imageURL. We add an <img> tag with this url to the photo-container div in our HTML.

The upload then happens in the background by calling our uploadPhotoFile function. Let’s take a look at what this does.

var uploadPhotoFile = function(file) {
    forge.request.ajax({
        url: 'https://api.parse.com/1/files/' + (
            new Date()).getTime() + '.jpg',
        headers: {
            'X-Parse-Application-Id': config.parseAppId,
            'X-Parse-REST-API-Key': config.parseRestKey
        },
        type: 'POST',
        files: [file],
        fileUploadMethod: 'raw',
        dataType: 'json',
        success: function (data) {
            uploadPhotoMetadata(data);
        },
        error: function () {
            alert('Problem uploading photo');
        }
    });
};

Here we’re using the forge.request.ajax API to post our image to the the Parse file REST API (Forge allows for easy file uploading through this method, and also sidesteps any cross-domain restrictions where necessary). We authenticate by adding our Parse account information to the headers of the post request and add our photo file to the parameters.

Straightforward, right? But we’re not quite done yet. We might want to store some metadata for the photo (date, location, user, etc) and for that we need to create a Parse object. So if the file was uploaded properly, we call uploadPhotoMetadata with the JSON returned by the upload request.

var uploadPhotoMetadata = function(data) {
    forge.request.ajax({
        url: 'https://api.parse.com/1/classes/Photo',
        headers: {
            'X-Parse-Application-Id': config.parseAppId,
            'X-Parse-REST-API-Key': config.parseRestKey
        },
        type: 'POST',
        contentType: 'application/json',
        dataType: 'json',
        data: JSON.stringify({
            file: {
                '__type': 'File',
                name: data.name
            },
            stream: config.streamName
        }),
        success: function (file) {
            // Upload complete - do nothing
        },
        error: function () {
            alert('Problem uploading photo metadata');
        }
    });
};

Here we follow the same pattern, but this time create a bespoke Photo object (Parse objects are schema-less, so we can create new classes and fields on the fly). Here we create a new object containing the photo file name and the name of the stream to which it belongs. If the request is successful – hooray! We’re done. If not, we let the user know.

Viewing a photo stream

Next, we want to show users the stream of uploaded photos. We’ll call this function from the $(document).ready listener.

var getPhotos = function() {
    forge.request.ajax({
        url: 'https://api.parse.com/1/classes/Photo',
        headers: {
            'X-Parse-Application-Id': config.parseAppId,
            'X-Parse-REST-API-Key': config.parseRestKey
        },
        type: 'GET',
        dataType: 'json',
        data: {
            'where': '{"stream": "' + config.streamName + '"}',
            'order': '-createdAt'
        },
        success: function (data) {
            $('#photo-container').children().remove();
            data.results.forEach(function (photo) {
                $('#photo-container').append(
                    $('&lt;img&gt;').attr('src', photo.file.url));
            })
        },
        error: function () {
            alert('Problem reading photos');
        }
    });
};

By now, this should be starting to look familiar. We request all of our stream’s Photo objects, most recent first. Then we remove child elements from our photo-container and append <img> elements with the photos’ url. In a real app, you should separate the display logic (we’ve kept things deliberately simple here).

Sending notifications

Finally, want to let users know when new photos are posted (to close that all important viral loop). Push notifications need deep native integration on each platform, so we’ve integrated the Parse notification framework into our Forge JavaScript API.

Once you’re set up with your Parse account, pairing it up with Forge is easy. Just add your Parse app ID and client key to your app’s local config file:

"partners": {
    "parse": {
        "applicationId": "ggJShmbAJh7YTgviK3fpH4QdIIp9az6WMW03swf5",
        "clientKey": "Bqjru0vC610FCIl5isczzxjPlv5CsFe8uK0yztez"
    }
}

(If you’re developing for iOS, you’ll need to upload a certificate to Parse before enabling pushing. This process is described in Parse’s own tutorial.)

After this, you’ll be able to send push notifications right away from Parse’s online interface (click ‘Push Notifications’ on your app’s admin panel). Type your message in a text box to broadcast it to all your app’s users, or specified groups. You can also send raw JSON data.

In our app, we’ll listen for these notifications and simply alert the user to the contents of the message:

forge.event.messagePushed.addListener(function (msg) {
    alert(msg.alert);
});

If you want to send notifications programmatically, check out Parse’s notifications API to see how to do this.

Building and running the app

To build and run the app yourself, first grab the code. Then sign up on our website and install the Trigger.io Forge framework if you haven’t already and start the Forge environment (instructions here).

Then,

  • Create a new directory for your app, cd into it, and run “forge create” to create the app in your account
  • Copy the tutorial code into the src directory, over-writing the boilerplate code that forge created
  • Run forge build to create each version of the app (this is only slow the first time – subsequent builds are lightning fast!)
  • Run forge run android or forge run ios to see the app (you’ll need to have the Android Emulator or iPhone Emulator installed first – see our documentation for more details)
  • If you have your Android phone connected, forge run android will deploy the app to your phone for testing (make sure you have USB debugging on)
  • Enjoy!

That’s it

If you’d like to play more, we’re sure you can think of lots of extensions. You might also like to think about how to port it to backbone.js.

Parse is a great solution for a simple, platform-agnostic back-end – and we’ve made it super-simple to take full advantage of it with Forge as well. Parse is free in beta, so sign up and give it a go – let us know how you get on, with any questions, comments or troubleshooting at support@trigger.io.