Skip to main content

REST API Guide

You can access LeanCloud from any devices supporting HTTP requests with REST API, for example:

  • You can manipulate data on LeanCloud with any programming language.
  • If you want to migrate from LeanCloud to other services, you can export all your data.
  • Your mobile site can fetch data from LeanCloud via JavaScript directly if you regard importing LeanCloud JavaScript SDK as overkill.
  • You can add new data in batch, to be consumed by mobile applications later.
  • You can export recent data for offline analysis or additional incremental backup.

API Version

The current API version is 1.1.

Testing

This guide provides curl command line examples. You may need to modify some syntax if using cmd.exe on Windows. For example, \ in curl examples means to be continued on the next line, but cmd.exe will consider it as path separator. Therefore, we recommend you to use Postman for testing on Windows.

Postman can import curl commands directly and automatically generate code snippets in various languages and frameworks.

点击展开 Postman 示例

Postman 可直接导入 curl 命令。

Postman 中点击 Import 按钮,在「Raw Text」标签中粘贴 curl 命令

Postman 还支持自动生成多种语言(库)调用 REST API 的代码。

Postman 中点击 Code,在展开的面板中选择语言(库)

Base URL

Base URL: FIRST_8_DIGITS_OF_YOUR_APP_ID.api.lncldglobal.com

object

URLHTTP功能
/1.1/classes/<className>POSTcreate an object
/1.1/classes/<className>/<objectId>GETretrieve an object
/1.1/classes/<className>/<objectId>PUTupdate an object
/1.1/classes/<className>GETquery objects
/1.1/classes/<className>/<objectId>DELETEdelete an object
/1.1/scan/classes/<className>GETiterate over objects

roles

URLHTTP功能
/1.1/rolesPOSTcreate a role
/1.1/roles/<objectId>GETretrieve a role
/1.1/roles/<objectId>PUTupdate a role
/1.1/rolesGETquery roles
/1.1/roles/<objectId>DELETEdelete a role

Schema

URLHTTP功能
/1.1/schemasGETretrieve all schemas
/1.1/schemas/<className>GETretrieve specified class schema

other

URLHTTP功能
/1.1/dateGETretrieve date and time at server side
/1.1/exportDataPOSTrequest to export data
/1.1/exportData/<id>GETretrieve status and result of export data job

Request Format

The request body should be JSON, and the Content-Type should be application/json accordingly.

X-LC-Id and X-LC-Key HTTP headers are used for authentication.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "update blog post"}' \
https://{{host}}/1.1/classes/Post/<objectId>

X-LC-Id is App ID. X-LC-Key is App Key or Master Key. A ,master postfix is used to distinguish Master Key and App Key, e.g.:

X-LC-Key: {{masterkey}},master

Cross-origin resource sharing is supported so that you can use these headers with XMLHttpRequest in JavaScript.

You can also use Accept-Encoding HTTP header to enable compression (gzip or brotli).

X-LC-Sign

You may also authenticate requests via X-LC-Sign instead of X-LC-Key:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Sign: d5bcbb897e19b2f6633c716dfdfaf9be,1453014943466" \
-H "Content-Type: application/json" \
-d '{"content": "reduce risk of App Key exposure"}' \
https://{{host}}/1.1/classes/Post/<objectId>

The value of X-LC-Sign is a string sign,timestamp[,master]:

NameOptionalityDescription
signrequiredConcat timestamp and App Key (or Master Key), then calculate its MD5 hash value.
timestamprequiredUnix timestamp of the current request, accurate to milliseconds.
masteroptionalUse this postfix to indicate Master Key is used.

For example, given the following application:

App IdFFnN2hso42Wego3pWq4X5qlu
App KeyUtOCzqb67d3sN12Kts4URwy8
Master KeyDyJegPlemooo4X1tg94gQkw1
Request date2016-01-17 7:15:43.466 UTC
timestamp1453014943466

Calculate sign with App Key

md5( timestamp + App Key )
= md5(

1453014943466UtOCzqb67d3sN12Kts4URwy8
)
= d5bcbb897e19b2f6633c716dfdfaf9be

  -H "X-LC-Sign: d5bcbb897e19b2f6633c716dfdfaf9be,1453014943466" \

Calculate sign with Master Key

md5( timestamp + Master Key )
= md5(1453014943466DyJegPlemooo4X1tg94gQkw1)
= e074720658078c898aa0d4b1b82bdf4b
  -H "X-LC-Sign: e074720658078c898aa0d4b1b82bdf4b,1453014943466,master" \

Using master key will bypass all permission validations. Make sure you do not leak the master key and only use it in restrained environments.

Specify hook invocation environment

Requests may trigger hooks, and you can use X-LC-Prod HTTP header to specify the invocation environment:

X-LC-Prod ValueEnvironment
0stage
1production

If you do not specify the X-LC-Prod HTTP header, LeanCloud will invoke the hook in the production environment.

Response Format

The response body is a JSON object.

HTTP status code is used to indicate whether a request succeeded or failed. A 2xx status code indicates success, and a 4xx/5xx status code indicates an error is encountered. When an error is encountered, the response body is a JSON object with two fields: code and error, where code is the error code (integer) and error is a brief error message (string). The code may be identical to the HTTP status code, but usually it is a customized error code more specific than the HTTP status code. For example, if you try to save an object with an invalid key name:

{
"code":105,
"error":"Invalid key name. Keys are case-sensitive and 'a-zA-Z0-9_' are the only valid characters. The column is: 'invalid?'."}

Object

Object Format

LeanStorage is built around objects. Each object is consist of several key-value pairs, where values are in a JSON compatible format. Objects are schemaless, so you do not need to allocate keys at the beginning. You only need to set key-value pairs as you wish and when needed.

For example, if you are implementing a Twitter-like social App, and a tweet may contain the following attributes (key-value pairs):

{
"content": "Serverless cloud for lightning-fast development.",
"pubUser": "LeanCloud",
"pubTimestamp": 1435541999
}

Keys can only contain letters, numbers, and underscores. Values can be anything encoded in JSON.

Each object belongs to a class (table in traditional database terms). We recommend to use CapitalizedWords to name your classes, and mixedCases to name your attributes. This naming style helps to improve code readability.

