Getting Started

The Parse platform provides a complete backend solution for your hardware device. Our goal is to totally eliminate the need for writing server code or maintaining servers. Using our C SDKs, all it takes is a few lines of code to save and retrieve data from the Parse Server.

We provide two open source reference implementations for embedded environments:

  1. Embedded C SDK - Targeted for Linux. This can be adapted to target OSes like Ubuntu, Debian, and others.
  2. Embedded RTOS C SDK - Targeted for Real Time OSes. This can be adapted for other embedded RTOS environments.

Both these SDKs provide a consistent interface to interact with the Parse REST API, but with different underlying implementations.

On Parse, you create an App for each of your mobile and embedded applications. Each App has its own application ID and client key that you apply to your SDK install. Your account on Parse can accommodate multiple Apps. This is useful even if you have one application, since you can deploy different versions for test and production.

Initialization

In order for Parse to know which app is associated with the connected device, simply specify the application ID and client key in the device code:

ParseClient client = parseInitialize("${APPLICATION_ID}", "${CLIENT_KEY}");

After this, all calls to the Parse Server will use the specified app.

Want to contribute to this doc? Edit this section.

Objects

The Parse Object

Storing data through the Parse REST API is built around a JSON encoding of the object’s data. This data is schemaless, which means that you don’t need to specify ahead of time what keys exist on each object. You simply set whatever key-value pairs you want, and the backend will store it.

For example, let’s say you’re tracking data for your smart toaster. A single Parse Object could contain:

temperature: 175.0, leverDown: true

Keys must be alphanumeric strings. Values can be strings, numbers, booleans, or even arrays and dictionaries - anything that can be JSON-encoded.

Each object has a class name that you can use to distinguish different sorts of data. For example, we store the temperature data in a class called Temperature. We recommend that you NameYourClassesLikeThis and nameYourKeysLikeThis, just to keep your code looking pretty.

Data Types

So far we’ve used values with type double and bool. The Parse REST API also supports strings, arrays, dates, and more. Read more about representing these and other types as JSON in the REST API Guide.

Want to contribute to this doc? Edit this section.

Requests

The main way you’ll be interacting with Parse is through the parseSendRequest function, which sends a request to the REST API. For example, here’s how to save an object with some data:

char data[] = "{ \"temperature\": 165 }"; parseSendRequest(client, "POST", "/1/classes/Temperature", data, NULL);

For some requests you will be interested in data returned for the request. In such a case you need to setup a callback and pass it to parseSendRequest.

void mySaveCallback(ParseClient client, int error, int httpStatus, const char* httpResponseBody) {
	if (error == 0 && httpResponseBody != NULL) {
		// httpResponseBody holds the response to the request
	}
}

parseSendRequest(client, "GET", "/1/classes/TestObject/gsMHOY3MAx", NULL, myCallback);

Using this function, you have full access to the REST API to create objects, delete objects, send analytics events, and more. Take a look at the REST API Guide to find out all the details.

Want to contribute to this doc? Edit this section.

Users & Sessions

At the core of many apps, there is a notion of user accounts that lets users access their information in a secure manner. In our other SDKs, we provide a specialized user class that automatically handles much of the functionality required for user account management. Users are a special class of Parse Objects and has all the same features, such as flexible schema, automatic persistence, and a key value interface.

You can sign in users via the REST API, but we do not recommend doing so unless your hardware device actually provides user keyboard input. In some cases, you may want to have a companion mobile or desktop app that lets the user sign up, and, that app creates a restricted session for the device running the embedded SDK. During your hardware device provisioning process, the phone can send this restricted session’s token to the device. You can read more about users in our REST API or one of our other SDK guides.

Once you have a session token, you can use it to act on the behalf of a particular user. The session token used by the SDK can be set withparseSetSessionToken:

char token[] = "r:olqZkbv8fefVFNjWegyIXIggd";
parseSetSessionToken(client, token);

Once the session token is set, it will be associated with the current installation if it is not already associated with an installation. This association can be done only once and is automatically done by the SDK.

A session token is tied to a specific installation (specified by the installationId field on the Session object). Attempts to use a session token for another installation will result in errors.

