Full disclaimer: we have recently received a full access to the tool from ObjectiveC2Swift Team! Thanks!
Challenge Accepted!

We all have some big and small legacy projects written in Objective-C, who doesn’t right? That’s why we have felt obliged to try this tool out and share with community how it worked for us.
All that being said I will stay as objective as possible when reviewing the tool in this subjective post. All the good things mentioned in this article are an appraisal to the team for their great job. All bad things are tips to help developers and for the Swiftify Team to make their product even better!
Hang on! Let’s rock!
It’s an online tool. No need to install anything. Code is transmitted securely and is not stored anywhere. Free tier enables you to convert pieces of code up to 2KB. Then there are paid versions that allow you convert whole files and even entire projects. There is also an Xcode plugin. Everything is neat and self- explanatory. No need for any long tutorials.

To make a full use of the license we have received, we have converted an entire project. This is a simple demo app to display the Game of Thrones (referred as GoT) data from Wikia’s API. It has some networking, a model and Masonry (a layout DSL, link in references) as Pod. As an additional difficulty it was a piece of code that I have never seen before. The app is small but uses some very specific patterns like Configurator, Loaders and blocks. Seems just enough to test.
NOTE: Objective-C2Swift converter does not promise a perfect conversion. There is a list of supported Swift and Objective-C features on their page.
I have followed this process to test the tool:

As a result we have a GitHub repository with 3 folders. One with the original Objective-C project, another one with converted project and last one with fixes. You can find a link in references.
My first impression after unzipping converted project was:
Wow, it looks like a perfect Swift Code.
And it quite is one.
Let’s build it!
Ok… 12 errors, not bad. Let’s see what impressed me most and what could be done better.
The first file that looked into in the converted project was AppDelegate.swift. It was converted 100% correctly. We can probably expect that for simple and small files. You may notice now, that good architecture and KISS pays off.
Good start.
// AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
...
The original GoT Objective-C code was using nullability to support Swift interoperability. It is good to know that our tool converts nullable attributed properties to Swift optionals.
// Article.h @property(nonatomic, strong, nullable) NSData *thumbnailData; - (nullable UIImage *)imageFromThumbnailData;
// Article.swift var thumbnailData: Data? func imageFromThumbnailData() -> UIImage?
I would give another plus for translating readonly property attribute into private (set) var.
In the example below, we get both optional and private setter right.
// AsyncLoadConfiguration.h @property(nonatomic, readonly, nullable) NSString *webserviceQuery;
// AsyncLoadConfiguration.swift private(set) var webserviceQuery: String?
I was wondering for a while if having let would be a better option here, but quickly reminded myself that there is no such thing as Objective-C const properties . Converter works well enough with Objective-C consts:
// Objective-C const NSString *const MyFirstConstant = @"FirstConstant"; // Swift const let MyFirstConstant: String = "FirstConstant"
As ugly using global vars are, they were converted properly!
// Article.m static NSString *kArticleIdentifier = @"privateIdentifier"; static NSString *kArticleTitle = @"privateTitle";
// Article.swift var kArticleIdentifier: String = "privateIdentifier" var kArticleTitle: String = "privateTitle"
It is good to see nice separation of parameters in init functions created from Objective-C initWithXYZ format.
// Article.m
- (nonnull instancetype)initWithArticle:(nonnull Article *)article
favourite:(BOOL)favourite {
// Article.swift init(article: Article, favourite: Bool)
Might seem pretty straightforward but it is nice to see attention to such details.
// DataSource.h
typedef void (^CellConfigureBlock)(UITableViewCell *_Nonnull cell,
NSIndexPath *_Nonnull indexPath,
id _Nonnull item);
// DataSource.swift typealias CellConfigureBlock = (_ cell: UITableViewCell, _ indexPath: IndexPath, _ item: Any) -> Void
Although GCD is a framework not a part of Swift language it was converted properly.
// DataSource.m
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
// DataSource.swift
DispatchQueue.main.async(execute: {() -> Void in
self.tableView.reloadData()
})
I have uploaded the zipped GoT project including fetched Pods directory. Luckily it was not touched at all and left in its Objective-C form.
The GoT project uses Masonry for autolayout purposes. Even in Objective-C Masonry calls felt weird. Having Masonry in Swift project (while SnapKit is available) is even weirder. To make fixes I had to take a look at sample repository Swift-Masonry to make it work.
Kudos for converter for taking it that far!
// DetailsViewController.m
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.imageView.superview);
make.top.equalTo(self.imageView.superview).offset(10);
make.width.height.equalTo(@100);
}];
// DetailsViewController.swift
self.imageView?.mas_makeConstraints({(_ make: MASConstraintMaker) -> Void in
make.centerX.equalTo(self.imageView?.superview)
make.top.equalTo(self.imageView?.superview?)?.offset(10)
make.width.height.equalTo(100)
})
// DetailsViewController.swift - after fixes
_ = self.imageView?.mas_makeConstraints({(make: MASConstraintMaker?) -> Void in
_ = make?.centerX.equalTo()(self.imageView?.superview)
_ = make?.top.equalTo()(self.imageView?.superview)?.offset()(10)
_ = make?.width.height().equalTo()(100)
})
This one is to echo the AppDelegate one. Custom FavouriteTableViewCell was almost perfectly converted (apart from crazy Masonry stuff and dispatch_once). This file is larger (100 lines) than AppDelegate and still converted nicely.
Do-catch error handling is supported. Some APIs became throwing APIs in Swift and converter wraps it in do-catch, try statement. On the little con side it rendered one these for me in an incomplete state.
It’s probably too much to ask, so just note what may happen:
// Data+JSON.m
- (id)JSONObject {
return [NSJSONSerialization JSONObjectWithData:self
options:NSJSONReadingAllowFragments
error:nil];
}
In swift JSONSerialization is a throwing API. It was wrapped in this way.
func jsonObject() -> Any {
do {
return try JSONSerialization.jsonObject(withData: self, options: NSJSONReadingAllowFragments)!
}
catch {
}
}
All in all, this went into positive side.
Now let’s see what may go wrong. It is not written to condemn creators of this awesome tool. Treat it as tips.
Update 24/03/2017: Look into comments. Swiftify team was working hard to address issues mentioned below.
This goes as number one as I was not expecting that when converter trips over at one of early lines it may swallow the entire method. 41 lines of code were turned into merely 3 and the rest was thrown outside of class scope in broken pieces:
// MainViewController.m
- (void)loadTableView {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero
style:UITableViewStylePlain];
self.tableView.dataSource = self.dataSource;
self.tableView.delegate = self;
[self.tableView registerClass:[FavouriteTableViewCell class]
forCellReuseIdentifier:self.dataSource.cellReuseIdentifier];
[self.view addSubview:self.tableView];
...
// 40 lines in total
// MainViewController.swift
func loadTableView() {
var onceToken: dispatch_once_t
dispatch_once
onceToken
}
Somehow the word ‘abstract’ that was used throughout the GoT project as a variable name (property in model) or an initializer parameter caused many troubles to the converter. Funny enough neither Objective-C nor Swift have ‘abstract’ keyword.
Could be some internal implementation detail.
// Article.h
@property(nonatomic, readonly, nonnull) NSString *abstract;
- (nonnull instancetype)initWithIdentifier:(nonnull NSString *)identifier
title:(nonnull NSString *)title
abstract:(nonnull NSString *)abstract
urlString:(nonnull NSString *)urlString
thumbnailURLString:(nonnull NSString *)thumbnailURLString;
// Article.swift
private(set) var: String = "" // this is in place of property
...
override init(identifier: String, title: String, urlString: String, urlString: String, thumbnailURLString: String) // look at doubled urlString param
...
override func abstract() -> String { // this is added somewhere in code
return self.privateAbstract
}
Another problem occurred with long init with block parameter. This piece of code gave a really hard time to the converter. Take a look at it:
// AsyncLoadConfiguration.m
- (nonnull instancetype)
initWithResponseParsingBlock:
(nonnull id _Nullable (^)(NSData *_Nonnull result))block
webserviceEndpoint:(nonnull NSString *)endpoint
webserviceQuery:(nullable NSString *)query {
self = [super init];
if (self) {
self.parsingBlock = block;
self.endpoint = endpoint;
self.query = query;
}
return self;
}
// AsyncLoadConfiguration.swift
override init(responseParsingBlock Nullable: Any) {
block
(endpoint as? String)
(query as? String)
do {
super.init()
self.parsingBlock = block
self.endpoint = endpoint
self.query = query
}
var: ((_ Nonnul: Data) -> Any)?
responseParsingBlock
do {
return self.parsingBlock
}
...
When trying to reproduce this in the Swiftify web tool I have found that there is a tiny console that shows all lexer, parser and converter messages. In the case of our unfortunate and weird initializer, it showed:
Lexer and Parser messages: (unknown): (3:12) Missing RP at '_Nullable' (unknown): (3:50) Mismatched input ')' (unknown): (13:1) Missing '}' at 'EOF' Converter messages: (unknown): (3:51) Unable to convert:(unknown): (13:0) Unable to convert:
This point is related to previous one. Trying to call such a complex initializer resulted in similarly broken code.
In many places throughout the code there were unnecessary override keywords.
// DataSource.m - (nonnull instancetype) initWithCellConfigureBlock:(nullable CellConfigureBlock)configureBlock cellReuseIdentifier:(nonnull NSString *)reuseIdentifier - (void)addItems:(nonnull NSArray *)items - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
// DataSource.swift override init(cellConfigureBlock configureBlock: CellConfigureBlock?, cellReuseIdentifier reuseIdentifier: String) override func addItems(_ items: [Any]) override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
While this is a safe option it is usually completely unnecessary and redundant piece. Still, better working code than optimized and broken.
// ArticleRepository.m
- (void)saveFavouriteArticle:(nonnull Article *)article {
[self.articles addObject:article];
[self saveFavouriteArticlesToDefaults];
}
// ArticleRepository.swift
func saveFavouriteArticle(_ article: Article) {
self.articles.append(article)
self.saveFavouriteArticlesToDefaults()
}
Some Objective-C patterns are sometimes not converted properly to Swift. That’s not a big deal though. Take a look at nil comparison:
// ArticlesRepository.m
if (!set) {
set = [[NSMutableSet alloc] init];
}
// ArticlesRepository.swift
if set.isEmpty {
set = Set()
}
// Objective-C
if (item) {
self.cellConfigureBlock(cell, indexPath, item);
}
// Swift
if item != nil {
self.cellConfigureBlock(cell, indexPath, item)
}
dispatch_once callsI do not know why, but I was expecting to have it converted when I saw GCD converted properly. The dispatch_once calls have no equivalent in Swift and should be rewritten into some form of lazy vars:
DISPATCH_SWIFT3_UNAVAILABLE("Use lazily initialized globals instead")
The converter took no attempt to translate this call:
+ (UIImage *)avatarImage {
static UIImage *avatarImage;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
avatarImage = [UIImage imageNamed:@"avatar"];
});
return avatarImage;
}
class func avatarImage() -> UIImage {
var avatarImage: UIImage?
var onceToken: dispatch_once_t
dispatch_once(onceToken, {() -> Void in
avatarImage = UIImage(named: "avatar")
})
return avatarImage!
}
Swift 3 imposes new style of writing. It affected many APIs and made them shorter. I have noticed that converter is not picking that up.
// DetailsViewController.m self.abstractTextView.editable = NO;
// DetailsViewController.swift // Should be 'isEditable' self.abstractTextView.editable = false
// Article.m [aCoder encodeObject:self.privateIdentifier forKey:kArticleIdentifier];
// Article.swift // Should be just 'encode' aCoder.encodeObject(self.privateIdentifier, forKey: kArticleIdentifier)
While looking into code we could probably find some more tiny wins and losses. But this trip was long already!
At this point of my process I was mostly working on strong typing of Set‘s and Array‘s so that everything was more type-safe and Swifty. Other tasks included handling optionals with guard let‘s and similar. It really didn’t take too much time until app was building and running correctly. Neat!
As you may notice project had properties and parameters marked with nullable and nonnull attributes that are there to help conversion to Swift optionals.
There is one more feature introduced in Xcode7 that I wanted to give a try and that was not in our sample project: Objective-C Lightweight Generics.
Let’s jump directly into Objective-C code and code converted using online tool:
@property NSArray*dates; @property NSCache > *cachedData; @property NSDictionary > *supportedLocales;
var dates = [Date]() var cachedData: NSCache! var supportedLocales = [String: [NSLocale]]()
Looks good to me. Good job Swiftify!
All in all I am very impressed with the results I was able to achieve using Swiftify to convert the entire project. There are few flaws but most of them are minor. They are picked by compiler and can be self-corrected quickly.
Clearly the fact that the project is building does not mean you are at home. There is still a high probability of runtime errors as the languages are very different. It is necessary to stay focused and analyze the results but all the tedious work and hours of typing are done for you! Now I just wonder whether unit tests could help in this converted project.
I have to admit that this project has a lot of unusual solutions. But only in this way we could get to the limits of the tool and give you some valuable tips and feedback.
It’s been more than a year since this review was created. If you are interested in converting Objective-C codebases into Swift you can follow up with this article from Swiftify.
Facing additional work, limited features and additional costs, some may have left Parse.com platform. However, many saw an opportunity in a newborn Parse Server. Blogs started to write extensive tutorials about migration, missing features and ideas for the future of the platform.
We did not give up on Parse Server either. In issue #4, we have covered a migration from Parse.com to Heroku and mLab Mongo as a service provider.