Each time when an object is saved to the cloud, a unique objectId will be assigned to it. createdAt and updatedAt will also be filled in by the cloud which indicate the time the object is created and updated. These attributes are preserved, and you cannot modify them yourself. For example, the object above could look like this when retrieved:

{
"content": "Serverless cloud for lightning-fast development.",
"pubUser": "LeanCloud",
"pubTimestamp": 1435541999,
"createdAt": "2015-06-29T01:39:35.931Z",
"updatedAt": "2015-06-29T01:39:35.931Z",
"objectId": "558e20cbe4b060308e3eb36c"
}

createdAt and updatedAt are strings whose content is a UTC timestamp in ISO 8601 format with millisecond precision YYYY-MM-DDTHH:MM:SS.MMMZ. objectId is a string unique in the class, like the primary key of a relational database.

In LeanCloud's REST API, class-level operations use the class name as its endpoint. For example:

https://{{host}}/1.1/classes/Post

Users (the built-in _User class) have a special endpoint:

https://{{host}}/1.1/users

Object-specific operations use nested URLs under the class. For example:

https://{{host}}/1.1/classes/Post/<objectId>

Creating Objects

To create a new object:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "Serverless cloud for lightning-fast development.","pubUser": "LeanCloud","pubTimestamp": 1435541999}' \
https://{{host}}/1.1/classes/Post

If succeed, you will receive 201 Created with a Location header point to the URL of the object just created:

Status: 201 Created
Location: https://{{host}}/1.1/classes/Post/558e20cbe4b060308e3eb36c

And the response body is a JSON object with objectId and createdAt key-value pairs:

{
"createdAt": "2015-06-29T01:39:35.931Z",
"objectId": "558e20cbe4b060308e3eb36c"
}

To tell LeanCloud to return full data, set the fetchWhenSave parameter to true:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "Serverless cloud for lightning-fast development.","pubUser": "LeanCloud","pubTimestamp": 1435541999}' \
https://{{host}}/1.1/classes/Post?fetchWhenSave=true

Class names can only contain letters, numbers, and underscores. Every application can contain up to 500 classes, and there is no limit on objects in each class.

Retrieving Objects

To fetch the object we just created:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/classes/Post/558e20cbe4b060308e3eb36c

The response body is a JSON object containing all attributes you specified above, and three preserved attributes objectId, createdAt, and updatedAt:

{
"content": "Serverless cloud for lightning-fast development.",
"pubUser": "LeanCloud",
"pubTimestamp": 1435541999,
"createdAt": "2015-06-29T01:39:35.931Z",
"updatedAt": "2015-06-29T01:39:35.931Z",
"objectId": "558e20cbe4b060308e3eb36c"
}

To fetch the other objects this object points to, specify them in include parameter:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'include=author' \
https://{{host}}/1.1/classes/Post/<objectId>

If the class does not exist, you will receive a 404 Not Found error:

{
"code": 101,
"error": "Class or object doesn't exists."
}

If LeanCloud cannot find the object according to the objectId you specified, you will receive an empty object (200 OK):

{}

Some built-in classes (class names with a leading underscore) may return a different result when an object does not exist. For example:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/classes/_User/<NonexistObjectId>

will return:

{
"code": 211,
"error": "Could not find user."
}

BTW, we recommend using GET /users/<objectId> to fetch user information, instead of directly querying the _User class. See also Retrieving Users.

Updating Objects

To update an object, you can send a PUT request to the object URL. LeanCloud will only update attributes you explicitly specified in the request (except for updatedAt). For example, just update the content of a post:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "Serverless cloud for lightning-fast development. https://leancloud.app"}' \
https://{{host}}/1.1/classes/Post/<objectId>

If the update succeeds, updatedAt will be returned:

{
"updatedAt": "2015-06-30T18:02:52.248Z"
}

You can also pass the fetchWhenSave parameter, which will return all updated attributes.

Counter

LeanCloud provides an Increment atomic operator to increase a counter-like attribute.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"upvotes":{"__op":"Increment","amount":1}}' \
https://{{host}}/1.1/classes/Post/<objectId>

There is also a Decrement operator. Decrementing a positive number is equivalent to Incrementing a negative number.

Bitwise Operators

LeanCloud provides three bitwise operators for integers:

  • BitAnd: bitwise and
  • BitOr: bitwise or
  • BitXor: bitwise xor
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"flags":{"__op":"BitOr","value": 0x0000000000000004}}' \
https://{{host}}/1.1/classes/Post/<objectId>

Arrays

LeanCloud provides three atomic operators for arrays:

  • Add extends an array attribute by appending elements from the given array.
  • AddUnique is similar to Add, but only appending elements not already contained in the array attribute.
  • Remove removes all occurrences of elements specified in the given array.

The given array mentioned above is passed in as the value of the objects key.

For example, to add some tags to the post:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"tags":{"__op":"AddUnique","objects":["Frontend","JavaScript"]}}' \
https://{{host}}/1.1/classes/Post/<objectId>

Conditional Updates

Suppose we are going to deduct some money from an Account, and we want to make sure this deduction will not result in a negative balance. Then we can use conditional updates.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"balance":{"__op":"Decrement","amount": 30}}' \
"https://{{host}}/1.1/classes/Account/558e20cbe4b060308e3eb36c?where=%7B%22balance%22%3A%7B%22%24gte%22%3A%2030%7D%7D"

Here %7B%22balance%22%3A%7B%22%24gte%22%3A%2030%7D%7D is the URL-encoded condition {"balance":{"$gte": 30}}. Refer to Queries for more examples.

If the condition is not met, the update will not be performed, and you will receive a 305 error:

{
"code" : 305,
"error": "No effect on updating/deleting a document."
}

Note: where must be passed in as the query parameter of URL.

Deleting Objects

To delete an object, send a DELETE request:

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/classes/Post/<objectId>

To delete an attribute from an object, send a PUT request with the Delete operator:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"downvotes":{"__op":"Delete"}}' \
https://{{host}}/1.1/classes/Post/<objectId>

Conditional Delete

Similar to conditional updates, we pass a URL-encoded where parameter to the DELETE request.

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
"https://{{host}}/1.1/classes/Post/<objectId>?where=%7B%22clicks%22%3A%200%7D" # {"clicks": 0}

Again, if the condition is not met, the update will not be performed, and you will receive a 305 error:

{
"code" : 305,
"error": "No effect on updating/deleting a document."
}