If a session token is set before an installation is set, the SDK will create an installation for you. Thus, if you have a specific pair of installation ID and session token you need to use, you should set the installation ID first.

The session token can be cleared withparseClearSessionToken function. Once the token is cleared, the device will not be authenticated as the user anymore:

parseClearSessionToken(client);

One can get the current session token by doing:

char* session_token = parseGetSessionToken(client);

The session token will be persistent across reboots. Note that we highly recommend using Restricted Sessions on hardware devices, especially ones that do not provide a high level of client security. For more details, check out the guide on Sessions.

Want to contribute to this doc? Edit this section.

Push Notifications

Using Push Notifications, you’ll be able to send realtime notifications to your device. This can be triggered by changes in your data, custom code in Cloud Code, a companion mobile app, and much more.

Installations

Every Parse application installed on a device registered for push notifications has an associated Installation object. The Installation object is where you store all the data needed to target push notifications. For example, you could send a connected thermostat a push to change the desired temperature.

There are two ways to create an installation in conjunction with your hardware device. You can generate an installation ID (random lowercase UUID) elsewhere (e.g. phone), send that to your hardware device during initial provisioning, then set the installation ID on the hardward device:

char data[] = "ab946c14-757a-4448-8b77-69704b01bb7b";
parseSetInstallationId(client, data);

The installation ID is a unique identifier for the device, so you should make sure to assign different installation IDs to different devices (i.e. your UUID generator has enough randomness). After you do the above, the device will automatically create an Installation object with this installation ID.

If you do not pass in an installation ID, the SDK will automatically generate an installation ID for you, and create an Installation object with it upon the first request sent to Parse. There are several events that will trigger this:parseGetInstallationId,parseSetSessionToken,parseSendRequest, andparseStartPushService.

You can retrieve your installation ID with theparseGetInstallationId function:

char* installation_id = parseGetInstallationId(client);

The installation ID is persisted across reboots.

The Installation class has several special fields that help you manage and target devices. The relevant ones for embedded devices are:

  • channels: An array of the channels to which a device is currently subscribed.
  • deviceType: The type of device, “ios”, “android”, “winrt”, “winphone”, “dotnet”, or “embedded” (readonly).
  • installationId: Universally Unique Identifier (UUID) for the device used by Parse. It must be unique across all of an app’s installations.(readonly).
  • appName: The display name of the client application to which this installation belongs.
  • appVersion: The version string of the client application to which this installation belongs.
  • parseVersion: The version of the Parse SDK which this installation uses.

Subscribing to Pushes

In order to subscribe to push notifications, you’ll need to start the push service and define how your device will handle a push when it is received.

First, we define the push callback function:

void myPushCallback(ParseClient client, int error, const char *buffer) {
	if (error == 0 && buffer != NULL) {
		printf("push: '%s'\n", buffer);
	}
}

Then, we set the callback and start the push service loop:

parseSetPushCallback(client, myPushCallback);
parseStartPushService(client);
parseRunPushLoop(client);

In cases where there is already an explicit application loop, we can integrate push into it using a file handle obtained with theparseGetPushSelectHandle function. Then we call theparseProcessNextPushEvent function on each iteration of the loop (not only when there is data on the file descriptor). TheparseProcessNextPushEvent function will call the push callback if there is a new push message.

To do this we must first include the respective libraries:

#include <sys/time.h>

Then add the following logic to your method:

// ...
parseSetPushCallback(client, myPushCallback);
parseStartPushService(client);
int socket = parseGetPushSocket(client);
while(1) {
	struct timeval tv;
	fd_set receive, send, error;

	// tv_sec defines the interval at which the method is executed.
	// The lower the value the more responsive it will be to notifications.

	tv.tv_sec = 10;
	tv.tv_usec= 0;
	FD_ZERO(&receive);
	FD_ZERO(&send);
	FD_ZERO(&error);
	FD_SET(socket, &error);
	FD_SET(socket, &receive);
	select(socket + 1, &receive, &send, &error, &tv);

	// ...

	parseProcessNextPushNotification(client);
}
Want to contribute to this doc? Edit this section.

