-
-
Notifications
You must be signed in to change notification settings - Fork 514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: add defined schema docs #863
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Class Level Permissions | ||
|
||
Setting Class level permissions through Defined Schema is a good first step into security systems available on Parse Server. | ||
|
||
## CLP Keys | ||
|
||
These CLP keys are available: | ||
|
||
- `find`: Control search permissions | ||
- `get`: Control direct ID get permission | ||
- `count`: Control counting objects permission | ||
- `create`: Create permission | ||
- `update`: Update permission | ||
- `delete`: Delete permission | ||
- `protectedFields`: Control get permission at field level | ||
|
||
You can set each CLP field with options to add a first strong security layer. This security layer will be applied on the Parse Class and all Parse Objects into this class. | ||
|
||
Note: If you update CLP you do not need to update Parse Objects. CLP is a security layer at Class Level not Object Level. For Object Level permission you can take a look to ALCs. You can use CLPs combined to ACLs to deeply secure your Parse Server. | ||
|
||
## CLP Key Options | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest replacing globally Currently |
||
|
||
Available options for CLP keys: | ||
|
||
- `role:MyRole`: If you have already created a Parse Role, you can use your created Parse Role (ie: `MyRole`) in CLP keys. | ||
- `requiresAuthentication`: If true an authenticated user will have the permission. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "If set to `true`, only authenticated users" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "If set to `true`, only authenticated users" |
||
- `*`: Everybody has the permission | ||
- `{}`: if you set the CLP key with `{}` like `create: {}` only calls with your Parse Server Master Key will have the permission | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "`role:<roleName>`: If you are making use of Parse Roles you can set the permission based on a role." |
||
|
||
## CLP Protected Fields Key | ||
|
||
This CLP key is powerful and need some additional explanation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this line can be removed, it doesn't seem to provide any relevant info. Maybe instead a sentence about what this is (used for). |
||
We will take the Parse User class as example. | ||
|
||
```js | ||
{ | ||
protectedFields: { | ||
"*": ["authData", "emailVerified", "password", "username"], | ||
}, | ||
} | ||
``` | ||
|
||
Listed keys under `*` will be protected from all users. Don't worry by default, `authData`, `emailVerified`, `password` are protected. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove "don't worry" |
||
But here for example we protect `username` from all users. So user A, even authenticated will not be able to get the `username` of a user B. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is "here"? There is an example before and one after. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The references "user A", "user B" seem to not be used anywhere else? If so, just simplify this to something like "a user cannot ... of other users". |
||
|
||
But protected fields could be combined for example. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make this is clear reference, like: "Protected fields ... as in this example:" |
||
|
||
```js | ||
{ | ||
protectedFields: { | ||
"*": ["authData", "emailVerified", "password", "username", "phone", "score"], | ||
"role:Admin": ["password", "authData", "emailVerified"], | ||
"role:VerifiedUser": ["password", "authData", "emailVerified", "score"], | ||
}, | ||
} | ||
``` | ||
|
||
In this case, a user member of the Parse Role `Admin` will be able to get the `phone` and `score` of another User. A user member of the Parse Role `VerifiedUser` can only get `phone`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In which case, the example above? |
||
If a user is member of `VerifiedUser` and `Admin`, he will have access to `phone` and `score`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# Core Classes/Fields | ||
|
||
Parse will never delete these fields on **ALL** classes if not provided in a class schema | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "will never delete the following fields from any class, even if these fields are not defined in a class schema" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. still open |
||
|
||
- `objectId` | ||
- `createdAt` | ||
- `updatedAt` | ||
- `ACL` | ||
|
||
Parse will never delete these classes/fields if not provided in `schema` option. | ||
|
||
- `_User` | ||
|
||
- `username` | ||
- `password` | ||
- `email` | ||
- `emailVerified` | ||
- `authData` | ||
|
||
- `_Installation` | ||
|
||
- `installationId` | ||
- `deviceToken` | ||
- `channels` | ||
- `deviceType` | ||
- `pushType` | ||
- `GCMSenderId` | ||
- `timeZone` | ||
- `localeIdentifier` | ||
- `badge` | ||
- `appVersion` | ||
- `appName` | ||
- `appIdentifier` | ||
- `parseVersion` | ||
|
||
- `_Role` | ||
|
||
- `name` | ||
- `users` | ||
- `roles` | ||
|
||
- `_Session` | ||
|
||
- `user` | ||
- `installationId` | ||
- `sessionToken` | ||
- `expiresAt` | ||
- `createdWith` | ||
|
||
- `_Product` | ||
|
||
- `productIdentifier` | ||
- `download` | ||
- `downloadName` | ||
- `icon` | ||
- `order` | ||
- `title` | ||
- `subtitle` | ||
|
||
- `_PushStatus` | ||
|
||
- `pushTime` | ||
- `source` | ||
- `query` | ||
- `payload` | ||
- `title` | ||
- `expiry` | ||
- `expiration_interval` | ||
- `status` | ||
- `numSent` | ||
- `numFailed` | ||
- `pushHash` | ||
- `errorMessage` | ||
- `sentPerType` | ||
- `failedPerType` | ||
- `sentPerUTCOffset` | ||
- `failedPerUTCOffset` | ||
- `count` | ||
|
||
- `_JobStatus` | ||
|
||
- `jobName` | ||
- `source` | ||
- `status` | ||
- `message` | ||
- `params` | ||
- `finishedAt` | ||
|
||
- `_JobSchedule` | ||
|
||
- `jobName` | ||
- `description` | ||
- `params` | ||
- `startAfter` | ||
- `daysOfWeek` | ||
- `timeOfDay` | ||
- `lastRun` | ||
- `repeatMinutes` | ||
|
||
- `_Audience` | ||
- `objectId` | ||
- `name` | ||
- `query` | ||
- `lastUsed` | ||
- `timesUsed` | ||
- `_Idempotency` | ||
- `reqId` | ||
- `expire` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Fields | ||
|
||
You can find here all field types available on Parse | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "These field types are available..." |
||
|
||
- `Number`: this type support `required` and `defaultValue` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe male this a table? Or at least remove the repetitive terms. |
||
- `String`: this type support `required` and `defaultValue` | ||
- `Boolean`: this type support `required` and `defaultValue` | ||
- `Date`: this type support `required` and `defaultValue` | ||
- `Object`: this type support `required` and `defaultValue` | ||
- `Array`: this type support `required` and `defaultValue` | ||
- `GeoPoint`: this type support `required` | ||
- `File`: this type support `required` | ||
- `Bytes`: this type support `required` | ||
- `Polygon`: this type support `required` | ||
- `Relation`: You need to provide `targetClass` | ||
- `Pointer`: You need to provide `targetClass`, this type support `required` | ||
|
||
Example: | ||
|
||
```js | ||
const UserSchema = { | ||
className: "_User", | ||
fields: { | ||
birthDate: { type: "Date" }, | ||
firstname: { type: "String", required: true }, | ||
lastname: { type: "String", required: true }, | ||
tags: { type: "Array" }, | ||
location: { type: "GeoPoint" }, | ||
city: { type: "Pointer", targetClass: "City" }, | ||
friends: { type: "Relation", targetClass: "_User" }, | ||
zone: { type: "Polygon" }, | ||
}, | ||
}; | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# Getting Started | ||
|
||
## Introduction | ||
|
||
Parse Server was historically designed to be a schema less system. You didn't have to perform migration and define specific database schemas at start up time. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "schemaless", "start-up" Remove "historically", it's confusing (is it still today designed that way?). Instead: |
||
But schema less do not fulfill each use case of developers and could also do not play very well with some new Parse Server features like the GraphQL API. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the 2 prose paragraphs, instead simplify to the facts: "For use cases in which a pre-defined schema is beneficial or required, you can define class fields, indexes, Class Level Permissions and more." |
||
|
||
To meet these needs, Parse Server now introduce Defined Schemas feature. | ||
Define easily you Parse Classes fields, indexes, Class level permissions and more. | ||
|
||
## Quick Start | ||
|
||
To leverage the power of Defined Schema we recommend to setup parse user like an express app. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rephrase this, is it required or why do we "recommend"? |
||
|
||
```js | ||
const { ParseServer } = require("parse-server"); | ||
|
||
const UserSchema = { | ||
className: "_User", | ||
fields: { | ||
birthDate: { type: "Date" }, | ||
firstname: { type: "String", required: true }, | ||
lastname: { type: "String", required: true }, | ||
tags: { type: "Array" }, | ||
location: { type: "GeoPoint" }, | ||
city: { type: "Pointer", targetClass: "City" }, | ||
friends: { type: "Relation", targetClass: "_User" }, | ||
zone: { type: "Polygon" }, | ||
}, | ||
indexes: { | ||
tagsIndex: { tags: 1 }, | ||
// Special _p_ word to create indexes on pointer fields | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "// The special prefix _p_ is used to create indexes on pointer fields" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "// Special p prefix" |
||
cityPointerIndex: { _p_city: 1 }, | ||
tagAndCityIndex: { _p_city: 1, tags: 1 }, | ||
}, | ||
classLevelPermissions: { | ||
find: { requiresAuthentication: true }, | ||
count: { "role:Admin": true }, | ||
get: { requiresAuthentication: true }, | ||
update: { requiresAuthentication: true }, | ||
create: { "role:Admin": true }, | ||
delete: { "role:Admin": true }, | ||
protectedFields: { | ||
// These fields will be protected from all other users | ||
// authData, and password are already protected by default | ||
"*": ["authData", "emailVerified", "password", "username"], | ||
}, | ||
}, | ||
}; | ||
|
||
const City = { | ||
className: "City", | ||
fields: { | ||
name: { type: "String", required: true }, | ||
location: { type: "GeoPoint" }, | ||
country: { type: "Pointer", targetClass: "Country" }, | ||
}, | ||
classLevelPermissions: { | ||
find: { requiresAuthentication: true }, | ||
count: { requiresAuthentication: true }, | ||
get: { requiresAuthentication: true }, | ||
// Only a user linked into the Admin Parse Role | ||
// authorized to manage cities | ||
update: { "role:Admin": true }, | ||
create: { "role:Admin": true }, | ||
delete: { "role:Admin": true }, | ||
}, | ||
}; | ||
|
||
const Country = { | ||
className: "Country", | ||
fields: { | ||
name: { type: "String", required: true }, | ||
}, | ||
classLevelPermissions: { | ||
find: { requiresAuthentication: true }, | ||
count: { requiresAuthentication: true }, | ||
get: { requiresAuthentication: true }, | ||
// Empty object meas that only master key | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. write comment on 1 line instead of 2 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. write comment on 1 line instead of 2 |
||
// is authorized to manage countries | ||
update: {}, | ||
create: {}, | ||
delete: {}, | ||
}, | ||
}; | ||
|
||
ParseServer.start({ | ||
databaseURI: "mongodb://your.mongo.uri", | ||
appId: "myAppId", | ||
masterKey: "mySecretMasterKey", | ||
serverURL: "http://localhost:1337/parse", | ||
port: 1337, | ||
publicServerURL: "http://localhost:1337/parse", | ||
// Then just register schemas into Parse Server | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // Define schemas of Parse Server There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // Define schemas of Parse Server |
||
schema: { | ||
definitions: [User, City, Country], | ||
// Parse Schema API will be disabled | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // Disable Parse Schema API; if you need to update the schemas later There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // If set to `true`, the Parse Server API for schema changes is disabled and schema |
||
// If you need to update schemas Parse server | ||
// need to be updated and deployed (CI/CD strategy) | ||
lockSchemas: true, | ||
// If true, Parse Server will delete non defined Classes from | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // If set to `true`, Parse Server will automatically delete non-defined classes from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // Parse Server will automatically delete non-defined classes from the |
||
// the database. (Core classes like Role, User are never deleted) | ||
strict: true, | ||
// If true, a field type change, the changed field is deleted | ||
// from the database (all data in this field will be deleted) | ||
// and then create the field with the new type | ||
recreateModifiedFields: true, | ||
// If true, Parse will delete non defined fields on a class. (Core fields are never deleted) | ||
deleteExtraFields: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Theses 2 parameters should be |
||
}, | ||
serverStartComplete: () => { | ||
// Here your Parse Server is ready | ||
// with schemas up to date | ||
|
||
// Just a code example if you want to expose | ||
// an endpoint when parse is fully initialized | ||
parseServer.expressApp.get("/ready", (req: any, res: any) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // Parse Server is ready with up-to-date schema There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace whole comment block with: // Parse Server is ready with up-to-date schema |
||
res.send("true"); | ||
}); | ||
}, | ||
}); | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Indexes | ||
|
||
To optimize you Parse Server database performance you can define indexes and compound indexes. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "To optimize the Parse Server performance..." |
||
|
||
To define an index on a `Pointer` field you need to use a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reformat and reword to: To optimize the Parse Server performance you can define indexes and compound indexes. Parse Server does not support indexes on special To define an index on a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reformat and reword to: To optimize the Parse Server performance you can define indexes and compound indexes. Parse Server does not support indexes on special To define an index on a |
||
special notation `_p_myFieldName`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
For example if you define `city: { type: "Pointer", targetClass: "City" }` in your `fields` you can define an index on this pointer with `cityIndexExample: { _p_city: true }` | ||
|
||
Note: Currently Defined Schemas do not support indexes on special `_Join` classes used under the hood by the `Relation` type | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dot at end |
||
|
||
Example: | ||
|
||
```js | ||
const UserSchema = { | ||
className: "_User", | ||
fields: { | ||
tags: { type: "Array" }, | ||
city: { type: "Pointer", targetClass: "City" }, | ||
}, | ||
indexes: { | ||
tagsIndex: { tags: 1 }, | ||
cityPointerIndex: { _p_city: 1 }, | ||
tagAndCityIndex: { _p_city: 1, tags: 1 }, | ||
}, | ||
}; | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Options | ||
|
||
## definitions | ||
|
||
You classes definitions stored in an `Array`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you rephrase this? |
||
|
||
## strict | ||
|
||
You can set the `strict` option to `true` if you want parse-server to delete removed classes from your schemas from your database. Data stored in removed classes will be lost. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Parse Server" Could you rephrase "from your schemas from your database", may be confusing |
||
|
||
`strict` is default to `false`. If you often change your schemas be aware that you can have some stale classes in your database. You will need to delete these classes manually. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "By default "You can have stale..." sounds like it's permissible. I think you want to say that the stale classes are unwanted and may remain? |
||
|
||
## deleteExtraFields | ||
|
||
You can set the `deleteExtraFields` option to `true` if you parse-server to delete removed a class field from your database. Data stored in the removed field will be lost. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "if you want Parse Server to..." "Delete remove" - a typo? |
||
|
||
`deleteExtraFields` is default to `false`. Be aware that some stale fields could exists in your database. You will need to delete these fields manually. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here rephrasing |
||
|
||
## recreateModifiedFields | ||
|
||
You can set the `recreateModifiedFields` option to `true` if you parse-server to clean field data before parse-server update the field type when you change the type of a field (ie: from `String` to `Number`). Data stored on the modified field will be lost. | ||
|
||
`recreateModifiedFields` is default to `false`. Be aware that if you do not perform some data migration, you can result with data type inconsistency on modified field. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe adding some Bold for ? Be aware that if you do not perform some data migration |
||
|
||
On production a good practice could be to create a new field with your new type, and then create a Parse Cloud Job to migrate old field data to the new created field. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Good practice would be to create the new field of the new type" ... "to the newly created field." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Good practice would be to create a new field with a new type" ... "to the newly created field." |
||
|
||
## lockSchemas | ||
|
||
You can set the `lockSchemas` option to `true` if you want to to prevent any `Parse.Schema` manipulation outside of the Defined Schema feature. If this options is `true` any create/update/delete request to `Parse.Schema` will be denied. You will not be able to manipulate `indexes`, `classLevelPermissions`, `fields`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "if you want to prevent any schema manipulation and to lock the schema as defined in the Parse Server configuration." ... "any create, update and delete request will be denied by the Parse Server API, even with the master key." You can delete the following sentence "This option help to keep " as it does not provide any additional information. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "if you want to prevent any schema manipulation and to lock the schema as defined in the Parse Server configuration." |
||
|
||
This option help to keep one source of truth. And prevent developers or custom code to interfere with your schema definitions and data structure, even with the master key. | ||
|
||
## beforeMigration | ||
|
||
A function called before parse-server performs schema updates based on the `definitions` option | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Always use "Parse Server" when you refer to the product, don't use "parse-server" unless you are referring to the repository. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. still open There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. still open |
||
|
||
## afterMigration | ||
|
||
A function called after parse-server performed schema updates based on the `definitions` option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"into this class"? Do you mean sub classes?