Iterate over Objects

For classes with a moderate number of objects, we can iterate over all objects in the class via queries (with skip and limit). However, for classes with a large number of objects, skip is inefficient. Therefore, LeanCloud provides a scan endpoint to iterate over objects of a class efficiently. By default, scan returns 100 results in ascending order by objectId. You can ask LeanCloud to return up to 1000 results via specifying the limit parameter.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \ # requires master key
-G \
--data-urlencode 'limit=10' \
https://{{host}}/1.1/scan/classes/Article

LeanCloud will return a results array and a cursor.

{
"results":
[
{
"tags" : ["clojure","\u7b97\u6cd5"],
"createdAt": "2016-07-07T08:54:13.250Z",
"updatedAt": "2016-07-07T08:54:50.268Z",
"title" : "clojure persistent vector",
"objectId" : "577e18b50a2b580057469a5e"
},
...
],
"cursor": "pQRhIrac3AEpLzCA"}

The cursor will be null if there are no more results. When cursor is not null, you can pass the cursor value to continue the iteration:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
--data-urlencode 'cursor=pQRhIrac3AEpLzCA' \
https://{{host}}/1.1/scan/classes/Article

Each cursor must be consumed within 10 minutes. It becomes invalid after 10 minutes.

You can also specify where conditions for filtering:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
--data-urlencode 'where={"score": 100}' \
https://{{host}}/1.1/scan/classes/Article

As mentioned above, by default the results are in ascending order by objectId. To return results ordered by another attribute, pass that attribute as the scan_key parameter.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
--data-urlencode 'scan_key=score' \
https://{{host}}/1.1/scan/classes/Article

To return results in descending order, prefix a minus sign (-) to the value of the scan_key, e.g., -score.

The value of the scan_key passed must be strictly monotonous, and it cannot be used in where conditions.

Batch Operations

To reduce network interactions, you can wrap create, update, and delete operations on multiple objects in one request.

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{
"method": "POST",
"path": "/1.1/classes/Post",
"body": {
"content": "Most Internet-based applications are data-driven and share a very similar architecture...",
"pubUser": "LeanCloud"
}
},
{
"method": "POST",
"path": "/1.1/classes/Post",
"body": {
"content": "LeanMessage is designed with the following goals:...",
"pubUser": "LeanCloud"
}
}
]
}' \
https://{{host}}/1.1/batch

Currently there is no limit on wrapped requests number, but LeanCloud has a 20 MB size limit on request body for all API requests.

The wrapped operations will be performed according to the order given in the requests array. And the response body will also be an array, with corresponding length and order. Each member of the results array will be a JSON object with one and only one key, and that key will be either success or error. The value of success or error will be the response to the corresponding single request on success or failure respectively.

[
{
"error": {
"code": 1,
"error": "Could not find object by id '558e20cbe4b060308e3eb36c' for class 'Post'."
}
},
{
"success": {
"updatedAt": "2017-02-22T06:35:29.419Z",
"objectId": "58ad2e850ce463006b217888"
}
}
]

Be aware that the HTTP status 200 returned by a batch request only means LeanCloud had received and performed the operations. It does not mean all operations within the batch request succeeded.

Besides POST requests in the above example, you can also wrap PUT and DELETE requests in a batch request:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{
"method": "PUT",
"path": "/1.1/classes/Post/55a39634e4b0ed48f0c1845b",
"body": {
"upvotes": 2
}
},
{
"method": "DELETE",
"path": "/1.1/classes/Post/55a39634e4b0ed48f0c1845c"
}
]
}' \
https://{{host}}/1.1/batch

Batch requests can also be used to replace requests with very long URLs (usually constructed with very complex queries or conditions) to bypass the limit on URL length enforced by the server side or the client side.

Advanced Data Types

Besides standard JSON values, LeanCloud also supports advanced data types like Date and Files. These advanced data types are encoded as a JSON object with a __type key.

Date contains an iso key, whose value is a UTC timestamp string in ISO 8601 format with millisecond precision YYYY-MM-DDTHH:MM:SS.MMMZ.

{
"__type": "Date",
"iso": "2015-06-21T18:02:52.249Z"
}

As mentioned above, built-in date attributes createdAt and updatedAt are UTC timestamp strings. They are not enclosed in a JSON object.

Byte contains a base64 key, whose value is a MIME base64 string (no whitespace characters).

{
"__type": "Bytes",
"base64": "5b6I5aSa55So5oi36KGo56S65b6I5Zac5qyi5oiR5Lus55qE5paH5qGj6aOO5qC877yM5oiR5Lus5bey5bCGIExlYW5DbG91ZCDmiYDmnInmlofmoaPnmoQgTWFya2Rvd24g5qC85byP55qE5rqQ56CB5byA5pS+5Ye65p2l44CC"
}

Pointer contains a className key and an objectId key, whose values are the corresponding class name and objectId of the pointed value.

{
"__type": "Pointer",
"className": "Post",
"objectId": "55a39634e4b0ed48f0c1845c"
}

A pointer to a user contains a className of _User. The leading underscore indicates that the _User class is built-in. Similarly, pointers to roles and installations contain a className of _Role or _Installation respectively. However, a pointer to a file is a special case:

{
"id": "543cbaede4b07db196f50f3c",
"__type": "File"
}

GeoPoint contains latitude and longitude of the location:

{
"__type": "GeoPoint",
"latitude": 39.9,
"longitude": 116.4
}

We may add more advanced data types in the future, so you should not use __type on your own JSON objects.

Queries

Basic Queries

To list objects in a class, just send a GET request to the class URL:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
https://{{host}}/1.1/classes/Post

The response body is a JSON object containing a results key, whose value is an array of objects:

{
"results": [
{
"content": "Most Internet-based applications are data-driven and share a very similar architecture...",
"pubUser": "LeanCloud",
"upvotes": 2,
"createdAt": "2015-06-29T03:43:35.931Z",
"objectId": "55a39634e4b0ed48f0c1845b"
},
{
"content": "LeanMessage is designed with the following goals:...",
"pubUser": "LeanCloud",
"pubTimestamp": 1435541999,
"createdAt": "2015-06-29T01:39:35.931Z",
"updatedAt": "2015-06-29T01:39:35.931Z",
"objectId": "558e20cbe4b060308e3eb36c"
}
]
}

Query Constraints

