-
Notifications
You must be signed in to change notification settings - Fork 472
Configuring a Parse Server
Parse provides a cloud-based backend service to build data-driven mobile apps quickly. Facebook, which acquired the company in 2013, shut down service on January 28, 2017. An open source version enables developers to continue using their apps was published, along with a migration guide.
While there are many alternate options to Parse, most of them lack either the functionality, documentation, or sample code to enable quick prototyping. For this reason, the open source Parse version is a good option to use with minimal deployment/configuration needed.
You can review this Wiki to understand the current development progress of this app. There are a few notable differences in the open source version:
-
Authentication: By default, only an application ID is needed to authenticate with open source Parse. The base configuration that comes with the one-click deploy options does not require authenticating with any other types of keys. Therefore, specifying client keys on Android or iOS is not needed.
-
Push notifications: Because of the implicit security issues with allowing push notifications to be sent through Android or iOS directly to other devices, this feature is disabled. Normally in Parse.com you can toggle an option to override this security restriction. For open source Parse, you must implement pre-defined code written in JavaScript that can be called by the clients to execute, otherwise known as Parse Cloud.
-
Single app aware: The current version only supports single app instances. There is ongoing work to make this version multi-app aware. However, if you intend to run many different apps with different datastores, you currently would need to instantiate separate instances.
-
File upload limitations: The backend for open source is backed by MongoDB, and the default storage layer relies on Mongo's GridFS layer. The current limit is set for 20 MB but you depend on storing large files, you should really configure the server to use Amazon's Simple Storage Service (S3).
Many of the options need to be configured by tweaking your own configuration. You may wish to fork the code that helps instantiate a Parse server and change them based on your own needs.
We will be using back4app.com to host our Parse dashboard.
If you are interested in hosting your Parse dashboard in another platform (i.e. AWS, Azure, Google GCP, etc.), check out this guide.
:::warning Note: Most other hosts require a credit card to get started with a Parse dashboard. :::
Below are the steps for deploying your Parse server on back4app.
Back4app is a platform that helps minimizing the workload of setting up the backend. Basically, they set up all the backend for you. Due to the nature of our course, we will mainly focus on how to connect an iOS app to your own backend server rather than teach the nitty gritties of creating a backend from scratch.
- Sign Up for Back4app
- Create a new Parse App
- Save your config variables (located on Core settings):
- Leave
PARSE_MOUNT
to be/parse
. It does not need to be changed. - Set
APP_ID
for the app identifier. If you do not set one, the default is set asmyAppId
. You will need this info for the Client SDK setup. - Set
MASTER_KEY
to be the master key used to read/write all data. You will only use this key if you intend to setup the Parse Dashboard. - Set
SERVER_URL
to correspond to match the App Name you defined in step #2 along with the PARSE_MOUNT (e.g. https://yourappname.herokuapp.com/parse) - If you intend to use Parse's Facebook authentication, set
FACEBOOK_APP_ID
to be the FB application ID.
-
^^Using the config variables, connect your app:
// AppDelegate.swift // Don't forget to install Parse pods! import Parse func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) { let parseConfig = ParseClientConfiguration { $0.applicationId = "parseAppId" $0.clientKey = "parseClientKey" $0.server = "parseServerUrlString" } Parse.initialize(with: parseConfig) return true }
You can change the core setting values to whatever you would like!
What's also good about Back4app.com is that it provides the dashboard for you so you can view the Parse data. Here is a screenshot of where your Parse data is stored:
-
Create a Podfile file:
pod init
-
Add dependencies in your Podfile (Don't forget to save your Podfile):
# Uncomment the next line to define a global platform for your project # platform :ios, '9.0' target 'YOUR_APP' do # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! # Pods for YOUR_APP pod 'Parse' ...
-
Install the new pods:
pod install
-
Initialize Parse in your
AppDelegate
to point to your own server:// AppDelegate.swift // ... import Parse class AppDelegate: UIResponder, UIApplicationDelegate { // ... func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Initialize Parse // Set applicationId and server based on the values in the Heroku settings. Parse.initialize( with: ParseClientConfiguration(block: { (configuration: ParseMutableClientConfiguration) -> Void in configuration.applicationId = "myAppId" configuration.server = "https://myAppName.herokuapp.com/parse" }) )
#import "AppDelegate.h" #import "Parse/Parse.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( NSDictionary *)launchOptions { ParseClientConfiguration *config = [ParseClientConfiguration configurationWithBlock:^(id<ParseMutableClientConfiguration> configuration) { configuration.applicationId = @"codepathInstagram"; configuration.server = @"http://codepathfbinstagram.herokuapp.com/parse"; }]; [Parse initializeWithConfiguration:config]; return YES; }
The /parse
path needs to match the PARSE_MOUNT
environment variable, which is set to this value by default.
One of the newer features of Parse is that you can monitor for live changes made to objects in your database (i.e. creation, updates, and deletes) To get started, make sure you have defined the ParseObjects that you want in your NodeJS server. Make sure to define a list of all the objects by declaring it in the liveQuery
and classNames listing
:
let api = new ParseServer({
...,
// Make sure to define liveQuery AND classNames
liveQuery: {
// define your ParseObject names here
classNames: ['Post', 'Comment']
}
});
See this guide and this spec for more details. Parse Live Queries rely on the websocket protocol, which creates a bidirectional channel between the client and server and periodically exchange ping/pong frames to validate the connection is still alive.
Websocket URLs are usually prefixed with ws:// or wss:// (secure) URLs. Heroku instances already provide websocket support, but if you are deploying to a different server (Amazon), you may need to make sure that TCP port 80 or TCP port 443 are available.
-
If you see
Application Error
orAn error occurred in the application and your page could not be served. Please try again in a few moments.
, double-check that you set aMASTER_KEY
in the environment settings for that app. -
If you are using Heroku, download the Heroku Toolbelt app here to help view system logs.
First, you must login with your Heroku login and password:
heroku login
You can then view the system logs by specifying the app name:
heroku logs --app <app name>
The logs should show the response from any types of network requests made to the site. Check the
status
code.2016-02-07T08:28:14.292475+00:00 heroku[router]: at=info method=POST path="/parse/classes/Message" host=parse-testing-port.herokuapp.com request_id=804c2533-ac56-4107-ad05-962d287537e9 fwd="101.12.34.12" dyno=web.1 connect=1ms service=2ms status=404 bytes=179
-
Create an auth token through developer.apple.com by clicking on the
Keys
->All
section. Fill out a name and make sure the APNS service is checked: Save the.p8
file and record the key ID. You will need to add this information to your Parse configuration. -
Fork your own copy of the Parse server code that initially used to deploy to Heroku. You will need to reconfigure your Heroku instance to point to this repo instead of Parse's because of additional customizations needed to be made on the
index.js
file within this repo. -
Copy the
.p8
certificate you exported and add it to this forked repo. This.p8
file should not have a passphrase with it. -
You will now need to edit the
index.js
to include to the APNS certificate. You will need to specify the key ID, team ID, and the location of thisp8
certificate. ```javascript var authKeyPath = path.resolve(__dirname, 'AuthKey.p8');var pushConfig = {'ios': { token: { key: authKeyPath, // P8 file only keyId: 'XXXXX', // key ID teamId: 'YYYYY', // The Team ID of your Apple Developer Account (available at https://developer.apple.com/account/#/membership/) }, production: false // set explicitly } }; ```
The Parse server relies on the node-apn module for sending Apple push notifications. See this guide for more information about iOS push options.
-
Make sure to include this
pushConfig
into your definition:```javascript var api = new ParseServer({ . . push: pushConfig, }); ```
-
Follow client steps to enable Push notifications inside your app.
- Make sure to use the same bundle identifier as the name specified in your server configuration.
- Verify that you've turned on Push Notifications in the
Capabilities
section. - Click on
Build Setting
", and find (or search for) theCode Signing Identity
field. This field should be set toiOS Developer
if you're testing against development, oriOS Distribution
if you're testing in production or building your app for the App Store.
-
Make sure to register your application for push notifications. First, you should specify inside
AppDelegate.swift
the notification types to which the app will respond:```swift // Swift func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { ... let userNotificationTypes: UIUserNotificationType = [.Alert, .Badge, .Sound] let settings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil) application.registerUserNotificationSettings(settings) application.registerForRemoteNotifications() ... } ```
-
Next, the
application:didRegisterForRemoteNotificationsWithDeviceToken:
will be called if registration is successful. The response comes with a device token which we want to pass along to the server.func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) { let installation = PFInstallation.currentInstallation() installation.setDeviceTokenFromData(deviceToken) installation.channels = ["global"] installation.saveInBackground() }
-
Test out whether you can receive push notifications by using this Curl command:
curl -X POST \ -H "X-Parse-Application-Id: myAppId" \ -H "X-Parse-Master-Key: masterKey" \ -H "Content-Type: application/json" \ -d '{ "where": { "deviceType": "ios" }, "data": { "title": "The Shining", "alert": "All work and no play makes Jack a dull boy." } }'\ http://yourherouapp.herokuapp.com/parse/push
You should see inside your logs:
APNS Connection 0 Connected APNS Connection 0 Notification transmitted to <device_token>
NOTE: Apple has two separate push notification environments for production and development purposes. Whether your push tokens are granted for development or production purposes depends on the certificate used to build your app. If the app was signed using an App Store certificate, it is designated for production. Otherwise, in most other cases, the token is relying on the development environment.
If you are building and testing your app in XCode (note that push notifications cannot be tested on an emulator), you will likely be testing in the development environment. Once your app is distributed through the app store, you will need to setup the Parse server to be rely on the production: true
setting. You will most likely need to have separate Parse servers, one setup for production and the other setup for development purposes.
While support for push notifications is now available with the open source Parse server, you cannot implement this type of code on the actual client:
// Note: This does NOT work with open Parse Server at this time
let push = PFPush.init()
push.setChannel("mychannel")
push.setMessage("this is my message")
push.sendPushInBackground()
You will likely see this error in the API response:
unauthorized: master key is required (Code: 0, Version: 1.12.0)
Instead, you need to write your own server-side Parse code and have the client invoke it.
Verify that cloud/main.js
is the default value of CLOUD_CODE_MAIN
environment variable. You should modify your cloud/main.js
file to define this Parse Cloud function:
// iOS push testing
Parse.Cloud.define("iosPushTest", function(request, response) {
// request has 2 parameters: params passed by the client and the authorized user
var params = request.params;
var user = request.user;
// Our "Message" class has a "text" key with the body of the message itself
var messageText = params.text;
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('deviceType', 'ios'); // targeting iOS devices only
Parse.Push.send({
where: pushQuery, // Set our Installation query
data: {
alert: "Message: " + messageText
}
}, { success: function() {
console.log("#### PUSH OK");
}, error: function(error) {
console.log("#### PUSH ERROR" + error.message);
}, useMasterKey: true});
response.success('success');
});
Make sure to redeploy your code with these changes to Heroku first. Then you can use the client to test:
curl -X POST \
-H "X-Parse-Application-Id: myAppId" \
-H "X-Parse-Master-Key: masterKey" \
-H "Content-Type: application/json" \
-d '{
"where": {
"deviceType": "ios"
},
"text": "This is a test"
}' \
http://myherokuapp.herokuapp.com/parse/functions/iosPushTest
You should receive a {"result":"success"}
message back if your application ID
and masterKey
matches your configuration.
You can then invoke this function inside your iOS client by adding the following command. Note how the text
parameter is used for the message to be sent:
PFCloud.callFunctionInBackground("iosPushTest", withParameters: ["text" : "Testing"])
-
Query the
Installation
table and make sure your app has registered a device token.curl -X GET \ -H "X-Parse-Application-Id: myAppId" \ -H "X-Parse-Master-Key: masterKey" \ http://myappname.herokuapp.com/parse/installations | python -mjson.tool
You should see:
{ "appIdentifier": "beta.codepath.pushtest", "appName": "pushtest", "appVersion": "1", "badge": 0, "channels": [ "global" ], "createdAt": "2016-03-13T07:07:12.184Z", "deviceToken": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "deviceType": "ios", "installationId": "498afd36-1987-4762-a5a3-9b958de41089", "localeIdentifier": "en-US", "objectId": "E6RQBu4q3e", "parseVersion": "1.12.0", "timeZone": "America/Los_Angeles", "updatedAt": "2016-03-13T07:07:12.184Z" }
-
Make sure your bundle ID matches what you specified in your
index.js
. If you getInvalid Token
responses, it means that you may have a mismatch issue. -
If you are using a development certificate, make sure it is marked as
production: false
in your Parse server configuration. -
Verify you can connect to Apple's APNS service by following these instructions.
-
Enable network logging on your IOS client by reviewing this Parse guide.