parse-server 2.8.4 → 8.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/LICENSE +167 -25
  2. package/NOTICE +10 -0
  3. package/README.md +929 -278
  4. package/lib/AccountLockout.js +47 -30
  5. package/lib/Adapters/AdapterLoader.js +21 -6
  6. package/lib/Adapters/Analytics/AnalyticsAdapter.js +15 -12
  7. package/lib/Adapters/Auth/AuthAdapter.js +116 -13
  8. package/lib/Adapters/Auth/BaseCodeAuthAdapter.js +99 -0
  9. package/lib/Adapters/Auth/OAuth1Client.js +27 -46
  10. package/lib/Adapters/Auth/apple.js +123 -0
  11. package/lib/Adapters/Auth/facebook.js +162 -35
  12. package/lib/Adapters/Auth/gcenter.js +217 -0
  13. package/lib/Adapters/Auth/github.js +118 -48
  14. package/lib/Adapters/Auth/google.js +160 -51
  15. package/lib/Adapters/Auth/gpgames.js +125 -0
  16. package/lib/Adapters/Auth/httpsRequest.js +6 -7
  17. package/lib/Adapters/Auth/index.js +170 -62
  18. package/lib/Adapters/Auth/instagram.js +114 -40
  19. package/lib/Adapters/Auth/janraincapture.js +52 -23
  20. package/lib/Adapters/Auth/janrainengage.js +19 -36
  21. package/lib/Adapters/Auth/keycloak.js +148 -0
  22. package/lib/Adapters/Auth/ldap.js +167 -0
  23. package/lib/Adapters/Auth/line.js +125 -0
  24. package/lib/Adapters/Auth/linkedin.js +111 -55
  25. package/lib/Adapters/Auth/meetup.js +24 -34
  26. package/lib/Adapters/Auth/mfa.js +324 -0
  27. package/lib/Adapters/Auth/microsoft.js +111 -0
  28. package/lib/Adapters/Auth/oauth2.js +97 -162
  29. package/lib/Adapters/Auth/phantauth.js +53 -0
  30. package/lib/Adapters/Auth/qq.js +108 -49
  31. package/lib/Adapters/Auth/spotify.js +107 -55
  32. package/lib/Adapters/Auth/twitter.js +188 -48
  33. package/lib/Adapters/Auth/utils.js +28 -0
  34. package/lib/Adapters/Auth/vkontakte.js +26 -39
  35. package/lib/Adapters/Auth/wechat.js +106 -44
  36. package/lib/Adapters/Auth/weibo.js +132 -58
  37. package/lib/Adapters/Cache/CacheAdapter.js +13 -8
  38. package/lib/Adapters/Cache/InMemoryCache.js +3 -13
  39. package/lib/Adapters/Cache/InMemoryCacheAdapter.js +5 -13
  40. package/lib/Adapters/Cache/LRUCache.js +13 -27
  41. package/lib/Adapters/Cache/NullCacheAdapter.js +3 -8
  42. package/lib/Adapters/Cache/RedisCacheAdapter.js +85 -76
  43. package/lib/Adapters/Cache/SchemaCache.js +25 -0
  44. package/lib/Adapters/Email/MailAdapter.js +10 -8
  45. package/lib/Adapters/Files/FilesAdapter.js +83 -25
  46. package/lib/Adapters/Files/GridFSBucketAdapter.js +231 -0
  47. package/lib/Adapters/Files/GridStoreAdapter.js +4 -91
  48. package/lib/Adapters/Logger/LoggerAdapter.js +18 -14
  49. package/lib/Adapters/Logger/WinstonLogger.js +69 -88
  50. package/lib/Adapters/Logger/WinstonLoggerAdapter.js +7 -16
  51. package/lib/Adapters/MessageQueue/EventEmitterMQ.js +8 -26
  52. package/lib/Adapters/PubSub/EventEmitterPubSub.js +12 -25
  53. package/lib/Adapters/PubSub/PubSubAdapter.js +34 -0
  54. package/lib/Adapters/PubSub/RedisPubSub.js +42 -19
  55. package/lib/Adapters/Push/PushAdapter.js +14 -7
  56. package/lib/Adapters/Storage/Mongo/MongoCollection.js +137 -45
  57. package/lib/Adapters/Storage/Mongo/MongoSchemaCollection.js +158 -63
  58. package/lib/Adapters/Storage/Mongo/MongoStorageAdapter.js +320 -168
  59. package/lib/Adapters/Storage/Mongo/MongoTransform.js +279 -306
  60. package/lib/Adapters/Storage/Postgres/PostgresClient.js +14 -10
  61. package/lib/Adapters/Storage/Postgres/PostgresConfigParser.js +47 -21
  62. package/lib/Adapters/Storage/Postgres/PostgresStorageAdapter.js +854 -468
  63. package/lib/Adapters/Storage/Postgres/sql/index.js +4 -6
  64. package/lib/Adapters/Storage/StorageAdapter.js +1 -1
  65. package/lib/Adapters/WebSocketServer/WSAdapter.js +35 -0
  66. package/lib/Adapters/WebSocketServer/WSSAdapter.js +66 -0
  67. package/lib/Auth.js +488 -125
  68. package/lib/ClientSDK.js +2 -6
  69. package/lib/Config.js +525 -94
  70. package/lib/Controllers/AdaptableController.js +5 -25
  71. package/lib/Controllers/AnalyticsController.js +22 -23
  72. package/lib/Controllers/CacheController.js +10 -31
  73. package/lib/Controllers/DatabaseController.js +767 -313
  74. package/lib/Controllers/FilesController.js +49 -54
  75. package/lib/Controllers/HooksController.js +80 -84
  76. package/lib/Controllers/LiveQueryController.js +35 -22
  77. package/lib/Controllers/LoggerController.js +22 -58
  78. package/lib/Controllers/ParseGraphQLController.js +293 -0
  79. package/lib/Controllers/PushController.js +58 -49
  80. package/lib/Controllers/SchemaController.js +916 -422
  81. package/lib/Controllers/UserController.js +265 -180
  82. package/lib/Controllers/index.js +90 -125
  83. package/lib/Controllers/types.js +1 -1
  84. package/lib/Deprecator/Deprecations.js +30 -0
  85. package/lib/Deprecator/Deprecator.js +127 -0
  86. package/lib/Error.js +48 -0
  87. package/lib/GraphQL/ParseGraphQLSchema.js +375 -0
  88. package/lib/GraphQL/ParseGraphQLServer.js +214 -0
  89. package/lib/GraphQL/helpers/objectsMutations.js +30 -0
  90. package/lib/GraphQL/helpers/objectsQueries.js +246 -0
  91. package/lib/GraphQL/loaders/configMutations.js +87 -0
  92. package/lib/GraphQL/loaders/configQueries.js +79 -0
  93. package/lib/GraphQL/loaders/defaultGraphQLMutations.js +21 -0
  94. package/lib/GraphQL/loaders/defaultGraphQLQueries.js +23 -0
  95. package/lib/GraphQL/loaders/defaultGraphQLTypes.js +1098 -0
  96. package/lib/GraphQL/loaders/defaultRelaySchema.js +53 -0
  97. package/lib/GraphQL/loaders/filesMutations.js +107 -0
  98. package/lib/GraphQL/loaders/functionsMutations.js +78 -0
  99. package/lib/GraphQL/loaders/parseClassMutations.js +268 -0
  100. package/lib/GraphQL/loaders/parseClassQueries.js +127 -0
  101. package/lib/GraphQL/loaders/parseClassTypes.js +493 -0
  102. package/lib/GraphQL/loaders/schemaDirectives.js +62 -0
  103. package/lib/GraphQL/loaders/schemaMutations.js +162 -0
  104. package/lib/GraphQL/loaders/schemaQueries.js +81 -0
  105. package/lib/GraphQL/loaders/schemaTypes.js +341 -0
  106. package/lib/GraphQL/loaders/usersMutations.js +433 -0
  107. package/lib/GraphQL/loaders/usersQueries.js +90 -0
  108. package/lib/GraphQL/parseGraphQLUtils.js +63 -0
  109. package/lib/GraphQL/transformers/className.js +14 -0
  110. package/lib/GraphQL/transformers/constraintType.js +53 -0
  111. package/lib/GraphQL/transformers/inputType.js +51 -0
  112. package/lib/GraphQL/transformers/mutation.js +274 -0
  113. package/lib/GraphQL/transformers/outputType.js +51 -0
  114. package/lib/GraphQL/transformers/query.js +237 -0
  115. package/lib/GraphQL/transformers/schemaFields.js +99 -0
  116. package/lib/KeyPromiseQueue.js +48 -0
  117. package/lib/LiveQuery/Client.js +25 -33
  118. package/lib/LiveQuery/Id.js +2 -5
  119. package/lib/LiveQuery/ParseCloudCodePublisher.js +26 -23
  120. package/lib/LiveQuery/ParseLiveQueryServer.js +560 -285
  121. package/lib/LiveQuery/ParsePubSub.js +7 -16
  122. package/lib/LiveQuery/ParseWebSocketServer.js +42 -39
  123. package/lib/LiveQuery/QueryTools.js +76 -15
  124. package/lib/LiveQuery/RequestSchema.js +111 -97
  125. package/lib/LiveQuery/SessionTokenCache.js +23 -36
  126. package/lib/LiveQuery/Subscription.js +8 -17
  127. package/lib/LiveQuery/equalObjects.js +2 -3
  128. package/lib/Options/Definitions.js +1355 -382
  129. package/lib/Options/docs.js +301 -62
  130. package/lib/Options/index.js +11 -1
  131. package/lib/Options/parsers.js +14 -10
  132. package/lib/Page.js +44 -0
  133. package/lib/ParseMessageQueue.js +6 -13
  134. package/lib/ParseServer.js +474 -235
  135. package/lib/ParseServerRESTController.js +102 -40
  136. package/lib/PromiseRouter.js +39 -50
  137. package/lib/Push/PushQueue.js +24 -30
  138. package/lib/Push/PushWorker.js +32 -56
  139. package/lib/Push/utils.js +22 -35
  140. package/lib/RestQuery.js +361 -139
  141. package/lib/RestWrite.js +713 -344
  142. package/lib/Routers/AggregateRouter.js +97 -71
  143. package/lib/Routers/AnalyticsRouter.js +8 -14
  144. package/lib/Routers/AudiencesRouter.js +16 -35
  145. package/lib/Routers/ClassesRouter.js +86 -72
  146. package/lib/Routers/CloudCodeRouter.js +28 -37
  147. package/lib/Routers/FeaturesRouter.js +22 -25
  148. package/lib/Routers/FilesRouter.js +266 -171
  149. package/lib/Routers/FunctionsRouter.js +87 -103
  150. package/lib/Routers/GlobalConfigRouter.js +94 -33
  151. package/lib/Routers/GraphQLRouter.js +41 -0
  152. package/lib/Routers/HooksRouter.js +43 -47
  153. package/lib/Routers/IAPValidationRouter.js +57 -70
  154. package/lib/Routers/InstallationsRouter.js +17 -25
  155. package/lib/Routers/LogsRouter.js +10 -25
  156. package/lib/Routers/PagesRouter.js +647 -0
  157. package/lib/Routers/PublicAPIRouter.js +104 -112
  158. package/lib/Routers/PurgeRouter.js +19 -29
  159. package/lib/Routers/PushRouter.js +14 -28
  160. package/lib/Routers/RolesRouter.js +7 -14
  161. package/lib/Routers/SchemasRouter.js +63 -42
  162. package/lib/Routers/SecurityRouter.js +34 -0
  163. package/lib/Routers/SessionsRouter.js +25 -38
  164. package/lib/Routers/UsersRouter.js +463 -190
  165. package/lib/SchemaMigrations/DefinedSchemas.js +379 -0
  166. package/lib/SchemaMigrations/Migrations.js +30 -0
  167. package/lib/Security/Check.js +109 -0
  168. package/lib/Security/CheckGroup.js +44 -0
  169. package/lib/Security/CheckGroups/CheckGroupDatabase.js +44 -0
  170. package/lib/Security/CheckGroups/CheckGroupServerConfig.js +96 -0
  171. package/lib/Security/CheckGroups/CheckGroups.js +21 -0
  172. package/lib/Security/CheckRunner.js +213 -0
  173. package/lib/SharedRest.js +29 -0
  174. package/lib/StatusHandler.js +96 -93
  175. package/lib/TestUtils.js +70 -14
  176. package/lib/Utils.js +468 -0
  177. package/lib/batch.js +74 -40
  178. package/lib/cache.js +8 -8
  179. package/lib/cli/definitions/parse-live-query-server.js +4 -3
  180. package/lib/cli/definitions/parse-server.js +4 -3
  181. package/lib/cli/parse-live-query-server.js +9 -17
  182. package/lib/cli/parse-server.js +49 -47
  183. package/lib/cli/utils/commander.js +20 -29
  184. package/lib/cli/utils/runner.js +31 -32
  185. package/lib/cloud-code/Parse.Cloud.js +711 -36
  186. package/lib/cloud-code/Parse.Server.js +21 -0
  187. package/lib/cryptoUtils.js +6 -11
  188. package/lib/defaults.js +21 -15
  189. package/lib/deprecated.js +1 -1
  190. package/lib/index.js +78 -67
  191. package/lib/logger.js +12 -20
  192. package/lib/middlewares.js +484 -160
  193. package/lib/password.js +10 -6
  194. package/lib/request.js +175 -0
  195. package/lib/requiredParameter.js +4 -3
  196. package/lib/rest.js +157 -82
  197. package/lib/triggers.js +627 -185
  198. package/lib/vendor/README.md +3 -3
  199. package/lib/vendor/mongodbUrl.js +224 -137
  200. package/package.json +135 -57
  201. package/postinstall.js +38 -50
  202. package/public_html/invalid_verification_link.html +3 -3
  203. package/types/@types/@parse/fs-files-adapter/index.d.ts +5 -0
  204. package/types/@types/deepcopy/index.d.ts +5 -0
  205. package/types/LiveQuery/ParseLiveQueryServer.d.ts +40 -0
  206. package/types/Options/index.d.ts +301 -0
  207. package/types/ParseServer.d.ts +65 -0
  208. package/types/eslint.config.mjs +30 -0
  209. package/types/index.d.ts +21 -0
  210. package/types/logger.d.ts +2 -0
  211. package/types/tests.ts +44 -0
  212. package/types/tsconfig.json +24 -0
  213. package/CHANGELOG.md +0 -1246
  214. package/PATENTS +0 -37
  215. package/bin/dev +0 -37
  216. package/lib/.DS_Store +0 -0
  217. package/lib/Adapters/Auth/common.js +0 -2
  218. package/lib/Adapters/Auth/facebookaccountkit.js +0 -69
  219. package/lib/Controllers/SchemaCache.js +0 -97
  220. package/lib/LiveQuery/.DS_Store +0 -0
  221. package/lib/cli/utils/parsers.js +0 -77
  222. package/lib/cloud-code/.DS_Store +0 -0
  223. package/lib/cloud-code/HTTPResponse.js +0 -57
  224. package/lib/cloud-code/Untitled-1 +0 -123
  225. package/lib/cloud-code/httpRequest.js +0 -102
  226. package/lib/cloud-code/team.html +0 -123
  227. package/lib/graphql/ParseClass.js +0 -234
  228. package/lib/graphql/Schema.js +0 -197
  229. package/lib/graphql/index.js +0 -1
  230. package/lib/graphql/types/ACL.js +0 -35
  231. package/lib/graphql/types/Date.js +0 -25
  232. package/lib/graphql/types/File.js +0 -24
  233. package/lib/graphql/types/GeoPoint.js +0 -35
  234. package/lib/graphql/types/JSONObject.js +0 -30
  235. package/lib/graphql/types/NumberInput.js +0 -43
  236. package/lib/graphql/types/NumberQuery.js +0 -42
  237. package/lib/graphql/types/Pointer.js +0 -35
  238. package/lib/graphql/types/QueryConstraint.js +0 -61
  239. package/lib/graphql/types/StringQuery.js +0 -39
  240. package/lib/graphql/types/index.js +0 -110