The where parameter is used to apply query constraints. It should be encoded as JSON first, then URL encoded.

The simplest form of where parameter is a key-value pair (exact match). For example, to query posts published by LeanCloud:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={"pubUser":"LeanCloud"}' \
https://{{host}}/1.1/classes/Post

Other operators available in the where parameter:

OperatorDescription
$nenot equal to
$ltless than
$lteless than or equal to
$gtgreater than
$gtegreater than or equal to
$regexmatch a regular expression
$incontain
$ninnot contain
$allcontain all (for array type)
$existsthe given key exists
$selectmatch the result of another query
$dontSelectnot match the result of another query

To query posts published on 2015-06-29 :

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={"createdAt":{"$gte":{"__type":"Date","iso":"2015-06-29T00:00:00.000Z"},"$lt":{"__type":"Date","iso":"2015-06-30T00:00:00.000Z"}}}' \
https://{{host}}/1.1/classes/Post

Posts whose votes is an odd number less than 10:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={"upvotes":{"$in":[1,3,5,7,9]}}' \
https://{{host}}/1.1/classes/Post

Posts not published by LeanCloud:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={"pubUser":{"$nin":["LeanCloud"]}}' \
https://{{host}}/1.1/classes/Post

Posts have been voted by someone:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={"upvotes":{"$exists":true}}' \
https://{{host}}/1.1/classes/Post

Posts have not been voted:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={"upvotes":{"$exists":false}}' \
https://{{host}}/1.1/classes/Post

Suppose we use _Followee and _Follower classes for the following relationship, then we can query posts published by someone followed by the current user like this:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={
"author": {
"$select": {
"query": {
"className":"_Followee",
"where": {
"user":{
"__type": "Pointer",
"className": "_User",
"objectId": "55a39634e4b0ed48f0c1845c"
}
}
},
"key":"followee"
}
}
}' \
https://{{host}}/1.1/classes/Post

Other parameters:

ParameterDescription
orderOrder by. Prefix - for descending.
limitThe number of returned objects. Defaults to 100 and the max is 1000.
skipSkipped results. Used for pagination.
keysOnly return specified keys. Prefix - for not including.
returnACLProvided that you have enabled Include ACL with objects being queried in Dashboard > LeanStorage > Settings, when this parameter is true, the returned objects will also include their ACL fields.

To query posts ordered by creation time:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'order=createdAt' \ # ascending
https://{{host}}/1.1/classes/Post

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'order=-createdAt' \ # descending
https://{{host}}/1.1/classes/Post

To sort results by multiple keys, use a comma to separate them:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'order=createdAt,-pubUser' \
https://{{host}}/1.1/classes/Post

An example of pagination:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'limit=200' \
--data-urlencode 'skip=400' \
https://{{host}}/1.1/classes/Post

If you only care about the content and author of posts:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'keys=pubUser,content' \
https://{{host}}/1.1/classes/Post

Note that returned objects will always contain preserved attributes such as objectId, createdAt, and updatedAt.

If you do not care about the post author:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'keys=-author' \
https://{{host}}/1.1/classes/Post

The inverted selection applies to preserved attributes, e.g. keys=-createdAt,-updatedAt,-objectId, too. You can also use it with dot notation, e.g. keys=-pubUser.createdAt,-pubUser.updatedAt.

The parameters mentioned above can be combined.

Regex Queries

To query posts whose title begins with WTO:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'where={"title":{"$regex":"^WTO.*","$options":"i"}}' \
https://{{host}}/1.1/classes/Post

The above example specifies i in options. Thus it is a case-insensitive search.

Available options (flags):

OptionsDescriptionNotes
icase-insensitive searchsame as in JavaScript
mmulti-line searchsame as in JavaScript
sallow . to match newline charactersadded in ES2018
xfree-spacing and line commentssame as in Perl

Options can be combined, for example "$options":"sixm".

Array Queries

Queries on keys with an array type overloads some operators mentioned above:

OperatorsExamplek is not an arrayk is an array
n/awhere={"k":2}k == 2k contains 2
inwhere={"k":{"$in":[2,3]}}k is 2 or 3k contains 2 or 3
allwhere={"arrayKey":{"$all":[2,3]}}n/ak contains 2 and 3
sizewhere={"arrayKey":{"$size": 3}}n/ak has a length of 3

Pointer Queries

To query a Pointer type attribute:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'where={"post":{"__type":"Pointer","className":"Post","objectId":"558e20cbe4b060308e3eb36c"}}' \
https://{{host}}/1.1/classes/Comment

To query objects with pointers according to another query on the pointed object, you can use the $inQuery operator.

For example, to query comments on posts with attached images:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'where={"post":{"$inQuery":{"where":{"image":{"$exists":true}},"className":"Post"}}}' \
https://{{host}}/1.1/classes/Comment

Be aware that the limit parameter (default 100, max 1000) also applies to inner queries. Thus you may need to construct queries deliberately to get the expected result. Refer to Caveats about Inner Queries for more details.

To include pointed objects in one query, use include parameter. For example, to query most recent 10 comments with the posts commented on:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'order=-createdAt' \
--data-urlencode 'limit=10' \
--data-urlencode 'include=post' \
https://{{host}}/1.1/classes/Comment

Without the include parameter, the post attribute of returned comments will look like this:

{
"__type": "Pointer",
"className": "Post",
"objectId": "51e3a359e4b015ead4d95ddc"
}

With the include=post parameter, the post attribute will be dereferenced:

{
"__type": "Object",
"className": "Post",
"objectId": "51e3a359e4b015ead4d95ddc",
"createdAt": "2015-06-29T09:31:20.371Z",
"updatedAt": "2015-06-29T09:31:20.371Z",
"content": "this is a post",
"author": "LeanCloud"
}

You can use dots (.) for multi-level dereference:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'order=-createdAt' \
--data-urlencode 'limit=10' \
--data-urlencode 'include=post.author' \
https://{{host}}/1.1/classes/Comment

And you can use comma (,) to separate multiple pointers to include.

GeoPoint Queries

We have briefly described GeoPoint in the Advanced Data Types section above.

There is currently one limit on GeoPoints: every class can only contain one GeoPoint attribute. Also, be aware that the range of latitude is [-90.0, 90.0], and the range of longitude is [-180.0, 180.0].