Cloud Functions

Cloud Functions allow you to run custom app logic in the Parse Cloud. This is especially useful for running complex app logic in the cloud so that you can reduce the memory footprint of your code on the IoT device. In a Cloud Function, you can query/save Parse data, send push notifications, and log analytics events.

You write your Cloud Code in JavaScript using the Parse JavaScript SDK. See our Cloud Code guide for details.

For example, you define a Cloud Function as below.

Parse.Cloud.define("hello", function(request, response) {
	response.success(request.body);
});

Then you can invoke this Cloud Function from your device:

void myCloudFunctionCallback(ParseClient client, int error, int httpStatus, const char* httpResponseBody) {
	if (error == 0 && httpResponseBody != NULL) {
		// httpResponseBody holds the Cloud Function response
	}
}
parseSendRequest(client, "POST", "/1/functions/hello", "{\"value\":\"echo\"}", myCloudFunctionCallback);
Want to contribute to this doc? Edit this section.

Sample App

We prepared a sample app that demonstrates how to provision connected devices using a companion phone app such that connected devices can securely access user-specific data on the Parse Cloud. This sample app also demonstrates how to send push notifications between the phone app and connected devices.

Want to contribute to this doc? Edit this section.

Handling Errors

There are two main ways an error from the SDK can be propagated to the caller - as a return result of the method call, or through the request and push callbacks.

All functions that return a result will return 0 on success and a non-zero value on error. The error value will be an OS-specific error (for example, socket errors).

The errors passed through callbacks are again OS-specific errors. The one exception is if there is an HTTP error status (4xx or 5xx) for a request, in which case, the HTTP status will be passed as separate parameters to the request callback.

In the case of an HTTP error status, you should also check the request body. If the request body contains a valid JSON document, the document will contain a Parse error code, as defined by the REST API documentation.

For a list of all possible error codes, scroll down to Error Codes.

Want to contribute to this doc? Edit this section.

Error Codes

The following is a list of all the error codes that can be returned by the Parse API. You may also refer to RFC2616 for a list of http error codes. Make sure to check the error message for more details.

API Issues