Github repository is the strongest evidence of how big and active community of Parse Server have become. At the time of writing it has more than 9k of stars, more than 2k forks and more than 1k of commits from 70+ contributors. Not only missing features are being added but also features not existing in Parse.com like Live Queries.

I really like a little table Fosco Marotto placed in his post that introduced Parse Server. Yes we have to sacrifice convenience, but there is much more to gain.
All this makes us believe that Parse Server is here to stay and prosper. In this post we will write about current status of Parse Server, choices you have while migrating your app or setting up a clean project and what to be careful of.
Whether migrating from an existing Parse.com deployment or setting up a clean project on Parse Server you need to take care about two major components: a solid MongoDB database and a node.js hosting. Below are results of our research and experiences.
Let us know in comments what you have been looking at and what powers your Parse Server setup.

mLab, formerly MongoLab, is the first you have probably heard of. It has a nice free tier of 500MB – can have many of these. They are great for development and testing. On production you would rather want to enable SSL, and have a Replica Set Cluster.
SSL costs extra $80, but can be set account wise. Cluster can easily host multiple databases depending on your needs. You have choices of AWS, Amazon and Google platform in multiple regions. Nice interface can setup everything just by clicking. Good and responsive support team too. This is actually our choice.

We have considered Scalegrid.io for quite some time and actually went for a trial. They allow you to host on AWS, Azure, Digital Ocean, Bare metal, Joyent and can setup on your AWS machines too. There is more, like private clouds and Amazon VPC. Good and responsive support, really open to customizations, when asked. Competitive pricing and SSL comes at no extra charge. There is a 20% discount offer for a long term, reserved instances.