To query near objects, you can use the $nearSphere operator.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'limit=10' \
--data-urlencode 'where={
"location": {
"$nearSphere": {
"__type": "GeoPoint",
"latitude": 39.9,
"longitude": 116.4
}
}
}' \
https://{{host}}/1.1/classes/Post

Returned results will be ordered by distance. The first result is the post published at the nearest location. This order can be overwritten by the order parameter.

To limit the maximum distance, you can use $maxDistanceInMiles, $maxDistanceInKilometers, or $maxDistanceInRadians.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'where={
"location": {
"$nearSphere": {
"__type": "GeoPoint",
"latitude": 39.9,
"longitude": 116.4
},
"$maxDistanceInMiles": 10.0
}
}' \
https://{{host}}/1.1/classes/Post

To query for objects within a rectangular area:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'where={
"location": {
"$within": {
"$box": [
{ // southwestGeoPoint
"__type": "GeoPoint",
"latitude": 39.97,
"longitude": 116.33
},
{ // northeastGeoPoint
"__type": "GeoPoint",
"latitude": 39.99,
"longitude": 116.37
}
]
}
}
}' \
https://{{host}}/1.1/classes/Post

File Queries

Querying files is similar to querying normal objects. For example, to query all files (just like querying normal objects, it returns at most 100 results by default):

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
https://{{host}}/1.1/classes/files

{{ data.file_url_query() }}

Counting Results

You can pass count=1 parameter to retrieve the count of matched results. For example, if you just need to know a specific user have posted how many posts:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'where={"pubUser":"LeanCloud"}' \
--data-urlencode 'count=1' \
--data-urlencode 'limit=0' \
https://{{host}}/1.1/classes/Post

Since limit=0, LeanCloud will only return the count, and the results array will be empty.

{
"results": [],
"count": 7
}

Given a nonzero limit parameter, LeanCloud will also return results together with the count.

Compound Queries

You can use $or operator to query objects matching any one of several queries.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'where={"$or":[{"priority":{"$gt":2}},{"isComplete":true}]}' \
https://{{host}}/1.1/classes/Todo

Similarly, you can use $and operator to query objects matching all subqueries.

where={"$and":[{"price": {"$ne":199}},{"price":{"$exists":true}}]}'

The query condition expressions are implicitly combined with the $and operator, so the query expression above could also be rewritten as:

where=[{"price": {"$ne":199}},{"price":{"$exists":true}}]

In fact, since both conditions are targeted at the same field (price), the above query expression can be further simplified to:

where={"price": {"$ne":199, "$exists":true}}

However, to combine two or more OR-ed queries, you have to use the $and operator:

where={"$and":[{"$or":[{"pubUserCertificate":{"$gt":2}},{"pubUserCertificate":{"$lt":3}}]},{"$or":[{"pubUser":"LeanCloud Support"},{"pubUser":"LeanCloud Engineers"}]}]}

Be aware that non-filtering constraints such as limit, skip, order, and include are not allowed in subqueries of a compound query.

Users

With users API, you can build an account system for your application quickly and conveniently.

Users (the _User class) share many traits with other classes. For example, _User is schema-free as well. However, all user objects must have username and password attributes. password will be encrypted automatically. username and email (if available) attributes must be unique (case sensitive).

Signing Up

To create a new user:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"username":"hjiang","password":"f32@ds*@&dsa","region": "China"}' \
https://{{host}}/1.1/users

As mentioned above, username and password are required. password will be stored in encrypted form, and LeanCloud will never return its value to the client side.

You may add any extra custom attributes. region in the above is just an example.

If the registration succeed, LeanCloud will return 201 Created and the Location will contain the URL for that user:

Status: 201 Created
Location: https://{{host}}/1.1/users/55a47496e4b05001a7732c5f

The response body is a JSON object containing three attributes:

{
"sessionToken":"qmdj8pdidnmyzp0c7yqil91oc",
"createdAt":"2015-07-14T02:31:50.100Z",
"objectId":"55a47496e4b05001a7732c5f"
}

sessionToken can be used to authenticate subsequent requests as that user. It never changes, unless:

  • the user forgets the password and resets it via email;
  • the user modifies the password, and the developer enabled "Log out the user when password is updated" in dashboard;
  • the refreshSessionToken API is invoked.

Logged in users will encounter a 403 Forbidden permission error when invoking related APIs after the sessionToken refreshed.

LeanCloud can verify a user's email address automatically. To enable this feature, access "Dashboard > LeanStorage > User > Setting", and select "Send verification emails when users register or change email addresses from clients".

The emailVerified of _User will be set to true once the new user clicked the verification link in the email.

You can also enable "Do not allow users with unverified phone numbers to log in" in the dashboard.

Logging In

To log in a user with username and password:

curl -X POST \
-H "Content-Type: application/json" \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-d '{"username":"hjiang","password":"f32@ds*@&dsa"}' \
https://{{host}}/1.1/login

The response body is a JSON object containing all the attributes of that user, except password:

{
"sessionToken":"qmdj8pdidnmyzp0c7yqil91oc",
"updatedAt":"2015-07-14T02:31:50.100Z",
"phone":"18612340000",
"objectId":"55a47496e4b05001a7732c5f",
"username":"hjiang",
"createdAt":"2015-07-14T02:31:50.100Z",
"emailVerified":false,
"mobilePhoneVerified":false
}

To log in a user with email and password, just replace username with email:

{"email":"hjiang@example.com","password":"f32@ds*@&dsa"}

Similarly, replace username with mobilePhoneNumber to log in a user with mobile phone and password:

{"mobilePhoneNumber":"+1xxxxxxxxxx","password":"f32@ds*@&dsa"}

LeanCloud also supports signing up or logging in a user via SMS. Please refer to the SMS REST API Guide for details.

Refresh sessionToken

To refresh a user's sessionToken:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: qmdj8pdidnmyzp0c7yqil91oc" \
https://{{host}}/1.1/users/57e3bcca67f35600577c3063/refreshSessionToken

X-LC-Session can be omitted when using Master Key.

If succeed, new sessionToken will be returned, with user information:

{
"sessionToken":"5frlikqlwzx1nh3wzsdtfr4q7",
"updatedAt":"2016-10-20T03:10:57.926Z",
"objectId":"57e3bcca67f35600577c3063",
"username":"leancloud",
"createdAt":"2016-09-22T11:13:14.842Z",
"emailVerified":false,
"mobilePhoneVerified":false
}

