Parse, one of the most popular backend solutions for mobile apps, recently announced it’s shutting down its service. Naturally, this caused confusion amongst developers because it was surprising and disruptive — in a bad way. As a result, anything built on the platform will need a new backend, or it’ll cease to function.
The good news is there are options, and the team here has analyzed and compared several viable alternatives to Parse.
The end of Parse begs the question: Should developers take the same risk and depend on third-party backend providers?
Any option outside of building and hosting your own backend service carries some risk, and when you think about it, DIY carries risks too. You might find it’s not worth your time or later decide it’s too much of a hassle to keep up.
If you’ve got Parse on any of your apps, then it’s up to you to analyze the options and decide how to move forward in a Parse-less world.
This Parse server tutorial will explore one specific option: setting up and hosting your very own Parse Server, and migrating your data.
Note: This Parse server tutorial assumes you know the basics of developing iOS apps using Parse, have an existing Parse account, and have worked through the Parse Tutorial: Getting Started with Web Backends.
If you haven’t gone through it, that’s fine, you can still read and make quite a bit of progress. You just won’t have a certificate and some other minutiae that would allow you to follow step by step.
Getting Started
First, you need an existing iOS app that uses Parse so you can follow the steps in this Parse server tutorial. Feel free to use your own demo app, or download this Parse Starter project. It’s set up to work with Swift 2.2, iOS 9 and includes the latest Parse SDK (at the time of writing v1.12.0).
Build and run the project in Xcode to see the following:
Migrating to Parse Server
In this Parse server tutorial, you’ll install your own Parse Server that can be maintained through the Parse SDK. It’s open source, thus (almost) guaranteeing it’ll never cease to exist. It can be hosted on all major web service providers, such as Heroku, Amazon AWS or Azure.
There are, however, a few features from Parse.com that have not been implemented on Parse Server, such as jobs, analytics and config. Moreover, with Parse Server, you do all of the work of installing and hosting the service either locally or in the cloud.
Parse made all the necessary tools available to help developers transition away from its service by January 28, 2017: an open source Parse Server, Migration guide, Push Notification guide and a Parse Dashboard for local development.
Parse further recommends that you use mLab (formerly known as MongoLab) and Heroku to host the database and server, respectively.
The minimum requirements to install Parse Server are:
- Homebrew, latest version
- Node 4.3
- MongoDB version 2.6.X or newer
- Python 2.x
- For deployment, Heroku Toolbelt
The MongoDB requirements for Parse Server are:
- About 10 times the space you’re currently using with Parse, because the current service heavily compresses your content.
- The failIndexKeyTooLong parameter must be set to
false
to accommodate indexed fields larger than 1024 bytes and collections larger than 1 million documents. - An SSL connection — although it’s not required, it’s strongly recommended.
- For minimal latency, host your MongoDB servers in the US-East region.
Migrating the Database and Installing Parse Server
Creating a New Database
Go to the mLab website and create an account if you don’t have one already, and then watch for the confirmation email that will let you activate your new account. Once activated, click the Create New button. Choose Amazon AWS, US East, Single-node and Sandbox — these are the recommended free options:
Your database name can be anything, but for now, just use tutorial-app. Click on Create new MongoDB deployment and wait for your new database to be created.
Next, select tutorial-app and go to Users / Add database user. Enter a username and password then click Create. Save your Database URI somewhere that’s easy to reference, because you’ll need it several times throughout this Parse server tutorial. It should look similar to the one below, but your database ID will be unique:
mongodb://<dbuser>:<dbpassword>@ds017678.mlab.com:17678/tutorial-app |
Migrating the Parse Database to mLab
Go to the Parse dashboard and find your app. Click App Settings and then the red Migrate button under General. On the next screen, paste your Database URI, and then click Begin the Migration; ignore this warning for now:
We strongly suggest you enable SSL on your database and use the URL option 'ssl=true'. |
Note: If you don’t see the red Migrate button, then check if you’re using the new Parse Dashboard. The old Parse Dashboard does not have the red Migrate button.
Once migration finishes, a warning will appear. Click Finalize after the warning: This action is irreversible!
. Once the migration completes successfully, your general page should look like this:
Return to the mLab website to look for your migrated database. Under MongoDB Deployments, you should see the database you created: ds017678/tutorial-app.
Note: If you don’t see MongoDB Deployments, click the Home link in the top-left corner to make it show itself.
Click on the database to see all of its collections.
If you did the previous tutorial mentioned at the beginning, you’ll see the Player
class, which is where you saved data when you built your app. Click on the Player
class and notice that your old records are all there!
If you didn’t go through the previous Parse tutorial, then obviously you won’t see any data there.
You’ll write new records to this database soon, and they’ll appear as a new collection.
Install the Prerequisites
Open Terminal and run through the below steps to make sure the required support is in place.
Homebrew
If you don’t have Homebrew, enter this command:
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" |
If you already have Homebrew, make sure it’s up to date by entering this command:
$ brew update |
MongoDM
Next, install MongoDB — this can take a few minutes:
$ brew install mongodb --with-openssl |
Create a local MongoDB database by running the following:
$ mkdir -p /data/db |
If you don’t have permission to write files at the root of your hard drive, then place sudo
in front of mkdir
and try again.
Now you just need to verify that you have the required MongoDB version: v2.6.X or newer:
$ mongo MongoDB shell version: 3.2.3 connecting to: test Welcome to the MongoDB shell. |
Press Control + D to quit MongoDB.
Note: If your Mongod daemon isn’t already running, then use the following command after installing MongoDB to allow connections to your local MongoDB daemon.
$ mongod --config /usr/local/etc/mongod.conf |
Python
It’s usually installed on all major OS versions, but check if you have it first:
$ python -V Python 2.7.10 |
If you get a no, install Python by running this:
$ brew install python |
Node
Install the latest version of Node:
$ brew install node |
Confirm that you have the required version — v4.3 or newer:
$ node --version V4.3.1 |
Installing the Parse Server
To make life a little easier for developers, Parse created a local version of its server and pushed it to GitHub. Make a clone of it on your system:
$ git clone https://github.com/ParsePlatform/parse-server-example.git Parse |
Change the directory to the freshly cloned Parse directory:
$ cd Parse |
Install Parse Server in this directory:
$ npm install |
Start Parse Server:
$ npm run start |
Check if it was successful by copying and pasting http://localhost:1337 into your browser:
Well, at least it dreams of being something. Rather progressive for a server, don’t you think? :]
Next, in the root folder of the ParsePlatform project, open index.js and replace the default database string with your MongoDB database URI:
// Replace this var databaseUri = process.env.DATABASE_URI || process.env.MONGOLAB_URI; // With this var databaseUri = 'mongodb://<dbuser>:<dbpassword>@ds017678.mlab.com:17678/tutorial-app'; |
This configures Parse Server to talk to your mLab database.
You also need to specify your Application ID:
// Replace this appId: process.env.APP_ID || 'myAppId', // With this, the value that actually represents your Application ID appId: process.env.APP_ID || '<myAppId>', |
Now that you’ve wired it up, you need to test if the Parse Server is talking to the remote database. Remember to insert your Application ID from the Parse.com dashboard:
$ curl -X GET \ -H "X-Parse-Application-Id: <myAppId>" \ -H "Content-Type: application/json" \ -d '{}' \ http://localhost:1337/parse/classes/Player |
The server should return any old records:
{ "results": [ { "objectId": "cZU7xfUNrX", "createdAt": "2016-02-25T22:54:02.679Z", "updatedAt": "2016-02-25T22:54:02.679Z", "Name": "John", "Score": 810 }, { "objectId": "sT4diOLqN3", "createdAt": "2016-02-25T22:52:01.139Z", "updatedAt": "2016-02-25T22:52:01.139Z", "Name": "John", "Score": 1230 }, { "objectId": "vRW6MAg3bX", "createdAt": "2016-02-25T22:54:35.189Z", "updatedAt": "2016-02-25T22:54:35.189Z", "Name": "Sally", "Score": 2400 } ] } |
You now have a functioning Parse Server complete with real data.
Configure the iOS app
At last you get to dive back into the comfortable familiarity of Swift. The starter app doesn’t have the correct server URL to use Parse SDK with Parse Server.
Pull up the app in Xcode, open AppDelegate.swift and look for the line below in application(_:didFinishLaunchingWithOptions:)
:
Parse.setApplicationId("--AppID Goes Here--", clientKey: "--ClientKey Goes Here--") |
Replace it with the block below, substituting your Application ID and Client Key from the Parse dashboard:
let configuration = ParseClientConfiguration { $0.applicationId = "YOUR_APP_ID" $0.clientKey = "YOUR_CLIENT_KEY" $0.server = "http://localhost:1337/parse" } Parse.initializeWithConfiguration(configuration) |
The ParseClientConfiguration
object represents the configuration the Parse SDK should use to connect with the server. It lets you create configuration variables for various connection parameters, including your Application ID, Client Key, Server URL and so on.
This configuration object is passed to initializeWithConfiguration(_:)
, which then sets up the Parse SDK before connecting to the server.
If you still have the username and password from the previous Parse tutorial, go ahead and enter them now. If not, simply make some new credentials on the User page inside the Parse Dashboard. Just click the + sign under the objectId column, then enter a new username and password:
Build, run and log in. Tap the Upload button and choose an image from your phone or Simulator’s stock images.
Write a short comment and tap Send. To double-check that you’re writing to the “online” database, try these two sanity checks:
- Go to the WallPost collection on the mLab website and look for the image you just sent.
- Delete the app from your phone or Simulator. Then build and run, log in and check if you can retrieve the image and comment from the Mongo database.
If it’s there, you’re ready to move the Parse Server to Heroku’s web hosting service.
Deploy the Parse Server to Heroku
In order to manage Heroku apps from Terminal, you’ll need to download and install the Heroku Toolbelt from the Heroku website. It’s a command line interface tool for creating and managing Heroku apps.
Note: You could have attempted the installation by using Homebrew, however, you’d have gotten a standalone version of the Heroku Toolbelt that doesn’t include all the required components.
If you don’t already have a Heroku account, please visit the Heroku sign up page and do the needful.
Next, authenticate against Heroku by running the following command inside the local Parse Server directory:
$ heroku login |
The Heroku platform uses git for deploying applications. When you create an application on Heroku, it associates a new git remote, typically named heroku, with the local git repository for your application. Since the Parse project was cloned from GitHub, a local git repository exists. All you need to do is initialize Heroku, and push to its remote.
From the Parse project directory, create an application on Heroku and push your source code to the Heroku server:
$ heroku create heroku-cli: Installing core plugins... done Creating app... done, stack is cedar-14 https://intense-chamber-52549.herokuapp.com/ | https://git.heroku.com/intense-chamber-52549.git |
Notice a Heroku service was created for you (in my case it was at: https://intense-chamber-52549.herokuapp.com).
Next, commit your changes, and push the local Parse Server to the newly created Heroku service with the following command:
$ git add . $ git commit -m "Commit with my custom config" $ git push heroku master |
Paste the URL you made with the create command into a web browser and you should see the same message as before when you tested the server locally:
I dream of being a web site. |
Now you need to test if that shiny new Heroku service still responds to GET
requests. Remember to replace <myAppId>
with your Application Id from the Parse dashboard, as well as your Heroku server URL:
$ curl -X GET \ -H "X-Parse-Application-Id: <myAppId>" \ -H "Content-Type: application/json" \ -d '{}' \ https://<your URL>.herokuapp.com/parse/classes/WallPost |
This is a similar curl as before when you were executing against a local server. This command goes against the remote server.
You should see the JSON version of the wall post record you created inside the iOS app:
{ "results": [ { "objectId": "a8536MK9nC", "image": { "__type": "File", "name": "57eb6f36cd8bcce8141dc5ccca3072c0_image.bin", "url": "http:\/\/afternoon-harbor-27828.herokuapp.com\/parse\/files\/" \ "jJ5Ds5h0eXWYhv7DGWYIrfLQTn2rjB0okakvo3LH\/57eb6f36cd8bcce8141dc5cc" \ "ca3072c0_image.bin" }, "user": { "__type": "Pointer", "className": "_User", "objectId": "SLPlVVfsvx" }, "comment": "great pic!", "updatedAt": "2016-03-14T17:36:20.849Z", "createdAt": "2016-03-14T17:36:20.849Z" } ] } |
It works! You just migrated your Parse app and database to the cloud, and that’s an accomplishment!
Implement Basic Push Notifications
Note: If you’re setting up push notifications on iOS for the first time and want to go through all the steps outlined below, you’ll need to head to the Push Notifications Tutorial and work through it until you’ve generated and downloaded the certificate.
When initializing Parse Server, you need to set up an additional push configuration. Inside the Parse Server directory, open the index.js file and add the following code block after the serverURL
line:
push: { ios: [ { pfx: 'cert.p12', bundleId: 'com.example.ParseTutorial', production: false } ] }, |
The certificate cert.p12 is the one you exported from the Push Notifications Tutorial (it may be named WenderCastPush.p12). The bundleId
should be the one you previously created in the Push Notifications Tutorial. You also need to change the Bundle Identifier for the app as well to match in Xcode.
production
should be false
if you’re using a development certificate, and true
if you’re using a production certificate.
Additionally, add the Master Key to index.js:
// Replace this masterKey: process.env.MASTER_KEY || '', // With the value of your app's Master Key completed: masterKey: process.env.MASTER_KEY || '<your app's Master Key>', |
Your next step is to put the certificate inside the local Parse Server directory, so it can be sent to the Heroku service, by running these commands in Terminal:
$ git add . $ git commit -m "added certificate" $ git push heroku master |
Switch back to Xcode, open AppDelegate.swift and find the application(_:didFinishLaunchingWithOptions:)
method. Replace this:
$0.server = "http://localhost:1337/parse" |
With this (using your Heroku URL):
$0.server = "https://afternoon-harbor-27828.herokuapp.com/parse" |
Add a private extension Selector
, just below the class definition:
// 1 private extension Selector { // 2 static let didReceiveRemoteNotification = #selector( UIApplicationDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:)) } |
Here’s a step-by-step explanation of the above code:
- Set up a private extension on the
Selector
type so its code is only available inside the AppDelegate.swift file. - Create a
didReceiveRemoteNotification
selector argument to use inside theSelector
definition that you’ll implement next.
Now you’ll register your app for remote push notifications by adding the following lines in application(_: didFinishLaunchingWithOptions:)
:
// 1 if application.applicationState != .Background { // 2 let preBackgroundPush = !application.respondsToSelector(Selector("backgroundRefreshStatus")) let oldPushHandlerOnly = !self.respondsToSelector(.didReceiveRemoteNotification) var pushPayload = false if let options = launchOptions { pushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil } if (preBackgroundPush || oldPushHandlerOnly || pushPayload) { PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions) } } // 3 let types: UIUserNotificationType = [.Alert, .Badge, .Sound] let settings = UIUserNotificationSettings(forTypes: types, categories: nil) application.registerUserNotificationSettings(settings) application.registerForRemoteNotifications() |
Here’s a step-by-step explanation of the above code:
- Verify the app isn’t opening in background mode
- Track the app open event here if you launch with a push, unless “content_available” triggered a background push. In that case, you skip tracking here to avoid double counting the app open.
- Set the type of notifications to register for your app, in this case it’s
.Alert
,.Badge
and.Sound
. Save these as default notification settings.
Next, you need to store the device token and handle the UI for notifications. Add the following below application(_:didFinishLaunchingWithOptions:)
:
// 1 func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) { let installation = PFInstallation.currentInstallation() installation.setDeviceTokenFromData(deviceToken) installation.saveInBackground() } // 2 func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) { if error.code == 3010 { print("Push notifications are not supported in the iOS Simulator.") } else { print("application:didFailToRegisterForRemoteNotificationsWithError: %@", error) } } // 3 func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) { PFPush.handlePush(userInfo) if case(.Inactive) = application.applicationState { PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo) } } |
Here’s a step-by-step explanation of what you just added:
- This method is called once the app successfully registers with the APNs (Apple Push Notification service). The device will only act on notifications that have the specified
deviceToken
. - When the APNs can’t complete device registration due to an error, this method gets called with error information, so your app can determine why registration failed.
- When your app receives a remote notification from the APNs, this method is called. If the app is running, it calls this method to process incoming remote notifications.
Build and run the app on a device because push notifications aren’t supported in iOS Simulator. To test, run this command in Terminal — remember to replace the Application ID, Master Key and server URL:
curl -X POST \ -H "X-Parse-Application-Id: <YOUR_APP_ID>" \ -H "X-Parse-Master-Key: <YOUR_MASTER_KEY>" \ -H "Content-Type: application/json" \ -d '{ "where": { "deviceType": "ios" }, "data": { "alert": "Hello, Parse!" } }' https://<YOUR_SERVER_URL>.herokuapp.com/parse/push |
If all went well, you should get a notification on your screen as shown below:
Bonus: Parse Dashboard
Only a few days after releasing push notifications for the Parse Server, the team at Parse also opened up the very useful dashboard. It can be used locally or in the cloud.
To install it locally, you need to clone the GitHub repository on your machine. Enter this into Terminal:
$ git clone https://github.com/ParsePlatform/parse-dashboard.git $ cd parse-dashboard $ npm install |
The dashboard isn’t fully compatible with the Parse Server instance you’ve set up. It’s only compatible with versions 2.1.4 or newer.
However, that’s no reason why you can’t take a peek at this powerful and useful tool which you can now use too, both in development and production.
Note: By the way, there’s no reason you can’t upgrade your instance later to experience the dashboard’s full-fledged capabilities.
In Terminal, in the Parse-Dashboard subfolder, edit parse-dashboard-config.json. Add your IDs, keys, URLs and names as shown below:
{ "apps": [ { "serverURL": "https://api.parse.com/1", "appId": "myAppId", "masterKey": "myMasterKey", "javascriptKey": "myJavascriptKey", "restKey": "myRestKey", "appName": "My Parse.Com App" }, { "serverURL": "http://localhost:1337/parse", "appId": "myAppId", "masterKey": "myMasterKey", "appName": "My Parse Server App" } ] } |
Run this command in the Parse Dashboard directory from Terminal:
$ npm run dashboard |
Next, copy and paste http://localhost:4040 into your browser, and you’ll see your app in the dashboard! For your apps on Parse.com, you currently have full run of the place, including the data browser, Parse config and API console. Your cloud code and logs as there too.
For apps on the Parse Server, only the data browser and API console are available.
Where to go From Here?
You can download the finished project here. As usual, you’ll need to replace the AppID and ClientKey with your own keys to make it all work right.
To expand on what you’ve done in this Parse server tutorial, you could:
- Explore Parse dashboard’s full potential by setting up a full version of the Parse Server.
- Explore the extended capabilities of using a push adapter for other push providers that use the default APN.
- Look into and compare other Parse alternatives such as Firebase or CloudKit, but beware that these alternatives lack some features covered in this Parse server tutorial.
Now you know that the end of Parse as we know it is not the end of the world, nor will you have to reinvent the wheel to transition gracefully away from the status quo.
There’s certainly a lot to talk about though, so bring your thoughts, questions and findings to the forums and let’s make some magic happen. I look forward to connecting with you!
Parse.com is (soon) dead, long live the Parse Server!
The post Migrating to Parse Server appeared first on Ray Wenderlich.