Skip to content

Commit 488b2ff

Browse files
committed
Migrate to new cloud code interfaces
removes job status object, moves messasge method on req object Adds 3.0.0 migration guide Fixes nits about 3.0.0 documentation Adds update guide to README
1 parent e46830a commit 488b2ff

15 files changed

+543
-372
lines changed

3.0.0.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# Upgrading Parse Server to version 3.0.0
2+
3+
parse-server 3.0.0 comes also with the JS SDK version 2.0 which requires a migration. Follow the migration guide [here](https://github.com/parse-community/Parse-SDK-JS/blob/master/2.0.0.md).
4+
5+
With the 3.0.0, parse-server has completely revamped it's cloud code interface. Gone are the backbone style calls, welcome promises and async/await.
6+
7+
In order to leverage those new nodejs features, you'll need to run at least node 8.10. We've dropped the support of node 6 a few months ago, so if you haven't made the change yet, now would be a really good time to take the plunge.
8+
9+
## Migrating Cloud Code Hooks
10+
11+
### Synchronous validations:
12+
13+
```js
14+
// before
15+
Parse.Cloud.beforeSave('MyClassName', function(request, response) {
16+
if (!passesValidation(req.object)) {
17+
response.error('Ooops something went wrong');
18+
} else {
19+
response.success();
20+
}
21+
});
22+
23+
// after
24+
Parse.Cloud.beforeSave('MyClassName', (request) => {
25+
if (!passesValidation(req.object)) {
26+
throw 'Ooops something went wrong';
27+
}
28+
});
29+
```
30+
31+
All methods are wrapped in promises, so you can freely `throw` `Error`, `Parse.Error` or `string` to mark an error.
32+
33+
### Asynchronous validations:
34+
35+
For asynchronous code, you can use promises or async / await.
36+
37+
Consider the following beforeSave call that would replace the contents of a fileURL with a proper copy of the image as a Parse.File.
38+
39+
```js
40+
// before
41+
Parse.Cloud.beforeSave('Post', function(request, response) {
42+
Parse.Cloud.httpRequest({
43+
url: request.object.get('fileURL'),
44+
success: function(contents) {
45+
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
46+
file.save({
47+
success: function() {
48+
request.object.set('file', file);
49+
response.success();
50+
},
51+
error: response.error
52+
});
53+
},
54+
error: response.error
55+
});
56+
});
57+
```
58+
59+
As we can see the current way, with backbone style callbacks is quite tough to read and maintain.
60+
It's also not really trivial to handle errors, as you need to pass the response.error to each error handlers.
61+
62+
Now it can be modernized with promises:
63+
64+
```js
65+
// after (with promises)
66+
Parse.Cloud.beforeSave('MyClassName', (request) => {
67+
return Parse.Cloud.httpRequest({
68+
url: request.object.get('fileURL')
69+
}).then((contents) => {
70+
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
71+
request.object.set('file', file);
72+
return file.save();
73+
});
74+
});
75+
```
76+
77+
And you can even make it better with async/await.
78+
79+
```js
80+
// after with async/await
81+
Parse.Cloud.beforeSave('MyClassName', async (request) => {
82+
const contents = await Parse.Cloud.httpRequest({
83+
url: request.object.get('fileURL')
84+
});
85+
86+
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
87+
request.object.set('file', file);
88+
await file.save();
89+
});
90+
```
91+
92+
## Aborting hooks and functions
93+
94+
In order to abort a `beforeSave` or any hook, you now need to throw an error:
95+
96+
```js
97+
// after with async/await
98+
Parse.Cloud.beforeSave('MyClassName', async (request) => {
99+
// valid, will result in a Parse.Error(SCRIPT_FAILED, 'Something went wrong')
100+
throw 'Something went wrong'
101+
// also valid, will fail with Parse.Error(SCRIPT_FAILED, 'Something else went wrong')
102+
throw new Error('Something else went wrong')
103+
// using a Parse.Error is also valid
104+
throw new Parse.Error(1001, 'My error')
105+
});
106+
```
107+
108+
## Migrating Functions
109+
110+
Cloud Functions can be migrated the same way as cloud code hooks.
111+
In functions, the response object is not passed anymore, as it is in cloud code hooks
112+
113+
Continuing with the image downloader example:
114+
115+
```js
116+
// before
117+
Parse.Cloud.define('downloadImage', function(request, response) {
118+
Parse.Cloud.httpRequest({
119+
url: request.params.url,
120+
success: function(contents) {
121+
const file = new Parse.File(request.params.name, { base64: contents.buffer.toString('base64') });
122+
file.save({
123+
success: function() {
124+
response.success(file);
125+
},
126+
error: response.error
127+
});
128+
},
129+
error: response.error
130+
});
131+
});
132+
```
133+
134+
You would call this method with:
135+
136+
```js
137+
Parse.Cloud.run({
138+
url: '....',
139+
name: 'my-file'
140+
});
141+
```
142+
143+
To migrate this function you would follow the same practices as the ones before, and we'll jump right away to the async/await implementation:
144+
145+
```js
146+
// after with async/await
147+
Parse.Cloud.beforeSave('MyClassName', async (request) => {
148+
const {
149+
url, name
150+
} = request.params;
151+
const response = await Parse.Cloud.httpRequest({ url });
152+
153+
const file = new Parse.File(name, { base64: response.buffer.toString('base64') });
154+
await file.save();
155+
return file;
156+
});
157+
```
158+
159+
## Migrating jobs
160+
161+
As with hooks and functions, jobs don't have a status object anymore.
162+
The message method has been moved to the request object.
163+
164+
```js
165+
// before
166+
Parse.Cloud.job('downloadImageJob', function(request, status) {
167+
var query = new Parse.Query('ImagesToDownload');
168+
query.find({
169+
success: function(images) {
170+
var done = 0;
171+
for (var i = 0; i<images.length; i++) {
172+
var image = images[i];
173+
status.message('Doing '+image.get('url'));
174+
Parse.Cloud.httpRequest({
175+
url: image.get('url'),
176+
success: function(contents) {
177+
status.message('Got '+image.get('url'));
178+
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
179+
file.save({
180+
success: function() {
181+
status.message('Saved '+image.get('url'));
182+
done++;
183+
if (done == images.length) {
184+
status.success();
185+
}
186+
},
187+
error: function() {
188+
response.message('Error '+image.get('url'));
189+
done++;
190+
if (done == images.length) {
191+
status.error();
192+
}
193+
}
194+
});
195+
},
196+
error: status.error
197+
});
198+
}
199+
}
200+
});
201+
});
202+
```
203+
204+
```js
205+
Parse.Cloud.job('downloadImageJob', async function(request) {
206+
const query = new Parse.Query('ImagesToDownload');
207+
const images = await query.find();
208+
const promises = images.map(async (image) => {
209+
request.message('Doing ' + image.get('url'));
210+
const contents = await Parse.Cloud.httpRequest({
211+
url: image.get('url')
212+
});
213+
request.message('Got ' + image.get('url'));
214+
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
215+
await file.save();
216+
request.message('Saved ' + image.get('url'));
217+
});
218+
await Promise.all(promises);
219+
});
220+
221+
```
222+
223+
As you can see the new implementation is more concise, easier to read and maintain.
224+
225+
If you encounter a problem or discover an issue with this guide, or with any Parse Community project, feel free to [reach out on github](https://github.com/parse-community/parse-server/issues/new/choose)
226+

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Parse Server works with the Express web application framework. It can be added t
3535
- [Ride the Bleeding Edge](#want-to-ride-the-bleeding-edge)
3636
- [Contributing](#contributing)
3737
- [Backers](#backers)
38+
- [Upgrading to 3.0.0](#upgrading-to-3.0.0)
3839
- [Sponsors](#sponsors)
3940

4041
# Getting Started
@@ -380,6 +381,14 @@ Parse Server allows developers to choose from several options when hosting files
380381

381382
`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).
382383

384+
# Upgrading to 3.0.0
385+
386+
Starting 3.0.0, parse-server uses the JS SDK version 2.0.
387+
In short, parse SDK v2.0 removes the backbone style callbacks as well as the Parse.Promise object in favor of native promises.
388+
All the Cloud Code interfaces also have been updated to reflect those changes, and all backbone style response objects are removed and replaced by Promise style resolution.
389+
390+
We have written up a [migration guide](3.0.0.md), hoping this will help you transition to the next major release.
391+
383392
# Support
384393

385394
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.

0 commit comments

Comments
 (0)