Locking Users

Seven consecutive failed login attempts for a user within 15 minutes will trigger a lock. After that, LeanCloud will return the following error:

{
"code":219,
"error":"Tried too many times to signin."
}

LeanCloud will release this lock automatically in 15 minutes after the last login failure. Developers cannot adjust this behavior via SDK or REST API. During the locking period, the user is not allowed to log in, even if they provide the correct password. This restriction also applies to SDK and LeanEngine.

Verifying Email Address

As mentioned above, once a user clicked the verification link in the email, their emailVerified will be set to true.

emailVerified is a Boolean:

  1. true: the user has verified their email address via clicking the link in the verification mail.
  2. false: when a user's email attribute is set or modified, LeanCloud will set their emailVerified to false and send a verification email to the user. After the user clicks the verification link in the email, LeanCloud will set emailVerified to true.
  3. null: The user does not have an email, or the user object is created when the verifying new user's email address option is disabled.

The verification link expires in one week. To resend the verification email:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"email":"hang@leancloud.rocks"}' \
https://{{host}}/1.1/requestEmailVerify

Resetting a Password

A user can reset their password via email:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"email":"hang@leancloud.rocks"}' \
https://{{host}}/1.1/requestPasswordReset

If succeed, the response body will be an empty JSON object:

{}

Retrieving Users

To retrieve a user, you can send a GET request to the user URL (as in the Location header returned on successful signing up).

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/users/55a47496e4b05001a7732c5f

Alternatively, you can retrieve a user via their sessionToken:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: qmdj8pdidnmyzp0c7yqil91oc" \
https://{{host}}/1.1/users/me

The returned JSON object is the same as in /login.

If the user does not exist, a 400 Bad Request will be returned:

{
"code": 211,
"error": "Could not find user."
}

Updating Users

Similar to Updating Objects, you can send a PUT request to the user URL to update a user's data.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: qmdj8pdidnmyzp0c7yqil91oc" \
-H "Content-Type: application/json" \
-d '{"phone":"18600001234"}' \
https://{{host}}/1.1/users/55a47496e4b05001a7732c5f

The X-LC-Session HTTP header is to authenticate the modification, whose value is the user's sessionToken.

If succeed, updatedAt will be returned. This is the same as Updating Objects.

If you want to update username, then you have to ensure that the new value of username must not conflict with other existing users.

If you want to update password after verifying the old password, then you can use PUT /1.1/users/:objectId/updatePassword instead.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: qmdj8pdidnmyzp0c7yqil91oc" \
-H "Content-Type: application/json" \
-d '{"old_password":"the_old_password", "new_password":"the_new_password"}' \
https://{{host}}/1.1/users/55a47496e4b05001a7732c5f/updatePassword

Note this API still requires the X-LC-Session header.

Querying Users

You can query users like how you query regular objects by sending GET requests to /1.1/users.

However, for security concerns, all queries on users will be rejected by LeanCloud unless you use master key or have properly configured the _User class's ACL settings (in Dashboard > LeanStorage > _User > Permission).

Deleting Users

Just like delete an object, send a DELETE request to delete a user.

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: qmdj8pdidnmyzp0c7yqil91oc" \
https://{{host}}/1.1/users/55a47496e4b05001a7732c5f

The X-LC-Session HTTP header is used for authenticating this request.

Linking Users

To allow users to use third-party accounts to log in to your application, you can use the authData attribute of users.

authData is a JSON object whose schema may be different for different services.

The simplest form of authData is as follows:

{
"anonymous": {
"id": "random UUID with lowercase hexadecimal digits"
// other optional keys
}
}

This is used for anonymous users, for example, to provide a "try it before signing up" or "guest login" feature for your application.

The authData for an arbitrary platform:

{
"platform_name":
{
"uid": "unique user id on that platform (string)",
"access_token": "access token for the user"
// other optional keys
}
}

authData can have other additional keys, but it must contain both uid and access_token. LeanCloud will automatically create a unique index for authData.platform_name.uid. This avoids binding a third-party account to multiple users. However, you need to verify authData yourself (except for certain platforms, see below).

LeanCloud has built-in support for Apple and some popular social networks in China (Weibo, WeChat (weixin in Chinese pinyin), and QQ).

{
"authData": {
"lc_apple": {
"uid": "user identifier",
"identity_token": "identity token",
"code": "authorization code"
}
}
}

{
"authData": {
"weibo": {
"uid": "123456789",
"access_token": "2.00vs3XtCI5FevCff4981adb5jj1lXE",
"expiration_in": "36000"
}
}
}

{
"authData": {
"weixin": {
"openid": "0395BA18A5CD6255E5BA185E7BEBA242",
"access_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
"expires_in": 1382686496
}
}
}

{
"authData": {
"qq": {
"openid": "0395BA18A5CD6255E5BA185E7BEBA242",
"access_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
"expires_in": 1382686496
}
}
}

LeanCloud will automatically verify access token for these platforms and will also create a unique index for each of these platforms.

In Weibo, WeChat, and QQ, a user's openid will be different for different applications. If you have multiple applications, you may want to link them across all your applications. To fulfill this requirement, you can utilize the UnionID function offered by Weibo, WeChat, and QQ. For details, see the UnionID section below.

Third-Party Signing Up and Login

To sign up or log in via a third party account, you also send a POST request with the authData. For example, to use a QQ account to login:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"authData": {
"qq": {
"openid": "0395BA18A5CD6255E5BA185E7BEBA242",
"access_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
"expires_in": 1382686496
}
}
}' \
https://{{host}}/1.1/users

As mentioned above, LeanCloud will verify access_token for QQ accounts. If the verification succeeds, LeanCloud will return 200 OK or 201 Created depending on if there is an existing user linking this QQ account. In both cases, the user URL will also be returned in the Location HTTP header.

The response body will be a JSON object whose content is similar to the one returned when creating or logging in a regular user. For new users, LeanCloud will automatically assign a random username, e.g., ec9m07bo32cko6soqtvn6bko5.

UnionID

As mentioned above, we can utilize the UnionID mechanism offered by Weibo, WeChat, and QQ to link users across multiple applications.