Name Code Description
UserInvalidLoginParams 101 Invalid login parameters. Check error message for more details.
ObjectNotFound 101 The specified object or session doesn’t exist or could not be found. Can also indicate that you do not have the necessary permissions to read or write this object. Check error message for more details.
InvalidQuery 102 There is a problem with the parameters used to construct this query. This could be an invalid field name or an invalid field type for a specific constraint. Check error message for more details.
InvalidClassName 103 Missing or invalid classname. Classnames are case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the only valid characters.
MissingObjectId 104 An unspecified object id.
InvalidFieldName 105 An invalid field name. Keys are case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the only valid characters. Some field names may be reserved. Check error message for more details.
InvalidPointer 106 A malformed pointer was used. You would typically only see this if you have modified a client SDK.
InvalidJSON 107 Badly formed JSON was received upstream. This either indicates you have done something unusual with modifying how things encode to JSON, or the network is failing badly. Can also indicate an invalid utf-8 string or use of multiple form encoded values. Check error message for more details.
CommandUnavailable 108 The feature you tried to access is only available internally for testing purposes.
NotInitialized 109 You must call Parse.initialize before using the Parse library. Check the Quick Start guide for your platform.
ObjectTooLarge 116 The object is too large. Parse Objects have a max size of 128 kilobytes.
ExceededConfigParamsError 116 You have reached the limit of 100 config parameters.
InvalidLimitError 117 An invalid value was set for the limit. Check error message for more details.
InvalidSkipError 118 An invalid value was set for skip. Check error message for more details.
OperationForbidden 119 The operation isn’t allowed for clients due to class-level permissions. Check error message for more details.
CacheMiss 120 The result was not found in the cache.
InvalidNestedKey 121 An invalid key was used in a nested JSONObject. Check error message for more details.
InvalidACL 123 An invalid ACL was provided.
InvalidEmailAddress 125 The email address was invalid.
DuplicateValue 137 Unique field was given a value that is already taken.
InvalidRoleName 139 Role’s name is invalid.
ReservedValue 139 Field value is reserved.
ExceededCollectionQuota 140 You have reached the quota on the number of classes in your app. Please delete some classes if you need to add a new class.
ScriptFailed 141 Cloud Code script failed. Usually points to a JavaScript error. Check error message for more details.
FunctionNotFound 141 Cloud function not found. Check that the specified Cloud function is present in your Cloud Code script and has been deployed.
JobNotFound 141 Background job not found. Check that the specified job is present in your Cloud Code script and has been deployed.
SuccessErrorNotCalled 141 success/error was not called. A cloud function will return once response.success() or response.error() is called. A background job will similarly finish execution once status.success() or status.error() is called. If a function or job never reaches either of the success/error methods, this error will be returned. This may happen when a function does not handle an error response correctly, preventing code execution from reaching the success() method call.
MultupleSuccessErrorCalls 141 Can’t call success/error multiple times. A cloud function will return once response.success() or response.error() is called. A background job will similarly finish execution once status.success() or status.error() is called. If a function or job calls success() and/or error() more than once in a single execution path, this error will be returned.
ValidationFailed 142 Cloud Code validation failed.
WebhookError 143 Webhook error.
InvalidImageData 150 Invalid image data.
UnsavedFileError 151 An unsaved file.
InvalidPushTimeError 152 An invalid push time was specified.
HostingError 158 Hosting error.
InvalidEventName 160 The provided analytics event name is invalid.
ClassNotEmpty 255 Class is not empty and cannot be dropped.
AppNameInvalid 256 App name is invalid.
MissingAPIKeyError 902 The request is missing an API key.
InvalidAPIKeyError 903 The request is using an invalid API key.
Name Code Description
IncorrectType 111 A field was set to an inconsistent type. Check error message for more details.
InvalidChannelName 112 Invalid channel name. A channel name is either an empty string (the broadcast channel) or contains only a-zA-Z0-9_ characters and starts with a letter.
InvalidSubscriptionType 113 Bad subscription type. Check error message for more details.
InvalidDeviceToken 114 The provided device token is invalid.
PushMisconfigured 115 Push is misconfigured in your app. Check error message for more details.
PushWhereAndChannels 115 Can’t set channels for a query-targeted push. You can fix this by moving the channels into your push query constraints.
PushWhereAndType 115 Can’t set device type for a query-targeted push. You can fix this by incorporating the device type constraints into your push query.
PushMissingData 115 Push is missing a ‘data’ field.
PushMissingChannels 115 Non-query push is missing a ‘channels’ field. Fix by passing a ‘channels’ or ‘query’ field.
ClientPushDisabled 115 Client-initiated push is not enabled. Check your Parse app’s push notification settings.
RestPushDisabled 115 REST-initiated push is not enabled. Check your Parse app’s push notification settings.
ClientPushWithURI 115 Client-initiated push cannot use the “uri” option.
PushQueryOrPayloadTooLarge 115 Your push query or data payload is too large. Check error message for more details.
InvalidExpirationError 138 Invalid expiration value.
MissingPushIdError 156 A push id is missing. Deprecated.
MissingDeviceTypeError 157 The device type field is missing. Deprecated.
Name Code Description
InvalidFileName 122 An invalid filename was used for Parse File. A valid file name contains only a-zA-Z0-9_. characters and is between 1 and 128 characters.
MissingContentType 126 Missing content type.
MissingContentLength 127 Missing content length.
InvalidContentLength 128 Invalid content length.
FileTooLarge 129 File size exceeds maximum allowed.
FileSaveError 130 Error saving a file.
FileDeleteError 131 File could not be deleted.
Name Code Description
InvalidInstallationIdError 132 Invalid installation id.
InvalidDeviceTypeError 133 Invalid device type.
InvalidChannelsArrayError 134 Invalid channels array value.
MissingRequiredFieldError 135 Required field is missing.
ChangedImmutableFieldError 136 An immutable field was changed.
Name Code Description
ReceiptMissing 143 Product purchase receipt is missing.
InvalidPurchaseReceipt 144 Product purchase receipt is invalid.
PaymentDisabled 145 Payment is disabled on this device.
InvalidProductIdentifier 146 The product identifier is invalid.
ProductNotFoundInAppStore 147 The product is not found in the App Store.
InvalidServerResponse 148 The Apple server response is not valid.
ProductDownloadFilesystemError 149 The product fails to download due to file system error.
Name Code Description
UsernameMissing 200 The username is missing or empty.
PasswordMissing 201 The password is missing or empty.
UsernameTaken 202 The username has already been taken.
UserEmailTaken 203 Email has already been used.
UserEmailMissing 204 The email is missing, and must be specified.
UserWithEmailNotFound 205 A user with the specified email was not found.
SessionMissing 206 A user object without a valid session could not be altered.
MustCreateUserThroughSignup 207 A user can only be created through signup.
AccountAlreadyLinked 208 An account being linked is already linked to another user.
InvalidSessionToken 209 The device’s session token is no longer valid. The application should ask the user to log in again.