Compose.io, formerly MongoHQ which is an IBM company. They have more broad spectrum of services and hosted MongoDB is just one of them. We saw there WiredTiger technology as an option first. WiredTiger is a technology that decreases usage of storage even 10x and boosts performance even 50-fold. It was actually used by Parse.com since some time. That is why they asked you to reserve 10x more space when migrating your DB expecting you to pick standard MMAP technology. Compose uses replica set by default and their pricing model is per GB. RAM memory and disk IOPs scale proportionally as you add more GBs. Looks really solid, however their pricing model and a lack of dedicated machines caused that we did not went for it.

ObjectRocket is the last of hosted MongoDB as a service providers that we have looked at. ObjectRocket is a Rackspace company. As it is at Compose.io, MongoDB is not their only offering. They offer Sharded Clusters and WiredTiger engine. In comparison to other vendors they were more expensive without showing clear advantages.

MongoDB Cloud Manager is a different kind of a beast. First, it is provided by MongoDB itself. Second, it is used to deploy and manage MongoDB cluster on your own AWS machines or servers. You setup agents or give Cloud Manager access (provisioning) to your AWS account. It seems a really great way to have more control over your cluster and is a very cost effective path to follow if you have multiple deployments. As it usually is, these benefits come at cost. You will spend more time setting up and maintaining your deployment. Still, we consider it as a future option for our growing number of Parse Server backed apps.
It is possible that you are MongoDB Jedi, or you can use a help of one, then you may decide to setup your cluster all by yourself. This will require some time for setup and maintenance plus knowledge. Two major benefits are cost effectiveness and full control. You can find some starting point links in references section.
For development and playing around you may set a single Mongo process where your Parse Server is hosted. However, this is a bad decision – your server and database will share resources, which is not scalable. If your hosting goes down, then your whole setup goes down. Thus, if your data can be hosted in cloud and you are not limited in other ways, reconsider one of nice trials and free tiers (ex. mLab’s 500MB).
To sum up this section, I was really tempted to create a table with a full-blown comparison, but that would just quickly outdate
.
Finding a good hosting for node.js deployment of Parse Server is not a big deal. There are plenty of platforms that support it. Topic is also less frightening. Most of developers already have experiences with at least one of PaaS providers. You can setup Parse Server on bare machines like Amazon EC2 or use PaaS like Heroku or AWS Elastic Beanstalk where node.js environment is just ready for your package.
NOTE: One thing to check for when choosing a smaller or a less known provider – make sure that all Parse Server dependencies are in required versions. Keep an eye on node.js, python and MongoDB versions support.
Back then, shortly after Parse Server was born, I was even preparing a tutorial about setup on one of smaller PaaS providers. After couple of hours of work I got stuck because of lack of support for a required MongoDB version
. Hopefully, those days are far behind us.
Parse Server github page contains a list of providers that we can assume are recommended and easiest to deploy. Heroku and AWS even have these cute "Deploy to Heroku" and "Deploy to AWS" buttons that get you half way through with one click.
Clearly you are not limited to choices above. It should run well on bare machines (ex. Linux), virtual machines or whatever you have available for your personal projects or at your company.
Going through comparison of even only major platforms would be duplicating of work. Make sure to see the list on Parse Server Github link above. If you have some prior experiences with one of platforms, go for it. If you are fresh go for Heroku or AWS – they have a free tier and are easy to setup.
We have had some prior experiences with Heroku and AWS. Our choice was AWS Elastic Beanstalk. So far we enjoy it.
That is quite a topic, probably for another post. Now, as you are in charge of your mBaaS, it is worth at least a short note. Here are a couple of things to look at:
Would you like to share some security tips? Let us know in comments or on Twitter.
When Parse Server was announced, we have all seen that it lacked many features that we have been used to in Parse.com. Not all of them are present at the moment, but major ones have been added really fast. With frequent, approximately bi-weekly releases, we can expect more to come. Actually, there are features like LiveQurery, numerous oAuth providers or File Adapters not present in commercial Parse.com.
What is included in Parse Server (at the time of writing):
What is still missing:

One more thing. It is always worth digging in changelog on Parse Server’s git repository
. Wiki on compatibility article may also help.
Parse.com team really cares about your migration to Parse Server going as smooth as possible. You can see official blog posts presenting major features being added. On April 18th, a set of video tutorials covering topics like environment setup, database migration, launching Parse Server app or things to look at when migrating your Cloud Code. This is on top of contents of Github repository and community blog posts.

What I really liked about video series was the Cloud Code Tips clip. It starts with 2 tips about using modern JS for a cleaner code:


Third tip, probably the most important for people migrating, is about current user scope. This scope may be used for operations related to particular user or assuring security. In Parse.com you would use:
Parse.User.current()
That is no longer valid in Parse Server. Now you have to take care about passing user session yourself. You can do it either by using sessionToken parameter in operation or setting 'X-Parse-Session-Token'. Once you have taken care of passing session, then it is available in your Cloud Code as:
request.user
Specifically, session token is available in:
request.user.getSessionToken()
You can see more about handling session on wiki page.
Parse Server did not have an easy start. Developers immediately noticed lack of GUI for managing data, logs and other mBaaS components. Suddenly we have all appreciated the convenience of Parse.com
.
This could not last long however. Brave and young team from Adminca.com created a first GUI and made it available to community on March 3rd.

With Adminca.com you can:
Great Adminca’s Team, facing the better-supported and incoming Parse Dashboard, froze further enhancements to their GUI. It is still a decent option for a free and hosted simple Parse Server data management.
Parse Dashboard is a separate project on Github. You can run it on your localhost, on the same server as your Parse Server or on an entirely different machine. It was announced on March 4th and contained very basic set of features. Soon, major features were added and it currently covers majority of our needs.
With Parse Dashboard you can:

Parse Dashboard is doing well. With 1.5k stars and almost 40 contributors we can expect it to be well maintained and growing.
Everything is well documented on Github page, so I would just want to attract your attention to security of your dashboard. You can setup Basic Auth credentials for access. For this to be safe is has to be accompanied by https protocol. Luckily, if you try to access it without https while not running on localhost you will not be let in. Good job team
for protecting us from ourselves!
Usually your load balancer on PaaS will provide SSL and that is enough to ensure secure connection. However, if ensuring secure connection is up to you, here is a useful snippet (Parse Dashboard documentation includes only http Express setup):
var express = require('express');
var ParseDashboard = require('parse-dashboard');
var fs = require('fs');
var https = require('https');
var key = fs.readFileSync('key.pem','utf8');
var cert = fs.readFileSync('cert.pem','utf8');
var credentials = {key:key, cert:cert};
var dashboard = new ParseDashboard(
{
"apps":[
{
"serverURL":"YOUR_SERVER_URL",
"appId":"YOUR_APP_ID",
"masterKey":"YOUR_MASTER_KEY",
"appName":"YOUR_APP_NAME"
}
],
"users":[
{
"user":"YOUR_DASHBOARD_USER_NAME",
"pass":"YOUR_DASHBOARD_PASSWORD",
"apps":[{"appId":"YOUR_APP_ID"}]
}
]
});
var app = express();
// make the Parse Dashboard available at /dashboard
app.use('/dashboard', dashboard);
var httpServer = require('https').createServer(credentials, app);
httpServer.listen(443);
UPDATE:
Parse Dashboard since version 1.0.11 allows you to specify --sslCert and --sslKey params to supply paths to certificate and key. They can also be set as node.js environment variables PARSE_DASHBOARD_SSL_CERT and PARSE_DASHBOARD_SSL_KEY respectively. You can lookup changes in this commit. It has a similar logic to our snippet above.
Last thing to cover in this post is an extensibility of Parse Server. There is a less known space for community projects like modules and adapters that are not part of core Parse Server. It is called parse-server-modules and already contains some cool stuff:

To sum up, Parse Server is here to stay. For our team it already contains most important features. Community support is vast and strong. Yes, we have had to sacrifice quite a bit of convenience but a little of JS has never killed anybody. Actually, we have got more awareness of what is powering our mobile apps. Initially, as probably many of you, we were afraid where to go with our Parse.com deployments. Right now we just go migrating to self hosted Parse Server with our existing projects one by one. At least until something better pops up on horizon
.
Hopefully, you have enjoyed our summary. We would love to see your thoughts, experiences and tips!
Let us know in comments or on Twitter.
Finally, it would not be us if we did not provide a proper pack of references. Here they come:
During creating this post I mainly based on Parse Server Guide, where you can find more general information about migration.
First let’s setup MongoDB on MongoLab. This is the easiest way to migrate our data from Parse, alternative way is to set up mongoDB locally, but in this tutorial I have decided to show everything based on MongoLab.
Go to MongoLab, if you don’t have account yet, create one and then choose 500 MB(for free):

Important: Don’t forget to add a new user to your database:)
set configuration for database according to requirements which you can find on Parse Guide website:
Install mongo locally:
brew install mongodb
I tried to set failIndexKeyTooLong parameter via:
db.runCommand( { setParameter: 1, failIndexKeyTooLong: false } )
an then in console appeared:
{
"ok" : 0,
"errmsg" : "setParameter may only be run against the admin database.",
"code" : 13
}
it means that you only can modify parameters when you have admin privileges, but I neither couldn’t login with admin privileges nor create user with root role (maybe I miss something). For sure it is possible if your database is set up locally. It will be great to hear your experience with databases!:)
Anyway, a very nice tool to manage tou mongoDB database you can download from here
Information how to make SSL connection you can find here.
After setting up database we are ready to:

Login to your Parse account and select your app, then go to:
App Settings → General → Migrate to external database:

then in text field enter your databaseURI which you achieved after setting up database on MongoLab:
mongodb://dbuser:[email protected]:33484/new_bw_database
then after pressing Begin the migration button, process should start:

In this stage your app is still hitting api.parse.com, but is using your MongoDB instance. Now you are responsible for your own imports, exports, backups, indexes, monitoring, and other database administration.
In this step we will go one step further, and we will setup Parse Server locally:

Make sure that you have Node and Express, if not, then in console type:
brew install node npm install express
if you upgraded/updated npm version, it could be helpful to rebuild everything by typing:
npm rebuild
If you want to remove node and install everything from zero this Gist can help you.
ok, now we can start setting up local server:
npm install parse-server
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();
var api = new ParseServer({
databaseURI: 'mongodb://your.mongo.uri',
cloud: './cloud/main.js',
appId: 'myAppId',
fileKey: 'myFileKey',
masterKey: 'mySecretMasterKey',
clientKey: 'myClientKey',
restAPIKey: 'myRESTAPIKey',
javascriptKey: 'myJavascriptKey',
dotNetKey: 'myDotNetKey',
});
// Serve the Parse API at /parse URL prefix
app.use('/parse', api);
var port = 1337;
app.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
of course don’t forget to copy your appID, masterKey from your Parse account (Security & Keys Tab) and databaseURI from your MongoLab website.
$ node app.js
and now you should have local server on your host: http://localhost:1337/
Now if you would open this site in browser you could get response from server:
{"error":"unauthorized"}
The reason is simple: we can’t forget to send our request with necessary parameters as in example below:

or just type in console:
curl -X GET \ -H "X-Parse-Application-Id: YOUR_APP_ID" \ -H "X-Parse-Master-Key: YOUR_APP_MASTER_KEY" \ http://localhost:1337/parse/classes/Cars?utm_source=swifting.io&utm_medium=web&utm_campaign=blog%20post
everything should work (i hope so:) ). If yes then in response we should see our requested entities.
{
"results": [
{
"objectId": "5wez6D7TIc",
"createdAt": "2016-02-06T16:57:14.534Z",
"updatedAt": "2016-02-06T16:57:53.009Z",
"carName": "Fiat 126 p"
},
{
"objectId": "dAZtEElbdg",
"createdAt": "2016-02-06T16:57:39.365Z",
"updatedAt": "2016-02-06T16:57:43.334Z",
"carName": "Citroen"
}
...
]
}
our next big and final step is to…

First of all create account on Heroku if you don’t have it yet.
Install the Heroku Toolbelt it is CLI tool for creating and managing Heroku apps. Once installed, you can use the heroku command from your command shell:
heroku login Enter your Heroku credentials. Email: [email protected] Password: ...
Basing on the project from Github I have created a similar, simplified one. Project uses the parse-server module on Express. You can download it from here.
After downloading open index.js and set necessary values for following keys:
Locate your project directory in console and then type:
$ cd my-project/ heroku create appName //in my case: heroku create bwparseserver
Above command prepares Heroku to receive your source code, and additionally a git remote (called heroku) is also created and associated with your local git repository.
Then to connect with self generating git we have to just type:
$ git init $ heroku git:remote -a appName
Finally commit your code to the repository and deploy it to Heroku:
$ git add . $ git commit -am "Super Commit" $ git push heroku master
and we should get endpoint to our service:

but before we test connection, we should also:
$ heroku addons:create mongolab:sandbox
here you can get some information like: "Please verify your account to install this add-on plan (please enter a credit card) For more information, see https://devcenter.heroku.com/categories/billing Verify now at https://heroku.com/verify"
This means that even we use free addons we have to connect our account to our credit or debit card, we can do this on billings section after logging in on heroku webpage.
Now our service should be available on new URL:
https://appName.herokuapp.com/parse/classes/Cars
Firstly to didFinishLaunchingWithOptions with AppDelegate.swift copy following code:
Parse.enableLocalDatastore()
let configuration = ParseClientConfiguration { (configuration) -> Void in
configuration.applicationId = "h..."
configuration.clientKey = "e..."
configuration.server = "https://appName.herokuapp.com/parse"
}
Parse.initializeWithConfiguration(configuration)
then for example to viewDidLoad() copy and paste following code:
let carObject = PFObject(className: "Car")
carObject["carName"] = "Subaru"
carObject.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
print("Object has been saved.")
}
if in console you got this error:
"[Error]: The resource could not be loaded because the App Transport Security policy requires the use of a secure connection. (Code: 100, Version: 1.12.0)"
The recipe for resolving this issue you can find here.
If everything works, then we should just see: "Object has been saved" in Xcode console.
Voilà!!!
After Migration everything should be transparent to our iOS application:)
When I have finished writing this post I have also discovered different tutorial on the same subject: Guide: How To Migrate Your Parse App To Parse Server With Heroku And MongoLab
which is much more detailed. If you are looking for more information about migration I think it can be really helpfull!:)
It would be great yo hear your opinion and your preferences on how you deal with migration prase:)
Have a nice day!:)
]]>