To do so, you need to use a specific schema of authData, with the following keys:

  • unionid: the user's UnionID;
  • main_account: true indicates the current authentication information will be used as the main account;
  • platform: the platform of the UnionID, whose name can be specified by the developer, such as weibo, weixin, qq, and so on.

Let's look at an example of WeChat UnionID.

Suppose you have a WeChat mini program named foo. Then to sign up or log in a user with UnionID:

curl -X POST \
-H "X-LC-Id: zbOycL3cTIr3gOTgFAyQYiop-gzGzoHsz" \
-H "X-LC-Key: pp4T5TmSR8mscQONix0xFXpT" \
-H "Content-Type: application/json" \
-d '{
"authData": {
"foo": {
"openid": "oTY851cqL0gk3DqW3xINqG1Q4PTc",
"access_token": "12_b6mz7ujXbTY4vpbqCRaKVa_y0Ij3N9grCeVtM8VJT8KFd4qnQ9lXtBsZVxG6x9c9Nay_oNgvbKK7KYKbn8R2P7uEgA0EhsXMHmxkx-xU-Tk",
"expires_in": 7200,
"refresh_token": "12_71UYUnqHDuIfekimsJsYjBDfY67ilo30fDqrYkqlwZtxNgcBhMmQgDVhT6mJWkRg0mngvX9kXeCGP8kmBWdvUtc5ngRiN5LDTWAau4du838",
"scope": "snsapi_userinfo",
"unionid": "ox7NLs-e-32ZyHg2URi_F2iPEI2U",
"platform": "weixin",
"main_account":"true"
}
}
}' \
https://{{host}}/1.1/users

And to sign up or log in a user for your another WeChat mini program bar:

curl -X POST \
-H "X-LC-Id: zbOycL3cTIr3gOTgFAyQYiop-gzGzoHsz" \
-H "X-LC-Key: pp4T5TmSR8mscQONix0xFXpT" \
-H "Content-Type: application/json" \
-d '{
"authData": {
"bar": {
"openid": "ohxoK3ldpsGDGGSaniEEexxx",
"access_token": "10_QfDeXVp8fUKMBYC_d4PKujpuLo3sBV_pxxxxIZivS77JojQPLrZ7OgP9PC9ZvFCXxIa9G6BcBn45wSBebsv9Pih7Xdr4-hzr5hYpUoSA",
"unionid": "ox7NLs06ZGfdxxxxxe0F1po78qE",
"expires_in": 7200,
"refresh_token": "10_RZXedP8Ia9G6B_Xxoxjxpu1o4DBV_hzr5hYpUoSAd87JojQPLrZ7OgP10e9ZvFCXxcon54wSfaero_CBebsd20h5ddr3-4PKuIZivS",
"scope": "snsapi_userinfo",
"unionid": "ox7NLs-e-32ZyHg2URi_F2iPEI2U",
"platform": "weixin",
"main_account":"true"
}
}
}' \
https://{{host}}/1.1/users

Note that openid is different but unionid is the same.

And the authData stored on LeanCloud will be something like:

{
"foo": {
// ...
},
"_weixin_unionid": {
"uid": "ox7NLs-e-32ZyHg2URi_F2iPEI2U"
},
"bar": {
// ...
}
}

The _weixin_unionid key is automatically created by LeanCloud based on the value of the platform parameter (weixin in this example).

Linking a Third-Party Account

To link a third-party account to an existing user, just update this user's authData attribute.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: qmdj8pdidnmyzp0c7yqil91oc" \
-H "Content-Type: application/json" \
-d '{
"authData": {
"weixin": {
"uid": "123456789",
"access_token": "2.00vs3XtCI5FevCff4981adb5jj1lXE",
"expiration_in": "36000"
// ...
}
}
}' \
https://{{host}}/1.1/users/55a47496e4b05001a7732c5f

This user can be authenticated via matching authData afterward.

Unlinking a Third-Party Account

Similarly, to unlink a user from a third party account, just delete the platform in their authData attribute.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: 6fehqhr2t2na5mv1aq2om7jgz" \
-H "Content-Type: application/json" \
-d '{"authData.weixin":{"__op":"Delete"}}' \
https://{{host}}/1.1/users/5b7e53a767f356005fb374f6

Roles

LeanCloud has a preserved class _Role for roles.

For security concerns, roles are typically created and managed manually or via a separate management interface, not directly in your applications.

Creating Roles

Creating a role is similar to creating an object, except that you must specify the name and ACL attributes. To prevent allowing wrong users to modify a role accidentally, you should set a restrictive and rigid ACL.

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"name": "Manager",
"ACL": {
"*": {
"read": true
}
}
}' \
https://{{host}}/1.1/roles

The response is the same as creating an object.

To create a role with existing child roles and users:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"name": "CLevel",
"ACL": {
"*": {
"read": true
}
},
"roles": {
"__op": "AddRelation",
"objects": [
{
"__type": "Pointer",
"className": "_Role",
"objectId": "55a48351e4b05001a774a89f"
}
]
},
"users": {
"__op": "AddRelation",
"objects": [
{
"__type": "Pointer",
"className": "_User",
"objectId": "55a47496e4b05001a7732c5f"
}
]
}
}' \
https://{{host}}/1.1/roles

You may have noticed that there is a new operator AddRelation we have not seen before. This operator adds a Relation to an object. The actual implementation of Relation is quite complicated for performance issues, but conceptually you can consider a Relation as an array of pointers, and they are only used in roles.

Retrieving Roles

Retrieving a role is similar to retrieving an object:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/roles/55a483f0e4b05001a774b837

The response body will be a JSON object:

{
"name":"CLevel",
"createdAt":"2015-07-14T03:37:20.992Z",
"updatedAt":"2015-07-14T03:37:20.994Z",
"objectId":"55a483f0e4b05001a774b837",
"users":{
"__type":"Relation",
"className":"_User"
},
"roles":{
"__type":"Relation",
"className":"_Role"
}
}

Querying Roles

To find the roles a user belongs to:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'where={"users": {"__type": "Pointer", "className": "_User", "objectId": "5e03100ed4b56c008e4a91dc"}}' \
https://{{host}}/1.1/roles

To find the users contained in a role (users contained in sub-roles not counted):

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode '"$relatedTo":{"object":{"__type":"Pointer","className":"_Role","objectId":"5f3dea7b7a53400006b13886"},"key":"users"}' \
https://{{host}}/1.1/users