Linked services errors

Name Code Description
LinkedIdMissing 250 A user cannot be linked to an account because that account’s id could not be found.
InvalidLinkedSession 251 A user with a linked (e.g. Facebook or Twitter) account has an invalid session. Check error message for more details.
InvalidGeneralAuthData 251 Invalid auth data value used.
BadAnonymousID 251 Anonymous id is not a valid lowercase UUID.
FacebookBadToken 251 The supplied Facebook session token is expired or invalid.
FacebookBadID 251 A user with a linked Facebook account has an invalid session.
FacebookWrongAppID 251 Unacceptable Facebook application id.
TwitterVerificationFailed 251 Twitter credential verification failed.
TwitterWrongID 251 Submitted Twitter id does not match the id associated with the submitted access token.
TwitterWrongScreenName 251 Submitted Twitter handle does not match the handle associated with the submitted access token.
TwitterConnectFailure 251 Twitter credentials could not be verified due to problems accessing the Twitter API.
UnsupportedService 252 A service being linked (e.g. Facebook or Twitter) is unsupported. Check error message for more details.
UsernameSigninDisabled 252 Authentication by username and password is not supported for this application. Check your Parse app’s authentication settings.
AnonymousSigninDisabled 252 Anonymous users are not supported for this application. Check your Parse app’s authentication settings.
FacebookSigninDisabled 252 Authentication by Facebook is not supported for this application. Check your Parse app’s authentication settings.
TwitterSigninDisabled 252 Authentication by Twitter is not supported for this application. Check your Parse app’s authentication settings.
InvalidAuthDataError 253 An invalid authData value was passed. Check error message for more details.
LinkingNotSupportedError 999 Linking to an external account not supported yet with signup_or_login. Use update instead.

Client-only errors

Name Code Description
ConnectionFailed 100 The connection to the Parse servers failed.
AggregateError 600 There were multiple errors. Aggregate errors have an “errors” property, which is an array of error objects with more detail about each error that occurred.
FileReadError 601 Unable to read input for a Parse File on the client.
XDomainRequest 602 A real error code is unavailable because we had to use an XDomainRequest object to allow CORS requests in Internet Explorer, which strips the body from HTTP responses that have a non-2XX status code.

Operational issues

Name Code Description
RequestTimeout 124 The request was slow and timed out. Typically this indicates that the request is too expensive to run. You may see this when a Cloud function did not finish before timing out, or when a Parse.Cloud.httpRequest connection times out.
InefficientQueryError 154 An inefficient query was rejected by the server. Refer to the Performance Guide and slow query log.
RequestLimitExceeded 155 This application has exceeded its request limit (legacy Parse.com apps only).
TemporaryRejectionError 159 An application’s requests are temporary rejected by the server (legacy Parse.com apps only).
DatabaseNotMigratedError 428 You should migrate your database as soon as possible (legacy Parse.com apps only).

Other issues

Name Code Description
OtherCause -1 An unknown error or an error unrelated to Parse occurred.
InternalServerError 1 Internal server error. No information available.
ServiceUnavailable 2 The service is currently unavailable.
ClientDisconnected 4 Connection failure.
Want to contribute to this doc? Edit this section.