package/README.md CHANGED
@@ -1,147 +1,206 @@
1
- ![Parse Server logo](.github/parse-server-logo.png?raw=true)
1
+ ![parse-repository-header-server](https://user-images.githubusercontent.com/5673677/138278489-7d0cebc5-1e31-4d3c-8ffb-53efcda6f29d.png)
2
2
 
3
- [![Backers on Open Collective](https://opencollective.com/parse-server/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/parse-server/sponsors/badge.svg)](#sponsors)
4
- [![Build Status](https://img.shields.io/travis/parse-community/parse-server/master.svg?style=flat)](https://travis-ci.org/parse-community/parse-server)
5
- [![Coverage Status](https://img.shields.io/codecov/c/github/parse-community/parse-server/master.svg)](https://codecov.io/github/parse-community/parse-server?branch=master)
6
- [![npm version](https://img.shields.io/npm/v/parse-server.svg?style=flat)](https://www.npmjs.com/package/parse-server)
7
- [![Join Chat](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/ParsePlatform/Chat)
8
- [![Greenkeeper badge](https://badges.greenkeeper.io/parse-community/parse-server.svg)](https://greenkeeper.io/)
3
+ ---
9
4
 
10
- Parse Server is an [open source version of the Parse backend](http://blog.parseplatform.org/announcements/introducing-parse-server-and-the-database-migration-tool/) that can be deployed to any infrastructure that can run Node.js.
5
+ [![Build Status](https://github.com/parse-community/parse-server/actions/workflows/ci.yml/badge.svg?branch=alpha)](https://github.com/parse-community/parse-server/actions/workflows/ci.yml?query=workflow%3Aci+branch%3Aalpha)
6
+ [![Build Status](https://github.com/parse-community/parse-server/actions/workflows/ci.yml/badge.svg?branch=release)](https://github.com/parse-community/parse-server/actions/workflows/ci.yml?query=workflow%3Aci+branch%3Arelease)
7
+ [![Snyk Badge](https://snyk.io/test/github/parse-community/parse-server/badge.svg)](https://snyk.io/test/github/parse-community/parse-server)
8
+ [![Coverage](https://codecov.io/github/parse-community/parse-server/branch/alpha/graph/badge.svg)](https://app.codecov.io/github/parse-community/parse-server/tree/alpha)
9
+ [![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases)
11
10
 
12
- Parse Server works with the Express web application framework. It can be added to existing web applications, or run by itself.
11
+ [![Node Version](https://img.shields.io/badge/nodejs-18,_20,_22,_24-green.svg?logo=node.js&style=flat)](https://nodejs.org)
12
+ [![MongoDB Version](https://img.shields.io/badge/mongodb-6,_7,_8-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com)
13
+ [![Postgres Version](https://img.shields.io/badge/postgresql-13,_14,_15,_16,_17,_18-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org)
13
14
 
15
+ [![npm latest version](https://img.shields.io/npm/v/parse-server/latest.svg)](https://www.npmjs.com/package/parse-server)
16
+ [![npm alpha version](https://img.shields.io/npm/v/parse-server/alpha.svg)](https://www.npmjs.com/package/parse-server)
17
+
18
+ [![Backers on Open Collective](https://opencollective.com/parse-server/backers/badge.svg)][open-collective-link]
19
+ [![Sponsors on Open Collective](https://opencollective.com/parse-server/sponsors/badge.svg)][open-collective-link]
20
+ [![Forum](https://img.shields.io/discourse/https/community.parseplatform.org/topics.svg)](https://community.parseplatform.org/c/parse-server)
21
+ [![Twitter](https://img.shields.io/twitter/follow/ParsePlatform.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=ParsePlatform)
22
+ [![Chat](https://img.shields.io/badge/Chat-Join!-%23fff?style=social&logo=slack)](https://chat.parseplatform.org)
23
+
24
+ ---
25
+
26
+ Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. Parse Server works with the Express web application framework. It can be added to existing web applications, or run by itself.
27
+
28
+ The full documentation for Parse Server is available in the [wiki](https://github.com/parse-community/parse-server/wiki). The [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/) is a good place to get started. An [API reference](http://parseplatform.org/parse-server/api/) and [Cloud Code guide](https://docs.parseplatform.org/cloudcode/guide/) are also available. If you're interested in developing for Parse Server, the [Development guide](http://docs.parseplatform.org/parse-server/guide/#development-guide) will help you get set up.
29
+
30
+ ---
31
+
32
+ A big *thank you* 🙏 to our [sponsors](#sponsors) and [backers](#backers) who support the development of Parse Platform!
33
+
34
+ #### Bronze Sponsors
35
+
36
+ [![Bronze Sponsors](https://opencollective.com/parse-server/tiers/bronze-sponsor.svg?avatarHeight=36&button=false)](https://opencollective.com/parse-server/contribute/bronze-sponsor-10559)
37
+
38
+ ---
39
+
40
+ - [Flavors \& Branches](#flavors--branches)
41
+ - [Long Term Support](#long-term-support)
14
42
  - [Getting Started](#getting-started)
15
- - [Running Parse Server](#running-parse-server)
16
- - [Locally](#locally)
17
- - [Docker](#inside-a-docker-container)
18
- - [Saving an Object](#saving-your-first-object)
19
- - [Connect an SDK](#connect-your-app-to-parse-server)
20
- - [Running elsewhere](#running-parse-server-elsewhere)
21
- - [Sample Application](#parse-server-sample-application)
22
- - [Parse Server + Express](#parse-server--express)
23
- - [Logging](#logging)
24
- - [Documentation](#documentation)
25
- - [Configuration](#configuration)
26
- - [Basic Options](#basic-options)
27
- - [Client Key Options](#client-key-options)
28
- - [Advanced Options](#advanced-options)
29
- - [Logging](#logging-1)
30
- - [Email Verification & Password Reset](#email-verification-and-password-reset)
31
- - [Using Environment Variables](#using-environment-variables-to-configure-parse-server)
32
- - [Available Adapters](#available-adapters)
33
- - [Configuring File Adapters](#configuring-file-adapters)
34
- - [Support](#support)
35
- - [Ride the Bleeding Edge](#want-to-ride-the-bleeding-edge)
43
+ - [Running Parse Server](#running-parse-server)
44
+ - [Compatibility](#compatibility)
45
+ - [Node.js](#nodejs)
46
+ - [MongoDB](#mongodb)
47
+ - [PostgreSQL](#postgresql)
48
+ - [Locally](#locally)
49
+ - [Docker Container](#docker-container)
50
+ - [Saving and Querying Objects](#saving-and-querying-objects)
51
+ - [Connect an SDK](#connect-an-sdk)
52
+ - [Running Parse Server elsewhere](#running-parse-server-elsewhere)
53
+ - [Sample Application](#sample-application)
54
+ - [Parse Server + Express](#parse-server--express)
55
+ - [Parse Server Health](#parse-server-health)
56
+ - [Status Values](#status-values)
57
+ - [Configuration](#configuration)
58
+ - [Basic Options](#basic-options)
59
+ - [Client Key Options](#client-key-options)
60
+ - [Access Scopes](#access-scopes)
61
+ - [Email Verification and Password Reset](#email-verification-and-password-reset)
62
+ - [Password and Account Policy](#password-and-account-policy)
63
+ - [Custom Routes](#custom-routes)
64
+ - [Example](#example)
65
+ - [Reserved Paths](#reserved-paths)
66
+ - [Parameters](#parameters)
67
+ - [Custom Pages](#custom-pages)
68
+ - [Using Environment Variables](#using-environment-variables)
69
+ - [Available Adapters](#available-adapters)
70
+ - [Configuring File Adapters](#configuring-file-adapters)
71
+ - [Idempotency Enforcement](#idempotency-enforcement)
72
+ - [Localization](#localization)
73
+ - [Pages](#pages)
74
+ - [Localization with Directory Structure](#localization-with-directory-structure)
75
+ - [Localization with JSON Resource](#localization-with-json-resource)
76
+ - [Dynamic placeholders](#dynamic-placeholders)
77
+ - [Reserved Keys](#reserved-keys)
78
+ - [Parameters](#parameters-1)
79
+ - [Logging](#logging)
80
+ - [Deprecations](#deprecations)
81
+ - [Live Query](#live-query)
82
+ - [GraphQL](#graphql)
83
+ - [Running](#running)
84
+ - [Using the CLI](#using-the-cli)
85
+ - [Using Docker](#using-docker)
86
+ - [Using Express.js](#using-expressjs)
87
+ - [Checking the API health](#checking-the-api-health)
88
+ - [Creating your first class](#creating-your-first-class)
89
+ - [Using automatically generated operations](#using-automatically-generated-operations)
90
+ - [Customizing your GraphQL Schema](#customizing-your-graphql-schema)
91
+ - [Learning more](#learning-more)
36
92
  - [Contributing](#contributing)
37
- - [Backers](#backers)
93
+ - [Contributors](#contributors)
38
94
  - [Sponsors](#sponsors)
95
+ - [Backers](#backers)
39
96
 
40
- # Getting Started
97
+ # Flavors & Branches
98
+
99
+ Parse Server is available in different flavors on different branches:
100
+
101
+ - The main branches are [release][log_release] and [alpha][log_alpha]. See the [changelog overview](CHANGELOG.md) for details.
102
+ - The long-term-support (LTS) branches are named `release-<version>.x.x`, for example `release-5.x.x`. LTS branches do not have pre-release branches.
103
+
104
+ ## Long Term Support
105
+
106
+ Long-Term-Support (LTS) is provided for the previous Parse Server major version. For example, Parse Server 5.x will receive security updates until Parse Server 6.x is superseded by Parse Server 7.x and becomes the new LTS version. While the current major version is published on branch `release`, a LTS version is published on branch `release-#.x.x`, for example `release-5.x.x` for the Parse Server 5.x LTS branch.
107
+
108
+ ⚠️ LTS versions are provided to help you transition as soon as possible to the current major version. While we aim to fix security vulnerabilities in the LTS version, our main focus is on developing the current major version and preparing the next major release. Therefore we may leave certain vulnerabilities up to the community to fix. Search for [pull requests with the specific LTS base branch](https://github.com/parse-community/parse-server/pulls?q=is%3Aopen+is%3Apr+base%3Arelease-5.x.x) to see the current open vulnerabilities for that LTS branch.
41
109
 
42
- April 2016 - We created a series of video screencasts, please check them out here: [http://blog.parseplatform.org/learn/parse-server-video-series-april-2016/](http://blog.parseplatform.org/learn/parse-server-video-series-april-2016/)
110
+ # Getting Started
43
111
 
44
112
  The fastest and easiest way to get started is to run MongoDB and Parse Server locally.
45
113
 
46
114
  ## Running Parse Server
47
115
 
48
- ### Locally
49
- ```
50
- $ npm install -g parse-server mongodb-runner
51
- $ mongodb-runner start
52
- $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test
53
- ```
54
- ***Note:*** *If installation with* `-g` *fails due to permission problems* (`npm ERR! code 'EACCES'`), *please refer to [this link](https://docs.npmjs.com/getting-started/fixing-npm-permissions).*
55
-
116
+ Before you start make sure you have installed:
56
117
 
57
- ### Inside a Docker container
58
- ```
59
- $ docker build --tag parse-server .
60
- $ docker run --name my-mongo -d mongo
61
- $ docker run --name my-parse-server --link my-mongo:mongo -d parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongo/test
62
- ```
118
+ - [NodeJS](https://www.npmjs.com/) that includes `npm`
119
+ - [MongoDB](https://www.mongodb.com/) or [PostgreSQL](https://www.postgresql.org/)(with [PostGIS](https://postgis.net) 2.2.0 or higher)
120
+ - Optionally [Docker](https://www.docker.com/)
63
121
 
64
- You can use any arbitrary string as your application id and master key. These will be used by your clients to authenticate with the Parse Server.
122
+ ### Compatibility
65
123
 
66
- That's it! You are now running a standalone version of Parse Server on your machine.
124
+ #### Node.js
67
125
 
68
- **Using a remote MongoDB?** Pass the `--databaseURI DATABASE_URI` parameter when starting `parse-server`. Learn more about configuring Parse Server [here](#configuration). For a full list of available options, run `parse-server --help`.
126
+ Parse Server is continuously tested with the most recent releases of Node.js to ensure compatibility. We follow the [Node.js Long Term Support plan](https://github.com/nodejs/Release) and only test against versions that are officially supported and have not reached their end-of-life date.
127
+
128
+ | Version | Minimum Version | End-of-Life | Parse Server Support |
129
+ |------------|-----------------|-------------|----------------------|
130
+ | Node.js 18 | 18.20.4 | April 2025 | <= 8.x (2025) |
131
+ | Node.js 20 | 20.18.0 | April 2026 | <= 9.x (2026) |
132
+ | Node.js 22 | 22.12.0 | April 2027 | <= 10.x (2027) |
133
+ | Node.js 24 | 24.11.0 | April 2028 | <= 11.x (2028) |
134
+
135
+ #### MongoDB
136
+
137
+ Parse Server is continuously tested with the most recent releases of MongoDB to ensure compatibility. We follow the [MongoDB support schedule](https://www.mongodb.com/support-policy) and [MongoDB lifecycle schedule](https://www.mongodb.com/support-policy/lifecycles) and only test against versions that are officially supported and have not reached their end-of-life date. MongoDB "rapid releases" are ignored as these are considered pre-releases of the next major version.
138
+
139
+ | Version | Minimum Version | End-of-Life | Parse Server Support |
140
+ |-----------|-----------------|-------------|----------------------|
141
+ | MongoDB 6 | 6.0.19 | July 2025 | <= 8.x (2025) |
142
+ | MongoDB 7 | 7.0.16 | August 2026 | <= 9.x (2026) |
143
+ | MongoDB 8 | 8.0.4 | TDB | <= 10.x (2027) |
69
144
 
70
- ### Saving your first object
145
+ #### PostgreSQL
71
146
 
72
- Now that you're running Parse Server, it is time to save your first object. We'll use the [REST API](http://docs.parseplatform.org/rest/guide), but you can easily do the same using any of the [Parse SDKs](http://parseplatform.org/#sdks). Run the following:
147
+ Parse Server is continuously tested with the most recent releases of PostgreSQL and PostGIS to ensure compatibility, using [PostGIS docker images](https://registry.hub.docker.com/r/postgis/postgis/tags?page=1&ordering=last_updated). We follow the [PostgreSQL support schedule](https://www.postgresql.org/support/versioning) and [PostGIS support schedule](https://www.postgis.net/eol_policy/) and only test against versions that are officially supported and have not reached their end-of-life date. Due to the extensive PostgreSQL support duration of 5 years, Parse Server drops support about 2 years before the official end-of-life date.
148
+
149
+ | Version | PostGIS Version | End-of-Life | Parse Server Support |
150
+ |-------------|-------------------------|---------------|----------------------|
151
+ | Postgres 13 | 3.1, 3.2, 3.3, 3.4, 3.5 | November 2025 | <= 6.x (2023) |
152
+ | Postgres 14 | 3.5 | November 2026 | <= 7.x (2024) |
153
+ | Postgres 15 | 3.3, 3.4, 3.5 | November 2027 | <= 8.x (2025) |
154
+ | Postgres 16 | 3.5 | November 2028 | <= 9.x (2026) |
155
+ | Postgres 17 | 3.5 | November 2029 | <= 10.x (2027) |
156
+ | Postgres 18 | 3.6 | November 2030 | <= 11.x (2028) |
157
+
158
+ ### Locally
73
159
 
74
160
  ```bash
75
- curl -X POST \
76
- -H "X-Parse-Application-Id: APPLICATION_ID" \
77
- -H "Content-Type: application/json" \
78
- -d '{"score":1337,"playerName":"Sean Plott","cheatMode":false}' \
79
- http://localhost:1337/parse/classes/GameScore
161
+ $ npm install -g parse-server mongodb-runner
162
+ $ mongodb-runner start
163
+ $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test
80
164
  ```
165
+ ***Note:*** *If installation with* `-g` *fails due to permission problems* (`npm ERR! code 'EACCES'`), *please refer to [this link](https://docs.npmjs.com/getting-started/fixing-npm-permissions).*
81
166
 
82
- You should get a response similar to this:
83
167
 
84
- ```js
85
- {
86
- "objectId": "2ntvSpRGIK",
87
- "createdAt": "2016-03-11T23:51:48.050Z"
88
- }
168
+ ### Docker Container
169
+
170
+ ```bash
171
+ $ git clone https://github.com/parse-community/parse-server
172
+ $ cd parse-server
173
+ $ docker build --tag parse-server .
174
+ $ docker run --name my-mongo -d mongo
89
175
  ```
90
176
 
91
- You can now retrieve this object directly (make sure to replace `2ntvSpRGIK` with the actual `objectId` you received when the object was created):
177
+ #### Running the Parse Server Image <!-- omit in toc -->
92
178
 
93
179
  ```bash
94
- $ curl -X GET \
95
- -H "X-Parse-Application-Id: APPLICATION_ID" \
96
- http://localhost:1337/parse/classes/GameScore/2ntvSpRGIK
97
- ```
98
- ```json
99
- // Response
100
- {
101
- "objectId": "2ntvSpRGIK",
102
- "score": 1337,
103
- "playerName": "Sean Plott",
104
- "cheatMode": false,
105
- "updatedAt": "2016-03-11T23:51:48.050Z",
106
- "createdAt": "2016-03-11T23:51:48.050Z"
107
- }
180
+ $ docker run --name my-parse-server -v config-vol:/parse-server/config -p 1337:1337 --link my-mongo:mongo -d parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongo/test
108
181
  ```
109
182
 
110
- Keeping tracks of individual object ids is not ideal, however. In most cases you will want to run a query over the collection, like so:
183
+ ***Note:*** *If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/), add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to the command above. Make sure `main.js` is in the `cloud-code-vol` directory before starting Parse Server.*
111
184
 
112
- ```
113
- $ curl -X GET \
114
- -H "X-Parse-Application-Id: APPLICATION_ID" \
115
- http://localhost:1337/parse/classes/GameScore
116
- ```
117
- ```json
118
- // The response will provide all the matching objects within the `results` array:
119
- {
120
- "results": [
121
- {
122
- "objectId": "2ntvSpRGIK",
123
- "score": 1337,
124
- "playerName": "Sean Plott",
125
- "cheatMode": false,
126
- "updatedAt": "2016-03-11T23:51:48.050Z",
127
- "createdAt": "2016-03-11T23:51:48.050Z"
128
- }
129
- ]
130
- }
185
+ You can use any arbitrary string as your application id and master key. These will be used by your clients to authenticate with the Parse Server.
131
186
 
132
- ```
187
+ That's it! You are now running a standalone version of Parse Server on your machine.
133
188
 
134
- To learn more about using saving and querying objects on Parse Server, check out the [Parse documentation](http://docs.parseplatform.org).
189
+ **Using a remote MongoDB?** Pass the `--databaseURI DATABASE_URI` parameter when starting `parse-server`. Learn more about configuring Parse Server [here](#configuration). For a full list of available options, run `parse-server --help`.
190
+
191
+ ### Saving and Querying Objects
192
+
193
+ Now that you're running Parse Server, it is time to save your first object. The easiest way is to use the [REST API](http://docs.parseplatform.org/rest/guide), but you can easily do the same using any of the [Parse SDKs](http://parseplatform.org/#sdks). To learn more check out the [documentation](http://docs.parseplatform.org).
135
194
 
136
- ### Connect your app to Parse Server
195
+ ### Connect an SDK
137
196
 
138
- Parse provides SDKs for all the major platforms. Refer to the Parse Server guide to [learn how to connect your app to Parse Server](https://github.com/parse-community/parse-server/wiki/Parse-Server-Guide#using-parse-sdks-with-parse-server).
197
+ Parse provides SDKs for all the major platforms. Refer to the Parse Server guide to [learn how to connect your app to Parse Server](https://docs.parseplatform.org/parse-server/guide/#using-parse-sdks-with-parse-server).
139
198
 
140
199
  ## Running Parse Server elsewhere
141
200
 
142
201
  Once you have a better understanding of how the project works, please refer to the [Parse Server wiki](https://github.com/parse-community/parse-server/wiki) for in-depth guides to deploy Parse Server to major infrastructure providers. Read on to learn more about additional ways of running Parse Server.
143
202
 
144
- ### Parse Server Sample Application
203
+ ### Sample Application
145
204
 
146
205
  We have provided a basic [Node.js application](https://github.com/parse-community/parse-server-example) that uses the Parse Server module on Express and can be easily deployed to various infrastructure providers:
147
206
 
@@ -152,65 +211,70 @@ We have provided a basic [Node.js application](https://github.com/parse-communit
152
211
  * [SashiDo](https://blog.sashido.io/tag/migration/)
153
212
  * [Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-run-parse-server-on-ubuntu-14-04)
154
213
  * [Pivotal Web Services](https://github.com/cf-platform-eng/pws-parse-server)
155
- * [Back4app](http://blog.back4app.com/2016/03/01/quick-wizard-migration/)
156
- * [Gomix](https://gomix.com/#!/project/parse-server)
214
+ * [Back4app](https://www.back4app.com/docs/get-started/welcome)
215
+ * [Glitch](https://glitch.com/edit/#!/parse-server)
157
216
  * [Flynn](https://flynn.io/blog/parse-apps-on-flynn)
217
+ * [Elestio](https://elest.io/open-source/parse)
158
218
 
159
219
  ### Parse Server + Express
160
220
 
161
221
  You can also create an instance of Parse Server, and mount it on a new or existing Express website:
162
222
 
163
223
  ```js
164
- var express = require('express');
165
- var ParseServer = require('parse-server').ParseServer;
166
- var app = express();
224
+ const express = require('express');
225
+ const ParseServer = require('parse-server').ParseServer;
226
+ const app = express();
167
227
 
168
- var api = new ParseServer({
228
+ const server = new ParseServer({
169
229
  databaseURI: 'mongodb://localhost:27017/dev', // Connection string for your MongoDB database
170
- cloud: '/home/myApp/cloud/main.js', // Absolute path to your Cloud Code
230
+ cloud: './cloud/main.js', // Path to your Cloud Code
171
231
  appId: 'myAppId',
172
232
  masterKey: 'myMasterKey', // Keep this key secret!
173
233
  fileKey: 'optionalFileKey',
174
234
  serverURL: 'http://localhost:1337/parse' // Don't forget to change to https if needed
175
235
  });
176
236
 
237
+ // Start server
238
+ await server.start();
239
+
177
240
  // Serve the Parse API on the /parse URL prefix
178
- app.use('/parse', api);
241
+ app.use('/parse', server.app);
179
242
 
180
243
  app.listen(1337, function() {
181
244
  console.log('parse-server-example running on port 1337.');
182
245
  });
183
246
  ```
184
247
 
185
- For a full list of available options, run `parse-server --help`.
186
-
187
- ## Logging
188
-
189
- Parse Server will, by default, log:
190
- * to the console
191
- * daily rotating files as new line delimited JSON
192
-
193
- Logs are also be viewable in Parse Dashboard.
248
+ For a full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations][server-options].
194
249
 
195
- **Want to log each request and response?** Set the `VERBOSE` environment variable when starting `parse-server`. Usage :- `VERBOSE='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
250
+ ## Parse Server Health
196
251
 
197
- **Want logs to be in placed in other folder?** Pass the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server`. Usage :- `PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
252
+ Check the Parse Server health by sending a request to the `/parse/health` endpoint.
198
253
 
199
- **Want to log specific levels?** Pass the `logLevel` parameter when starting `parse-server`. Usage :- `parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --logLevel LOG_LEVEL`
254
+ The response looks like this:
200
255
 
201
- **Want new line delimited JSON error logs (for consumption by CloudWatch, Google Cloud Logging, etc.)?** Pass the `JSON_LOGS` environment variable when starting `parse-server`. Usage :- `JSON_LOGS='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
256
+ ```json
257
+ {
258
+ "status": "ok"
259
+ }
260
+ ```
202
261
 
203
- # Documentation
262
+ ### Status Values
204
263
 
205
- The full documentation for Parse Server is available in the [wiki](https://github.com/parse-community/parse-server/wiki). The [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/) is a good place to get started. If you're interested in developing for Parse Server, the [Development guide](http://docs.parseplatform.org/parse-server/guide/#development-guide) will help you get set up.
264
+ | Value | Description |
265
+ |---------------|-----------------------------------------------------------------------------|
266
+ | `initialized` | The server has been created but the `start` method has not been called yet. |
267
+ | `starting` | The server is starting up. |
268
+ | `ok` | The server started and is running. |
269
+ | `error` | There was a startup error, see the logs for details. |
206
270
 
207
- ## Configuration
271
+ # Configuration
208
272
 
209
273
  Parse Server can be configured using the following options. You may pass these as parameters when running a standalone `parse-server`, or by loading a configuration file in JSON format using `parse-server path/to/configuration.json`. If you're using Parse Server on Express, you may also pass these to the `ParseServer` object as options.
210
274
 
211
- For the full list of available options, run `parse-server --help`.
275
+ For the full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations][server-options].
212
276
 
213
- #### Basic options
277
+ ## Basic Options
214
278
 
215
279
  * `appId` **(required)** - The application id to host with this server instance. You can use any arbitrary string. For migrated apps, this should match your hosted Parse app.
216
280
  * `masterKey` **(required)** - The master key to use for overriding ACL security. You can use any arbitrary string. Keep it secret! For migrated apps, this should match your hosted Parse app.
@@ -218,9 +282,9 @@ For the full list of available options, run `parse-server --help`.
218
282
  * `port` - The default port is 1337, specify this parameter to use a different port.
219
283
  * `serverURL` - URL to your Parse Server (don't forget to specify http:// or https://). This URL will be used when making requests to Parse Server from Cloud Code.
220
284
  * `cloud` - The absolute path to your cloud code `main.js` file.
221
- * `push` - Configuration options for APNS and GCM push. See the [Push Notifications quick start](http://docs.parseplatform.org/parse-server/guide/#push-notifications_push-notifications-quick-start).
285
+ * `push` - Configuration options for APNS and GCM push. See the [Push Notifications quick start](https://docs.parseplatform.org/parse-server/guide/#push-notifications-quick-start).
222
286
 
223
- #### Client key options
287
+ ## Client Key Options
224
288
 
225
289
  The client keys used with Parse are no longer necessary with Parse Server. If you wish to still require them, perhaps to be able to refuse access to older clients, you can set the keys at initialization time. Setting any of these keys will require all requests to provide one of the configured keys.
226
290
 
@@ -229,108 +293,47 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
229
293
  * `restAPIKey`
230
294
  * `dotNetKey`
231
295
 
232
- #### Advanced options
233
-
234
- * `fileKey` - For migrated apps, this is necessary to provide access to files already hosted on Parse.
235
- * `preserveFileName` - Set to true to remove the unique hash added to the file names. Defaults to false.
236
- * `allowClientClassCreation` - Set to false to disable client class creation. Defaults to true.
237
- * `enableAnonymousUsers` - Set to false to disable anonymous users. Defaults to true.
238
- * `auth` - Used to configure support for [3rd party authentication](http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication).
239
- * `facebookAppIds` - An array of valid Facebook application IDs that users may authenticate with.
240
- * `mountPath` - Mount path for the server. Defaults to `/parse`.
241
- * `filesAdapter` - The default behavior (GridStore) can be changed by creating an adapter class (see [`FilesAdapter.js`](https://github.com/parse-community/parse-server/blob/master/src/Adapters/Files/FilesAdapter.js)).
242
- * `maxUploadSize` - Max file size for uploads. Defaults to 20 MB.
243
- * `loggerAdapter` - The default behavior/transport (File) can be changed by creating an adapter class (see [`LoggerAdapter.js`](https://github.com/parse-community/parse-server/blob/master/src/Adapters/Logger/LoggerAdapter.js)).
244
- * `logLevel` - Set the specific level you want to log. Defaults to `info`. The default logger uses the npm log levels as defined by the underlying winston logger. Check [Winston logging levels](https://github.com/winstonjs/winston#logging-levels) for details on values to specify.
245
- * `sessionLength` - The length of time in seconds that a session should be valid for. Defaults to 31536000 seconds (1 year).
246
- * `maxLimit` - The maximum value supported for the limit option on queries. Defaults to unlimited.
247
- * `revokeSessionOnPasswordReset` - When a user changes their password, either through the reset password email or while logged in, all sessions are revoked if this is true. Set to false if you don't want to revoke sessions.
248
- * `accountLockout` - Lock account when a malicious user is attempting to determine an account password by trial and error.
249
- * `passwordPolicy` - Optional password policy rules to enforce.
250
- * `customPages` - A hash with urls to override email verification links, password reset links and specify frame url for masking user-facing pages. Available keys: `parseFrameURL`, `invalidLink`, `choosePassword`, `passwordResetSuccess`, `verifyEmailSuccess`.
251
- * `middleware` - (CLI only), a module name, function that is an express middleware. When using the CLI, the express app will load it just **before** mounting parse-server on the mount path. This option is useful for injecting a monitoring middleware.
252
- * `masterKeyIps` - The array of ip addresses where masterKey usage will be restricted to only these ips. (Default to [] which means allow all ips). If you're using this feature and have `useMasterKey: true` in cloudcode, make sure that you put your own ip in this list.
253
- * `readOnlyMasterKey` - A masterKey that has full read access to the data, but no write access. This key should be treated the same way as your masterKey, keeping it private.
254
- * `objectIdSize` - The string length of the newly generated object's ids.
296
+ ## Access Scopes
255
297
 
256
- ##### Logging
298
+ | Scope | Internal data | Read-only data <sub>(1)</sub> | Custom data | Restricted by CLP, ACL | Key |
299
+ |----------------|---------------|-------------------------------|-------------|------------------------|---------------------|
300
+ | Internal | r/w | r/w | r/w | no | `maintenanceKey` |
301
+ | Master | -/- | r/- | r/w | no | `masterKey` |
302
+ | ReadOnlyMaster | -/- | r/- | r/- | no | `readOnlyMasterKey` |
303
+ | Session | -/- | r/- | r/w | yes | `sessionToken` |
257
304
 
258
- Use the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server` to save your server logfiles to the specified folder.
305
+ <sub>(1) `Parse.Object.createdAt`, `Parse.Object.updatedAt`.</sub>
259
306
 
260
- Usage:
307
+ ## Email Verification and Password Reset
261
308
 
262
- ```
263
- PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY
264
- ```
265
-
266
- ##### Email verification and password reset
267
-
268
- Verifying user email addresses and enabling password reset via email requires an email adapter. As part of the `parse-server` package we provide an adapter for sending email through Mailgun. To use it, sign up for Mailgun, and add this to your initialization code:
309
+ Verifying user email addresses and enabling password reset via email requires an email adapter. There are many email adapters provided and maintained by the community. The following is an example configuration with an example email adapter. See the [Parse Server Options][server-options] for more details and a full list of available options.
269
310
 
270
311
  ```js
271
- var server = ParseServer({
312
+ const server = ParseServer({
272
313
  ...otherOptions,
314
+
273
315
  // Enable email verification
274
316
  verifyUserEmails: true,
275
317
 
276
- // if `verifyUserEmails` is `true` and
277
- // if `emailVerifyTokenValidityDuration` is `undefined` then
278
- // email verify token never expires
279
- // else
280
- // email verify token expires after `emailVerifyTokenValidityDuration`
281
- //
282
- // `emailVerifyTokenValidityDuration` defaults to `undefined`
283
- //
284
- // email verify token below expires in 2 hours (= 2 * 60 * 60 == 7200 seconds)
285
- emailVerifyTokenValidityDuration: 2 * 60 * 60, // in seconds (2 hours = 7200 seconds)
286
-
287
- // set preventLoginWithUnverifiedEmail to false to allow user to login without verifying their email
288
- // set preventLoginWithUnverifiedEmail to true to prevent user from login if their email is not verified
289
- preventLoginWithUnverifiedEmail: false, // defaults to false
290
-
291
- // The public URL of your app.
292
- // This will appear in the link that is used to verify email addresses and reset passwords.
293
- // Set the mount path as it is in serverURL
294
- publicServerURL: 'https://example.com/parse',
295
- // Your apps name. This will appear in the subject and body of the emails that are sent.
296
- appName: 'Parse App',
297
- // The email adapter
318
+ // Set email verification token validity to 2 hours
319
+ emailVerifyTokenValidityDuration: 2 * 60 * 60,
320
+
321
+ // Set email adapter
298
322
  emailAdapter: {
299
- module: '@parse/simple-mailgun-adapter',
323
+ module: 'example-mail-adapter',
300
324
  options: {
301
- // The address that your emails come from
302
- fromAddress: 'parse@example.com',
303
- // Your domain from mailgun.com
304
- domain: 'example.com',
305
- // Your API key from mailgun.com
306
- apiKey: 'key-mykey',
325
+ // Additional adapter options
326
+ ...mailAdapterOptions
307
327
  }
308
328
  },
309
-
310
- // account lockout policy setting (OPTIONAL) - defaults to undefined
311
- // if the account lockout policy is set and there are more than `threshold` number of failed login attempts then the `login` api call returns error code `Parse.Error.OBJECT_NOT_FOUND` with error message `Your account is locked due to multiple failed login attempts. Please try again after <duration> minute(s)`. After `duration` minutes of no login attempts, the application will allow the user to try login again.
312
- accountLockout: {
313
- duration: 5, // duration policy setting determines the number of minutes that a locked-out account remains locked out before automatically becoming unlocked. Set it to a value greater than 0 and less than 100000.
314
- threshold: 3, // threshold policy setting determines the number of failed sign-in attempts that will cause a user account to be locked. Set it to an integer value greater than 0 and less than 1000.
315
- },
316
- // optional settings to enforce password policies
317
- passwordPolicy: {
318
- // Two optional settings to enforce strong passwords. Either one or both can be specified.
319
- // If both are specified, both checks must pass to accept the password
320
- // 1. a RegExp object or a regex string representing the pattern to enforce
321
- validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, // enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1 digit
322
- // 2. a callback function to be invoked to validate the password
323
- validatorCallback: (password) => { return validatePassword(password) },
324
- doNotAllowUsername: true, // optional setting to disallow username in passwords
325
- maxPasswordAge: 90, // optional setting in days for password expiry. Login fails if user does not reset the password within this period after signup/last reset.
326
- maxPasswordHistory: 5, // optional setting to prevent reuse of previous n passwords. Maximum value that can be specified is 20. Not specifying it or specifying 0 will not enforce history.
327
- //optional setting to set a validity duration for password reset links (in seconds)
328
- resetTokenValidityDuration: 24*60*60, // expire after 24 hours
329
- }
330
329
  });
331
330
  ```
332
331
 
333
- You can also use other email adapters contributed by the community such as:
332
+ Offical email adapters maintained by Parse Platform:
333
+ - [parse-server-api-mail-adapter](https://github.com/parse-community/parse-server-api-mail-adapter) (localization, templates, universally supports any email provider)
334
+
335
+ Email adapters contributed by the community:
336
+ - [parse-smtp-template](https://www.npmjs.com/package/parse-smtp-template) (localization, templates)
334
337
  - [parse-server-postmark-adapter](https://www.npmjs.com/package/parse-server-postmark-adapter)
335
338
  - [parse-server-sendgrid-adapter](https://www.npmjs.com/package/parse-server-sendgrid-adapter)
336
339
  - [parse-server-mandrill-adapter](https://www.npmjs.com/package/parse-server-mandrill-adapter)
@@ -341,7 +344,112 @@ You can also use other email adapters contributed by the community such as:
341
344
  - [simple-parse-smtp-adapter](https://www.npmjs.com/package/simple-parse-smtp-adapter)
342
345
  - [parse-server-generic-email-adapter](https://www.npmjs.com/package/parse-server-generic-email-adapter)
343
346
 
344
- ### Using environment variables to configure Parse Server
347
+ ## Password and Account Policy
348
+
349
+ Set a password and account policy that meets your security requirements. The following is an example configuration. See the [Parse Server Options][server-options] for more details and a full list of available options.
350
+
351
+ ```js
352
+ const server = ParseServer({
353
+ ...otherOptions,
354
+
355
+ // The account lock policy
356
+ accountLockout: {
357
+ // Lock the account for 5 minutes.
358
+ duration: 5,
359
+ // Lock an account after 3 failed log-in attempts
360
+ threshold: 3,
361
+ // Unlock the account after a successful password reset
362
+ unlockOnPasswordReset: true,
363
+ },
364
+
365
+ // The password policy
366
+ passwordPolicy: {
367
+ // Enforce a password of at least 8 characters which contain at least 1 lower case, 1 upper case and 1 digit
368
+ validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/,
369
+ // Do not allow the username as part of the password
370
+ doNotAllowUsername: true,
371
+ // Do not allow to re-use the last 5 passwords when setting a new password
372
+ maxPasswordHistory: 5,
373
+ },
374
+ });
375
+ ```
376
+
377
+ ## Custom Routes
378
+
379
+ Custom routes allow to build user flows with webpages, similar to the existing password reset and email verification features. Custom routes are defined with the `pages` option in the Parse Server configuration:
380
+
381
+ ### Example
382
+
383
+ ```js
384
+ const api = new ParseServer({
385
+ ...otherOptions,
386
+
387
+ pages: {
388
+ enableRouter: true,
389
+ customRoutes: [{
390
+ method: 'GET',
391
+ path: 'custom_route',
392
+ handler: async request => {
393
+ // custom logic
394
+ // ...
395
+ // then, depending on the outcome, return a HTML file as response
396
+ return { file: 'custom_page.html' };
397
+ }
398
+ }]
399
+ }
400
+ }
401
+ ```
402
+
403
+ The above route can be invoked by sending a `GET` request to:
404
+ `https://[parseServerPublicUrl]/[parseMount]/[pagesEndpoint]/[appId]/[customRoute]`
405
+
406
+ The `handler` receives the `request` and returns a `custom_page.html` webpage from the `pages.pagesPath` directory as response. The advantage of building a custom route this way is that it automatically makes use of Parse Server's built-in capabilities, such as [page localization](#pages) and [dynamic placeholders](#dynamic-placeholders).
407
+
408
+ ### Reserved Paths
409
+
410
+ The following paths are already used by Parse Server's built-in features and are therefore not available for custom routes. Custom routes with an identical combination of `path` and `method` are ignored.
411
+
412
+ | Path | HTTP Method | Feature |
413
+ |-----------------------------|-------------|--------------------|
414
+ | `verify_email` | `GET` | email verification |
415
+ | `resend_verification_email` | `POST` | email verification |
416
+ | `choose_password` | `GET` | password reset |
417
+ | `request_password_reset` | `GET` | password reset |
418
+ | `request_password_reset` | `POST` | password reset |
419
+
420
+ ### Parameters
421
+
422
+ | Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
423
+ |------------------------------|----------|-----------------|---------------|-----------------------|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
424
+ | `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
425
+ | `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. |
426
+ | `pages.customRoutes` | yes | `Array` | `[]` | - | `PARSE_SERVER_PAGES_CUSTOM_ROUTES` | The custom routes. The routes are added in the order they are defined here, which has to be considered since requests traverse routes in an ordered manner. Custom routes are traversed after build-in routes such as password reset and email verification. |
427
+ | `pages.customRoutes.method` | | `String` | - | `GET`, `POST` | - | The HTTP method of the custom route. |
428
+ | `pages.customRoutes.path` | | `String` | - | `custom_page` | - | The path of the custom route. Note that the same path can used if the `method` is different, for example a path `custom_page` can have two routes, a `GET` and `POST` route, which will be invoked depending on the HTTP request method. |
429
+ | `pages.customRoutes.handler` | | `AsyncFunction` | - | `async () => { ... }` | - | The route handler that is invoked when the route matches the HTTP request. If the handler does not return a page, the request is answered with a 404 `Not found.` response. |
430
+
431
+ ## Custom Pages
432
+
433
+ It’s possible to change the default pages of the app and redirect the user to another path or domain.
434
+
435
+ ```js
436
+ const server = ParseServer({
437
+ ...otherOptions,
438
+
439
+ customPages: {
440
+ passwordResetSuccess: "http://yourapp.com/passwordResetSuccess",
441
+ verifyEmailSuccess: "http://yourapp.com/verifyEmailSuccess",
442
+ parseFrameURL: "http://yourapp.com/parseFrameURL",
443
+ linkSendSuccess: "http://yourapp.com/linkSendSuccess",
444
+ linkSendFail: "http://yourapp.com/linkSendFail",
445
+ invalidLink: "http://yourapp.com/invalidLink",
446
+ invalidVerificationLink: "http://yourapp.com/invalidVerificationLink",
447
+ choosePassword: "http://yourapp.com/choosePassword"
448
+ }
449
+ })
450
+ ```
451
+
452
+ ## Using Environment Variables
345
453
 
346
454
  You may configure the Parse Server using environment variables:
347
455
 
@@ -360,106 +468,638 @@ The default port is 1337, to use a different port set the PORT environment varia
360
468
  $ PORT=8080 parse-server --appId APPLICATION_ID --masterKey MASTER_KEY
361
469
  ```
362
470
 
363
- For the full list of configurable environment variables, run `parse-server --help`.
471
+ For the full list of configurable environment variables, run `parse-server --help` or take a look at [Parse Server Configuration](https://github.com/parse-community/parse-server/blob/master/src/Options/Definitions.js).
364
472
 
365
- ### Available Adapters
473
+ ## Available Adapters
366
474
 
367
- All official adapters are distributed as scoped pacakges on [npm (@parse)](https://www.npmjs.com/search?q=scope%3Aparse).
475
+ All official adapters are distributed as scoped packages on [npm (@parse)](https://www.npmjs.com/search?q=scope%3Aparse).
368
476
 
369
477
  Some well maintained adapters are also available on the [Parse Server Modules](https://github.com/parse-server-modules) organization.
370
478
 
371
479
  You can also find more adapters maintained by the community by searching on [npm](https://www.npmjs.com/search?q=parse-server%20adapter&page=1&ranking=optimal).
372
480
 
373
- ### Configuring File Adapters
481
+ ## Configuring File Adapters
374
482
 
375
483
  Parse Server allows developers to choose from several options when hosting files:
376
484
 
377
- * `GridStoreAdapter`, which is backed by MongoDB;
378
- * `S3Adapter`, which is backed by [Amazon S3](https://aws.amazon.com/s3/); or
379
- * `GCSAdapter`, which is backed by [Google Cloud Storage](https://cloud.google.com/storage/)
485
+ * `GridFSBucketAdapter` - which is backed by MongoDB
486
+ * `S3Adapter` - which is backed by [Amazon S3](https://aws.amazon.com/s3/)
487
+ * `GCSAdapter` - which is backed by [Google Cloud Storage](https://cloud.google.com/storage/)
488
+ * `FSAdapter` - local file storage
489
+
490
+ `GridFSBucketAdapter` is used by default and requires no setup, but if you're interested in using Amazon S3, Google Cloud Storage, or local file storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters).
491
+
492
+ ## Idempotency Enforcement
493
+
494
+ **Caution, this is an experimental feature that may not be appropriate for production.**
495
+
496
+ This feature deduplicates identical requests that are received by Parse Server multiple times, typically due to network issues or network adapter access restrictions on mobile operating systems.
380
497
 
381
- `GridStoreAdapter` is used by default and requires no setup, but if you're interested in using S3 or Google Cloud Storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters).
498
+ Identical requests are identified by their request header `X-Parse-Request-Id`. Therefore a client request has to include this header for deduplication to be applied. Requests that do not contain this header cannot be deduplicated and are processed normally by Parse Server. This means rolling out this feature to clients is seamless as Parse Server still processes requests without this header when this feature is enabled.
382
499
 
383
- # Support
500
+ > This feature needs to be enabled on the client side to send the header and on the server to process the header. Refer to the specific Parse SDK docs to see whether the feature is supported yet.
384
501
 
385
- For implementation related questions or technical support, please refer to the [Stack Overflow](http://stackoverflow.com/questions/tagged/parse.com) and [Server Fault](https://serverfault.com/tags/parse) communities.
502
+ Deduplication is only done for object creation and update (`POST` and `PUT` requests). Deduplication is not done for object finding and deletion (`GET` and `DELETE` requests), as these operations are already idempotent by definition.
386
503
 
387
- If you believe you've found an issue with Parse Server, make sure these boxes are checked before [reporting an issue](https://github.com/parse-community/parse-server/issues):
504
+ ### Configuration example <!-- omit in toc -->
388
505
 
389
- - [ ] You've met the [prerequisites](http://docs.parseplatform.org/parse-server/guide/#prerequisites).
506
+ ```
507
+ let api = new ParseServer({
508
+ idempotencyOptions: {
509
+ paths: [".*"], // enforce for all requests
510
+ ttl: 120 // keep request IDs for 120s
511
+ }
512
+ }
513
+ ```
514
+
515
+ ### Parameters <!-- omit in toc -->
390
516
 
391
- - [ ] You're running the [latest version](https://github.com/parse-community/parse-server/releases) of Parse Server.
517
+ | Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
518
+ |----------------------------|----------|-----------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
519
+ | `idempotencyOptions` | yes | `Object` | `undefined` | | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS | Setting this enables idempotency enforcement for the specified paths. |
520
+ | `idempotencyOptions.paths` | yes | `Array<String>` | `[]` | `.*` (all paths, includes the examples below), <br>`functions/.*` (all functions), <br>`jobs/.*` (all jobs), <br>`classes/.*` (all classes), <br>`functions/.*` (all functions), <br>`users` (user creation / update), <br>`installations` (installation creation / update) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_PATHS | An array of path patterns that have to match the request path for request deduplication to be enabled. The mount path must not be included, for example to match the request path `/parse/functions/myFunction` specify the path pattern `functions/myFunction`. A trailing slash of the request path is ignored, for example the path pattern `functions/myFunction` matches both `/parse/functions/myFunction` and `/parse/functions/myFunction/`. |
521
+ | `idempotencyOptions.ttl` | yes | `Integer` | `300` | `60` (60 seconds) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_TTL | The duration in seconds after which a request record is discarded from the database. Duplicate requests due to network issues can be expected to arrive within milliseconds up to several seconds. This value must be greater than `0`. |
392
522
 
393
- - [ ] You've searched through [existing issues](https://github.com/parse-community/parse-server/issues?utf8=%E2%9C%93&q=). Chances are that your issue has been reported or resolved before.
523
+ ### Postgres <!-- omit in toc -->
394
524
 
395
- # Want to ride the bleeding edge?
525
+ To use this feature in Postgres, you will need to create a cron job using [pgAdmin](https://www.pgadmin.org/docs/pgadmin4/development/pgagent_jobs.html) or similar to call the Postgres function `idempotency_delete_expired_records()` that deletes expired idempotency records. You can find an example script below. Make sure the script has the same privileges to log into Postgres as Parse Server.
396
526
 
397
- It is recommend to use builds deployed npm for many reasons, but if you want to use
398
- the latest not-yet-released version of parse-server, you can do so by depending
399
- directly on this branch:
527
+ ```bash
528
+ #!/bin/bash
400
529
 
530
+ set -e
531
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
532
+ SELECT idempotency_delete_expired_records();
533
+ EOSQL
534
+
535
+ exec "$@"
401
536
  ```
402
- npm install parse-community/parse-server.git#master
537
+
538
+ Assuming the script above is named, `parse_idempotency_delete_expired_records.sh`, a cron job that runs the script every 2 minutes may look like:
539
+
540
+ ```bash
541
+ 2 * * * * /root/parse_idempotency_delete_expired_records.sh >/dev/null 2>&1
403
542
  ```
404
543
 
405
- ## Experimenting
544
+ ## Localization
545
+
546
+ ### Pages
547
+
548
+ Custom pages as well as feature pages (e.g. password reset, email verification) can be localized with the `pages` option in the Parse Server configuration:
549
+
550
+ ```js
551
+ const api = new ParseServer({
552
+ ...otherOptions,
553
+
554
+ pages: {
555
+ enableRouter: true,
556
+ enableLocalization: true,
557
+ }
558
+ }
559
+ ```
406
560
 
407
- You can also use your own forks, and work in progress branches by specifying them:
561
+ Localization is achieved by matching a request-supplied `locale` parameter with localized page content. The locale can be supplied in either the request query, body or header with the following keys:
562
+ - query: `locale`
563
+ - body: `locale`
564
+ - header: `x-parse-page-param-locale`
408
565
 
566
+ For example, a password reset link with the locale parameter in the query could look like this:
409
567
  ```
410
- npm install github:myUsername/parse-server#my-awesome-feature
568
+ http://example.com/parse/apps/[appId]/request_password_reset?token=[token]&username=[username]&locale=de-AT
411
569
  ```
412
570
 
413
- And don't forget, if you plan to deploy it remotely, you should run `npm install` with the `--save` option.
571
+ - Localization is only available for pages in the pages directory as set with `pages.pagesPath`.
572
+ - Localization for feature pages (e.g. password reset, email verification) is disabled if `pages.customUrls` are set, even if the custom URLs point to the pages within the pages path.
573
+ - Only `.html` files are considered for localization when localizing custom pages.
414
574
 
415
- # Contributing
575
+ Pages can be localized in two ways:
416
576
 
417
- We really want Parse to be yours, to see it grow and thrive in the open source community. Please see the [Contributing to Parse Server guide](CONTRIBUTING.md).
577
+ #### Localization with Directory Structure
418
578
 
419
- -----
579
+ Pages are localized by using the corresponding file in the directory structure where the files are placed in subdirectories named after the locale or language. The file in the base directory is the default file.
420
580
 
421
- As of April 5, 2017, Parse, LLC has transferred this code to the parse-community organization, and will no longer be contributing to or distributing this code.
581
+ **Example Directory Structure:**
582
+ ```js
583
+ root/
584
+ ├── public/ // pages base path
585
+ │ ├── example.html // default file
586
+ │ └── de/ // de language folder
587
+ │ │ └── example.html // de localized file
588
+ │ └── de-AT/ // de-AT locale folder
589
+ │ │ └── example.html // de-AT localized file
590
+ ```
422
591
 
592
+ Files are matched with the locale in the following order:
593
+ 1. Locale match, e.g. locale `de-AT` matches file in folder `de-AT`.
594
+ 1. Language match, e.g. locale `de-CH` matches file in folder `de`.
595
+ 1. Default; file in base folder is returned.
423
596
 
424
- # Backers
597
+ **Configuration Example:**
598
+ ```js
599
+ const api = new ParseServer({
600
+ ...otherOptions,
601
+
602
+ pages: {
603
+ enableRouter: true,
604
+ enableLocalization: true,
605
+ customUrls: {
606
+ passwordReset: 'https://example.com/page.html'
607
+ }
608
+ }
609
+ }
610
+ ```
425
611
 
426
- Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/parse-server#backer)]
427
-
428
- <a href="https://opencollective.com/parse-server/backer/0/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/0/avatar.svg"></a>
429
- <a href="https://opencollective.com/parse-server/backer/1/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/1/avatar.svg"></a>
430
- <a href="https://opencollective.com/parse-server/backer/2/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/2/avatar.svg"></a>
431
- <a href="https://opencollective.com/parse-server/backer/3/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/3/avatar.svg"></a>
432
- <a href="https://opencollective.com/parse-server/backer/4/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/4/avatar.svg"></a>
433
- <a href="https://opencollective.com/parse-server/backer/5/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/5/avatar.svg"></a>
434
- <a href="https://opencollective.com/parse-server/backer/6/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/6/avatar.svg"></a>
435
- <a href="https://opencollective.com/parse-server/backer/7/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/7/avatar.svg"></a>
436
- <a href="https://opencollective.com/parse-server/backer/8/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/8/avatar.svg"></a>
437
- <a href="https://opencollective.com/parse-server/backer/9/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/9/avatar.svg"></a>
438
- <a href="https://opencollective.com/parse-server/backer/10/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/10/avatar.svg"></a>
439
- <a href="https://opencollective.com/parse-server/backer/11/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/11/avatar.svg"></a>
440
- <a href="https://opencollective.com/parse-server/backer/12/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/12/avatar.svg"></a>
441
- <a href="https://opencollective.com/parse-server/backer/13/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/13/avatar.svg"></a>
442
- <a href="https://opencollective.com/parse-server/backer/14/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/14/avatar.svg"></a>
443
- <a href="https://opencollective.com/parse-server/backer/15/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/15/avatar.svg"></a>
444
- <a href="https://opencollective.com/parse-server/backer/16/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/16/avatar.svg"></a>
445
- <a href="https://opencollective.com/parse-server/backer/17/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/17/avatar.svg"></a>
446
- <a href="https://opencollective.com/parse-server/backer/18/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/18/avatar.svg"></a>
447
- <a href="https://opencollective.com/parse-server/backer/19/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/19/avatar.svg"></a>
448
- <a href="https://opencollective.com/parse-server/backer/20/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/20/avatar.svg"></a>
449
- <a href="https://opencollective.com/parse-server/backer/21/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/21/avatar.svg"></a>
450
- <a href="https://opencollective.com/parse-server/backer/22/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/22/avatar.svg"></a>
451
- <a href="https://opencollective.com/parse-server/backer/23/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/23/avatar.svg"></a>
452
- <a href="https://opencollective.com/parse-server/backer/24/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/24/avatar.svg"></a>
453
- <a href="https://opencollective.com/parse-server/backer/25/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/25/avatar.svg"></a>
454
- <a href="https://opencollective.com/parse-server/backer/26/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/26/avatar.svg"></a>
455
- <a href="https://opencollective.com/parse-server/backer/27/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/27/avatar.svg"></a>
456
- <a href="https://opencollective.com/parse-server/backer/28/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/28/avatar.svg"></a>
457
- <a href="https://opencollective.com/parse-server/backer/29/website" target="_blank"><img src="https://opencollective.com/parse-server/backer/29/avatar.svg"></a>
612
+ Pros:
613
+ - All files are complete in their content and can be easily opened and previewed by viewing the file in a browser.
458
614
 
615
+ Cons:
616
+ - In most cases, a localized page differs only slightly from the default page, which could cause a lot of duplicate code that is difficult to maintain.
617
+
618
+ #### Localization with JSON Resource
619
+
620
+ Pages are localized by adding placeholders in the HTML files and providing a JSON resource that contains the translations to fill into the placeholders.
621
+
622
+ **Example Directory Structure:**
623
+ ```js
624
+ root/
625
+ ├── public/ // pages base path
626
+ │ ├── example.html // the page containing placeholders
627
+ ├── private/ // folder outside of public scope
628
+ │ └── translations.json // JSON resource file
629
+ ```
630
+
631
+ The JSON resource file loosely follows the [i18next](https://github.com/i18next/i18next) syntax, which is a syntax that is often supported by translation platforms, making it easy to manage translations, exporting them for use in Parse Server, and even to automate this workflow.
632
+
633
+ **Example JSON Content:**
634
+ ```json
635
+ {
636
+ "en": { // resource for language `en` (English)
637
+ "translation": {
638
+ "greeting": "Hello!"
639
+ }
640
+ },
641
+ "de": { // resource for language `de` (German)
642
+ "translation": {
643
+ "greeting": "Hallo!"
644
+ }
645
+ }
646
+ "de-AT": { // resource for locale `de-AT` (Austrian German)
647
+ "translation": {
648
+ "greeting": "Servus!"
649
+ }
650
+ }
651
+ }
652
+ ```
653
+
654
+ **Configuration Example:**
655
+ ```js
656
+ const api = new ParseServer({
657
+ ...otherOptions,
658
+
659
+ pages: {
660
+ enableRouter: true,
661
+ enableLocalization: true,
662
+ localizationJsonPath: './private/localization.json',
663
+ localizationFallbackLocale: 'en'
664
+ }
665
+ }
666
+ ```
667
+
668
+ Pros:
669
+ - There is only one HTML file to maintain that contains the placeholders that are filled with the translations according to the locale.
670
+
671
+ Cons:
672
+ - Files cannot be easily previewed by viewing the file in a browser because the content contains only placeholders and even HTML or CSS changes may be dynamically applied, e.g. when a localization requires a Right-To-Left layout direction.
673
+ - Style and other fundamental layout changes may be more difficult to apply.
674
+
675
+ #### Dynamic placeholders
676
+
677
+ In addition to feature related default parameters such as `appId` and the translations provided via JSON resource, it is possible to define custom dynamic placeholders as part of the router configuration. This works independently of localization and, also if `enableLocalization` is disabled.
678
+
679
+ **Configuration Example:**
680
+ ```js
681
+ const api = new ParseServer({
682
+ ...otherOptions,
683
+
684
+ pages: {
685
+ enableRouter: true,
686
+ placeholders: {
687
+ exampleKey: 'exampleValue'
688
+ }
689
+ }
690
+ }
691
+ ```
692
+ The placeholders can also be provided as function or as async function, with the `locale` and other feature related parameters passed through, to allow for dynamic placeholder values:
693
+
694
+ ```js
695
+ const api = new ParseServer({
696
+ ...otherOptions,
697
+
698
+ pages: {
699
+ enableRouter: true,
700
+ placeholders: async (params) => {
701
+ const value = await doSomething(params.locale);
702
+ return {
703
+ exampleKey: value
704
+ };
705
+ }
706
+ }
707
+ }
708
+ ```
709
+
710
+ #### Reserved Keys
711
+
712
+ The following parameter and placeholder keys are reserved because they are used related to features such as password reset or email verification. They should not be used as translation keys in the JSON resource or as manually defined placeholder keys in the configuration: `appId`, `appName`, `email`, `error`, `locale`, `publicServerUrl`, `token`, `username`.
713
+
714
+ #### Parameters
715
+
716
+ | Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
717
+ |-------------------------------------------------|----------|---------------------------------------|----------------------------------------|------------------------------------------------------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
718
+ | `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
719
+ | `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. |
720
+ | `pages.enableLocalization` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_LOCALIZATION` | Is true if pages should be localized; this has no effect on custom page redirects. |
721
+ | `pages.localizationJsonPath` | yes | `String` | `undefined` | `./private/translations.json` | `PARSE_SERVER_PAGES_LOCALIZATION_JSON_PATH` | The path to the JSON file for localization; the translations will be used to fill template placeholders according to the locale. |
722
+ | `pages.localizationFallbackLocale` | yes | `String` | `en` | `en`, `en-GB`, `default` | `PARSE_SERVER_PAGES_LOCALIZATION_FALLBACK_LOCALE` | The fallback locale for localization if no matching translation is provided for the given locale. This is only relevant when providing translation resources via JSON file. |
723
+ | `pages.placeholders` | yes | `Object`, `Function`, `AsyncFunction` | `undefined` | `{ exampleKey: 'exampleValue' }` | `PARSE_SERVER_PAGES_PLACEHOLDERS` | The placeholder keys and values which will be filled in pages; this can be a simple object or a callback function. |
724
+ | `pages.forceRedirect` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_FORCE_REDIRECT` | Is `true` if responses should always be redirects and never content, `false` if the response type should depend on the request type (`GET` request -> content response; `POST` request -> redirect response). |
725
+ | `pages.pagesPath` | yes | `String` | `./public` | `./files/pages`, `../../pages` | `PARSE_SERVER_PAGES_PAGES_PATH` | The path to the pages directory; this also defines where the static endpoint `/apps` points to. |
726
+ | `pages.pagesEndpoint` | yes | `String` | `apps` | - | `PARSE_SERVER_PAGES_PAGES_ENDPOINT` | The API endpoint for the pages. |
727
+ | `pages.customUrls` | yes | `Object` | `{}` | `{ passwordReset: 'https://example.com/page.html' }` | `PARSE_SERVER_PAGES_CUSTOM_URLS` | The URLs to the custom pages |
728
+ | `pages.customUrls.passwordReset` | yes | `String` | `password_reset.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET` | The URL to the custom page for password reset. |
729
+ | `pages.customUrls.passwordResetSuccess` | yes | `String` | `password_reset_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET_SUCCESS` | The URL to the custom page for password reset -> success. |
730
+ | `pages.customUrls.passwordResetLinkInvalid` | yes | `String` | `password_reset_link_invalid.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET_LINK_INVALID` | The URL to the custom page for password reset -> link invalid. |
731
+ | `pages.customUrls.emailVerificationSuccess` | yes | `String` | `email_verification_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SUCCESS` | The URL to the custom page for email verification -> success. |
732
+ | `pages.customUrls.emailVerificationSendFail` | yes | `String` | `email_verification_send_fail.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SEND_FAIL` | The URL to the custom page for email verification -> link send fail. |
733
+ | `pages.customUrls.emailVerificationSendSuccess` | yes | `String` | `email_verification_send_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SEND_SUCCESS` | The URL to the custom page for email verification -> resend link -> success. |
734
+ | `pages.customUrls.emailVerificationLinkInvalid` | yes | `String` | `email_verification_link_invalid.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_LINK_INVALID` | The URL to the custom page for email verification -> link invalid. |
735
+ | `pages.customUrls.emailVerificationLinkExpired` | yes | `String` | `email_verification_link_expired.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_LINK_EXPIRED` | The URL to the custom page for email verification -> link expired. |
736
+
737
+ ### Notes <!-- omit in toc -->
738
+
739
+ - In combination with the [Parse Server API Mail Adapter](https://www.npmjs.com/package/parse-server-api-mail-adapter) Parse Server provides a fully localized flow (emails -> pages) for the user. The email adapter sends a localized email and adds a locale parameter to the password reset or email verification link, which is then used to respond with localized pages.
740
+
741
+ ## Logging
742
+
743
+ Parse Server will, by default, log:
744
+ * to the console
745
+ * daily rotating files as new line delimited JSON
746
+
747
+ Logs are also viewable in Parse Dashboard.
748
+
749
+ **Want to log each request and response?** Set the `VERBOSE` environment variable when starting `parse-server`. Usage :- `VERBOSE='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
750
+
751
+ **Want logs to be placed in a different folder?** Pass the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server`. Usage :- `PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
752
+
753
+ **Want to log specific levels?** Pass the `logLevel` parameter when starting `parse-server`. Usage :- `parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --logLevel LOG_LEVEL`
754
+
755
+ **Want new line delimited JSON error logs (for consumption by CloudWatch, Google Cloud Logging, etc)?** Pass the `JSON_LOGS` environment variable when starting `parse-server`. Usage :- `JSON_LOGS='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
756
+
757
+ # Deprecations
758
+
759
+ See the [Deprecation Plan](https://github.com/parse-community/parse-server/blob/master/DEPRECATIONS.md) for an overview of deprecations and planned breaking changes.
760
+
761
+ # Live Query
762
+
763
+ Live queries are meant to be used in real-time reactive applications, where just using the traditional query paradigm could cause several problems, like increased response time and high network and server usage. Live queries should be used in cases where you need to continuously update a page with fresh data coming from the database, which often happens in (but is not limited to) online games, messaging clients and shared to-do lists.
764
+
765
+ Take a look at [Live Query Guide](https://docs.parseplatform.org/parse-server/guide/#live-queries), [Live Query Server Setup Guide](https://docs.parseplatform.org/parse-server/guide/#scalability) and [Live Query Protocol Specification](https://github.com/parse-community/parse-server/wiki/Parse-LiveQuery-Protocol-Specification). You can setup a standalone server or multiple instances for scalability (recommended).
766
+
767
+ # GraphQL
768
+
769
+ [GraphQL](https://graphql.org/), developed by Facebook, is an open-source data query and manipulation language for APIs. In addition to the traditional REST API, Parse Server automatically generates a GraphQL API based on your current application schema. Parse Server also allows you to define your custom GraphQL queries and mutations, whose resolvers can be bound to your cloud code functions.
770
+
771
+ ## Running
772
+
773
+ ### Using the CLI
774
+
775
+ The easiest way to run the Parse GraphQL API is through the CLI:
776
+
777
+ ```bash
778
+ $ npm install -g parse-server mongodb-runner
779
+ $ mongodb-runner start
780
+ $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test --publicServerURL http://localhost:1337/parse --mountGraphQL --mountPlayground
781
+ ```
782
+
783
+ After starting the server, you can visit http://localhost:1337/playground in your browser to start playing with your GraphQL API.
784
+
785
+ ***Note:*** Do ***NOT*** use --mountPlayground option in production. [Parse Dashboard](https://github.com/parse-community/parse-dashboard) has a built-in GraphQL Playground and it is the recommended option for production apps.
786
+
787
+ ### Using Docker
788
+
789
+ You can also run the Parse GraphQL API inside a Docker container:
790
+
791
+ ```bash
792
+ $ git clone https://github.com/parse-community/parse-server
793
+ $ cd parse-server
794
+ $ docker build --tag parse-server .
795
+ $ docker run --name my-mongo -d mongo
796
+ ```
797
+
798
+ #### Running the Parse Server Image <!-- omit in toc -->
799
+
800
+ ```bash
801
+ $ docker run --name my-parse-server --link my-mongo:mongo -v config-vol:/parse-server/config -p 1337:1337 -d parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongo/test --publicServerURL http://localhost:1337/parse --mountGraphQL --mountPlayground
802
+ ```
803
+
804
+ ***Note:*** *If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/), add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to the command above. Make sure `main.js` is in the `cloud-code-vol` directory before starting Parse Server.*
805
+
806
+ After starting the server, you can visit http://localhost:1337/playground in your browser to start playing with your GraphQL API.
807
+
808
+ ***Note:*** Do ***NOT*** use --mountPlayground option in production. [Parse Dashboard](https://github.com/parse-community/parse-dashboard) has a built-in GraphQL Playground and it is the recommended option for production apps.
809
+
810
+ ### Using Express.js
811
+
812
+ You can also mount the GraphQL API in an Express.js application together with the REST API or solo. You first need to create a new project and install the required dependencies:
813
+
814
+ ```bash
815
+ $ mkdir my-app
816
+ $ cd my-app
817
+ $ npm install parse-server express --save
818
+ ```
819
+
820
+ Then, create an `index.js` file with the following content:
821
+
822
+ ```js
823
+ const express = require('express');
824
+ const { ParseServer, ParseGraphQLServer } = require('parse-server');
825
+
826
+ const app = express();
827
+
828
+ const parseServer = new ParseServer({
829
+ databaseURI: 'mongodb://localhost:27017/test',
830
+ appId: 'APPLICATION_ID',
831
+ masterKey: 'MASTER_KEY',
832
+ serverURL: 'http://localhost:1337/parse',
833
+ publicServerURL: 'http://localhost:1337/parse'
834
+ });
835
+
836
+ const parseGraphQLServer = new ParseGraphQLServer(
837
+ parseServer,
838
+ {
839
+ graphQLPath: '/graphql',
840
+ playgroundPath: '/playground'
841
+ }
842
+ );
843
+
844
+ app.use('/parse', parseServer.app); // (Optional) Mounts the REST API
845
+ parseGraphQLServer.applyGraphQL(app); // Mounts the GraphQL API
846
+ parseGraphQLServer.applyPlayground(app); // (Optional) Mounts the GraphQL Playground - do NOT use in Production
847
+
848
+ await parseServer.start();
849
+ app.listen(1337, function() {
850
+ console.log('REST API running on http://localhost:1337/parse');
851
+ console.log('GraphQL API running on http://localhost:1337/graphql');
852
+ console.log('GraphQL Playground running on http://localhost:1337/playground');
853
+ });
854
+ ```
855
+
856
+ And finally start your app:
857
+
858
+ ```bash
859
+ $ npx mongodb-runner start
860
+ $ node index.js
861
+ ```
862
+
863
+ After starting the app, you can visit http://localhost:1337/playground in your browser to start playing with your GraphQL API.
864
+
865
+ ***Note:*** Do ***NOT*** mount the GraphQL Playground in production. [Parse Dashboard](https://github.com/parse-community/parse-dashboard) has a built-in GraphQL Playground and it is the recommended option for production apps.
866
+
867
+ ## Checking the API health
868
+
869
+ Run the following:
870
+
871
+ ```graphql
872
+ query Health {
873
+ health
874
+ }
875
+ ```
876
+
877
+ You should receive the following response:
878
+
879
+ ```json
880
+ {
881
+ "data": {
882
+ "health": true
883
+ }
884
+ }
885
+ ```
886
+
887
+ ## Creating your first class
888
+
889
+ Since your application does not have any schema yet, you can use the `createClass` mutation to create your first class. Run the following:
890
+
891
+ ```graphql
892
+ mutation CreateClass {
893
+ createClass(
894
+ name: "GameScore"
895
+ schemaFields: {
896
+ addStrings: [{ name: "playerName" }]
897
+ addNumbers: [{ name: "score" }]
898
+ addBooleans: [{ name: "cheatMode" }]
899
+ }
900
+ ) {
901
+ name
902
+ schemaFields {
903
+ name
904
+ __typename
905
+ }
906
+ }
907
+ }
908
+ ```
909
+
910
+ You should receive the following response:
911
+
912
+ ```json
913
+ {
914
+ "data": {
915
+ "createClass": {
916
+ "name": "GameScore",
917
+ "schemaFields": [
918
+ {
919
+ "name": "objectId",
920
+ "__typename": "SchemaStringField"
921
+ },
922
+ {
923
+ "name": "updatedAt",
924
+ "__typename": "SchemaDateField"
925
+ },
926
+ {
927
+ "name": "createdAt",
928
+ "__typename": "SchemaDateField"
929
+ },
930
+ {
931
+ "name": "playerName",
932
+ "__typename": "SchemaStringField"
933
+ },
934
+ {
935
+ "name": "score",
936
+ "__typename": "SchemaNumberField"
937
+ },
938
+ {
939
+ "name": "cheatMode",
940
+ "__typename": "SchemaBooleanField"
941
+ },
942
+ {
943
+ "name": "ACL",
944
+ "__typename": "SchemaACLField"
945
+ }
946
+ ]
947
+ }
948
+ }
949
+ }
950
+ ```
951
+
952
+ ## Using automatically generated operations
953
+
954
+ Parse Server learned from the first class that you created and now you have the `GameScore` class in your schema. You can now start using the automatically generated operations!
955
+
956
+ Run the following to create your first object:
957
+
958
+ ```graphql
959
+ mutation CreateGameScore {
960
+ createGameScore(
961
+ fields: {
962
+ playerName: "Sean Plott"
963
+ score: 1337
964
+ cheatMode: false
965
+ }
966
+ ) {
967
+ id
968
+ updatedAt
969
+ createdAt
970
+ playerName
971
+ score
972
+ cheatMode
973
+ ACL
974
+ }
975
+ }
976
+ ```
977
+
978
+ You should receive a response similar to this:
979
+
980
+ ```json
981
+ {
982
+ "data": {
983
+ "createGameScore": {
984
+ "id": "XN75D94OBD",
985
+ "updatedAt": "2019-09-17T06:50:26.357Z",
986
+ "createdAt": "2019-09-17T06:50:26.357Z",
987
+ "playerName": "Sean Plott",
988
+ "score": 1337,
989
+ "cheatMode": false,
990
+ "ACL": null
991
+ }
992
+ }
993
+ }
994
+ ```
995
+
996
+ You can also run a query to this new class:
997
+
998
+ ```graphql
999
+ query GameScores {
1000
+ gameScores {
1001
+ results {
1002
+ id
1003
+ updatedAt
1004
+ createdAt
1005
+ playerName
1006
+ score
1007
+ cheatMode
1008
+ ACL
1009
+ }
1010
+ }
1011
+ }
1012
+ ```
1013
+
1014
+ You should receive a response similar to this:
1015
+
1016
+ ```json
1017
+ {
1018
+ "data": {
1019
+ "gameScores": {
1020
+ "results": [
1021
+ {
1022
+ "id": "XN75D94OBD",
1023
+ "updatedAt": "2019-09-17T06:50:26.357Z",
1024
+ "createdAt": "2019-09-17T06:50:26.357Z",
1025
+ "playerName": "Sean Plott",
1026
+ "score": 1337,
1027
+ "cheatMode": false,
1028
+ "ACL": null
1029
+ }
1030
+ ]
1031
+ }
1032
+ }
1033
+ }
1034
+ ```
1035
+
1036
+ ## Customizing your GraphQL Schema
1037
+
1038
+ Parse GraphQL Server allows you to create a custom GraphQL schema with own queries and mutations to be merged with the auto-generated ones. You can resolve these operations using your regular cloud code functions.
1039
+
1040
+ To start creating your custom schema, you need to code a `schema.graphql` file and initialize Parse Server with `--graphQLSchema` and `--cloud` options:
1041
+
1042
+ ```bash
1043
+ $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test --publicServerURL http://localhost:1337/parse --cloud ./cloud/main.js --graphQLSchema ./cloud/schema.graphql --mountGraphQL --mountPlayground
1044
+ ```
1045
+
1046
+ ### Creating your first custom query <!-- omit in toc -->
1047
+
1048
+ Use the code below for your `schema.graphql` and `main.js` files. Then restart your Parse Server.
1049
+
1050
+ ```graphql
1051
+ # schema.graphql
1052
+ extend type Query {
1053
+ hello: String! @resolve
1054
+ }
1055
+ ```
1056
+
1057
+ ```js
1058
+ // main.js
1059
+ Parse.Cloud.define('hello', async () => {
1060
+ return 'Hello world!';
1061
+ });
1062
+ ```
1063
+
1064
+ You can now run your custom query using GraphQL Playground:
1065
+
1066
+ ```graphql
1067
+ query {
1068
+ hello
1069
+ }
1070
+ ```
1071
+
1072
+ You should receive the response below:
1073
+
1074
+ ```json
1075
+ {
1076
+ "data": {
1077
+ "hello": "Hello world!"
1078
+ }
1079
+ }
1080
+ ```
1081
+
1082
+ ## Learning more
1083
+
1084
+ The [Parse GraphQL Guide](http://docs.parseplatform.org/graphql/guide/) is a very good source for learning how to use the Parse GraphQL API.
1085
+
1086
+ You also have a very powerful tool inside your GraphQL Playground. Please look at the right side of your GraphQL Playground. You will see the `DOCS` and `SCHEMA` menus. They are automatically generated by analyzing your application schema. Please refer to them and learn more about everything that you can do with your Parse GraphQL API.
1087
+
1088
+ Additionally, the [GraphQL Learn Section](https://graphql.org/learn/) is a very good source to learn more about the power of the GraphQL language.
1089
+
1090
+ # Contributing
1091
+
1092
+ Please see the [Contributing Guide](CONTRIBUTING.md).
1093
+
1094
+ # Contributors
1095
+
1096
+ This project exists thanks to all the people who contribute... we'd love to see your face on this list!
1097
+
1098
+ <a href="../../graphs/contributors"><img src="https://opencollective.com/parse-server/contributors.svg?width=890&button=false" /></a>
459
1099
 
460
1100
  # Sponsors
461
1101
 
462
- Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/parse-server#sponsor)]
1102
+ Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor!](https://opencollective.com/parse-server#sponsor)
463
1103
 
464
1104
  <a href="https://opencollective.com/parse-server/sponsor/0/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/0/avatar.svg"></a>
465
1105
  <a href="https://opencollective.com/parse-server/sponsor/1/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/1/avatar.svg"></a>
@@ -492,3 +1132,14 @@ Become a sponsor and get your logo on our README on Github with a link to your s
492
1132
  <a href="https://opencollective.com/parse-server/sponsor/28/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/28/avatar.svg"></a>
493
1133
  <a href="https://opencollective.com/parse-server/sponsor/29/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/29/avatar.svg"></a>
494
1134
 
1135
+ # Backers
1136
+
1137
+ Support us with a monthly donation and help us continue our activities. [Become a backer!](https://opencollective.com/parse-server#backer)
1138
+
1139
+ <a href="https://opencollective.com/parse-server#backers" target="_blank"><img src="https://opencollective.com/parse-server/backers.svg?width=890" /></a>
1140
+
1141
+ [open-collective-link]: https://opencollective.com/parse-server
1142
+ [log_release]: https://github.com/parse-community/parse-server/blob/release/changelogs/CHANGELOG_release.md
1143
+ [log_beta]: https://github.com/parse-community/parse-server/blob/beta/changelogs/CHANGELOG_beta.md
1144
+ [log_alpha]: https://github.com/parse-community/parse-server/blob/alpha/changelogs/CHANGELOG_alpha.md
1145
+ [server-options] http://parseplatform.org/parse-server/api/release/ParseServerOptions.html