You can also query roles based on other attributes, just like querying a normal object.

Updating Roles

Updating roles are similar to update objects, except that name cannot be modified, as mentioned above. To add or remove users and child roles, you can use AddRelation and RemoveRelation operators.

Suppose we have a Manager role with objectId 55a48351e4b05001a774a89f, we can add a user to it as below:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"users": {
"__op": "AddRelation",
"objects": [
{
"__type": "Pointer",
"className": "_User",
"objectId": "55a4800fe4b05001a7745c41"
}
]
}
}' \
https://{{host}}/1.1/roles/55a48351e4b05001a774a89f

Similarly, to remove a child role:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"roles": {
"__op": "RemoveRelation",
"objects": [
{
"__type": "Pointer",
"className": "_Role",
"objectId": "55a483f0e4b05001a774b837"
}
]
}
}' \
https://{{host}}/1.1/roles/55a48351e4b05001a774a89f

Deleting Roles

Deleting roles are similar to delete objects. It is authenticated with the X-LC-Session HTTP header. The session token passed in must belong to a user who has the permission to delete the specified role.

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: qmdj8pdidnmyzp0c7yqil91oc" \
https://{{host}}/1.1/roles/55a483f0e4b05001a774b837

Roles and ACL

As demonstrated above, accessing LeanCloud data via REST API is also restricted by ACL, just as SDKs.

Roles make maintaining ACL easier. For example, to set an ACL of an object with the following permissions:

  • It can be read by Staffs.
  • It can only be written by Managers and its creator.
{
"55a4800fe4b05001a7745c41": {
"write": true
},
"role:Staff": {
"read": true
},
"role:Manager": {
"write": true
}
}

The creator belongs to the Staff role, and the Manager role is a child role of the Staff role. Therefore, since they will inherit read permissions, we did not grant them the read permission manually.

Let's look at another example of permission inherence among roles. In UGC applications such as forums, Administrators typically have all the permissions of Moderators. Thus Administrators should be a sub-role of Moderators.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"roles": {
"__op": "AddRelation",
"objects": [
{
"__type": "Pointer",
"className": "_Role",
"objectId": "<AdministratorsRoleObjectId>"
}
]
}
}' \
https://{{host}}/1.1/roles/<ModeratorsRoleObjectId>

Files

Associating with Objects

As mentioned above, files can be considered as a special form of pointers. To associate a file object with an object, we just pass the file object {"id": "objectId of the file", "__type": "File"} to an attribute of that file. For example, to create a Staff object with a photo:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"name": "hjiang",
"picture": {
"id": "543cbaede4b07db196f50f3c",
"__type": "File"
}
}' \
https://{{host}}/1.1/classes/Staff

Deleting Files

Deleting files is similar to deleting objects:

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/files/543cbaede4b07db196f50f3c

Schema

You can use REST API to fetch the data schema of your application. For security concerns, master key is required to fetch data schema.

To fetch the schema of all classes:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/schemas

Result:

{
"_User":{
"username" : {"type":"String"},
"password" : {"type":"String"},
"objectId" : {"type":"String"},
"emailVerified": {"type":"Boolean"},
"email" : {"type":"String"},
"createdAt" : {"type":"Date"},
"updatedAt" : {"type":"Date"},
"authData" : {"type":"Object"}
}
// other classes
}

You can also fetch a single class's schema:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/schemas/_User

Data schema can be used with tools such as code generators and internal management interfaces.

Exporting Your Data

For security concerns, master key is required to export your data:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{}' \
https://{{host}}/1.1/exportData

To specify date range (updatedAt) of data to export:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"from_date":"2015-09-20", "to_date":"2015-09-25"}' \
https://{{host}}/1.1/exportData

To specify classes of data to export:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"classes":"_User,GameScore,Post"}' \
https://{{host}}/1.1/exportData

Just export the schema (no data will be exported):

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"only-schema":"true"}' \
https://{{host}}/1.1/exportData

Exported schema file can be imported into other applications via the import data function in dashboard.

After the data exported, LeanCloud will send an email to the application creator, containing the url to download the data. You can also specify the address to receive this email:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"email":"username@exmaple.com"}' \
https://{{host}}/1.1/exportData

The export data job id will be returned:

{
"status":"running",
"id":"1wugzx81LvS5R4RHsuaeMPKlJqFMFyLwYDNcx6LvCc6MEzQ2",
"app_id":"{{appid}}"
}

You can also query the export data job status via the id returned previously:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/exportData/1wugzx81LvS5R4RHsuaeMPKlJqFMFyLwYDNcx6LvCc6MEzQ2

If the job status is done, the download url will also be returned:

{
"status":"done",
"download_url": "https://download.leancloud.cn/export/example.tar.gz",
"id":"1wugzx81LvS5R4RHsuaeMPKlJqFMFyLwYDNcx6LvCc6MEzQ2",
"app_id":"{{appid}}"
}

If the job status is still running, you can query it again later.

Other

Server Time

To retrieve LeanCloud server's current time:

curl -i -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/date

Returned date is in UTC:

{
"iso": "2015-08-27T07:38:33.643Z",
"__type": "Date"
}

CORS Workarounds

LeanCloud supports wrapping GET, PUT, and DELETE requests in a POST request:

  • Specify the intended HTTP method in the _method parameter.
  • Specify appid and appkey in _ApplicationId and _ApplicationKey parameters.

This is a workaround for certain platforms. It is recommended to follow HTML CORS standard instead.

GET

  curl -i -X POST \
-H "Content-Type: text/plain" \
-d \
'{"_method":"GET",
"_ApplicationId":"{{appid}}",
"_ApplicationKey":"{{appkey}}"}' \
https://{{host}}/1.1/classes/Post/<objectId>

PUT

curl -i -X POST \
-H "Content-Type: text/plain" \
-d \
'{"_method":"PUT",
"_ApplicationId":"{{appid}}",
"_ApplicationKey":"{{appkey}}",
"upvotes":99}' \
https://{{host}}/1.1/classes/Post/<objectId>

DELETE

curl -i -X POST \
-H "Content-Type: text/plain" \
-d \
'{"_method": "DELETE",
"_ApplicationId":"{{appid}}",
"_ApplicationKey":"{{appkey}}"}' \
https://{{host}}/1.1/classes/Post/<objectId>