the singularity of being and nothingness
Ext JS 5, Sencha Fiddle and Parse.com
As I’ve used Sencha Fiddle, I’ve really come to enjoy how simple it makes testing ideas, exploring aspects of Ext JS, and debugging my code. One of the really nice features is the ability to simulate AJAX requests. While this is REALLY nice for simulating the loading of remote data, one place where it has a gap is in testing a fully-rounded workflow…for example, loading data from the server, modifying it, sending it back to the server, and receiving a successful response.
For these kinds of tasks, there a few options. First, you can set up your own server which your Fiddle code can talk to, either via CORS or JSONP. While this works, it’s a pain. Most of the time the stuff I’m doing in Fiddle is not that involved, so having to mess with a server just for remote communications is a little onerous.
Another option is Parse.com. Using this service, you can create and manage cloud-based data structures. And using their RESTful API, you can retrieve this data, as well as all the other standard CRUD operations.
Integrating Parse.com with your Ext JS app (or Sencha Touch app) is RIDICULOUSLY easy. I’m going to assume you’ve already set up your Parse.com account…if you haven’t, go get one now.
Ready? Okay, let’s do this.
Step 1: Understand the API URLs
The Parse.com RESTful API is pretty straightforward. All of your base class URLs are going to follow this syntax:
https://api.parse.com/1/classes/{className}
So let’s say that you have a class called “color”. The RESTful API endpoints will look like this:
- https://api.parse.com/1/classes/color (GET – List)
- https://api.parse.com/1/classes/color/{objectId} (GET – Single Result)
- https://api.parse.com/1/classes/color (POST – Create)
- https://api.parse.com/1/classes/color/{objectId} (PUT – Update)
- https://api.parse.com/1/classes/color/{objectId} (DELETE – Remove)
For those already using it, you’ll immediately notice something great…this is precisely the way that the Ext JS Rest proxy will format the api method URLs out-of-the-box. Perfect! Job done.
Using this knowledge, we can configure the proxy for app’s base model:
Ext.define('CarTracker.model.Base', { extend: 'Ext.data.Model', ... schema: { namespace: 'CarTracker.model', proxy: { type: 'rest', url: 'https://api.parse.com/1/classes/{entityName:lowercase}', useDefaultXhrHeader: false, withCredentials: false, headers: { 'X-Parse-Application-Id': 'XXXXX', 'X-Parse-REST-API-Key': 'XXXXX', 'Content-Type': 'application/json' } ... } } });
A few things to note here.
First, since we’re using a schema (aka, a manager for related entities), we can use the {entityName:lowercase) syntax in our URL to provide a nice template for defining all the RESTful endpoints for models within this schema. So if our concrete class of “Color” belongs to this schema, the generated URL will be: ‘https://api.parse.com/1/classes/color’
Next, note the headers configuration. This is critical in order for the API requests to work. Obviously you will substitute the Application ID and API Key with the values you get as a result of setting up your datastore with Parse.com
Step 2: Configure the Reader
Next, we need to configure our proxy’s reader to deal appropriately with the data coming back from Parse.com’s API. Let’s look at the code, and then I’ll explain:
reader: { type: 'json', rootProperty: 'results', transform: function( data ) { return data.results ? data.results : {results:data}; } }
The default rootProperty is configured to “results”. This is the wrapper that Parse.com adds to list requests. It’s possible to change it (I think) through a lot of trouble and *code* on the Parse.com end. Save yourself some headaches, though, and just use the default!
You’ll notice also that we’ve implemented a custom transform function for our reader. This is necessary because in the instance of single-result retrieval, Parse.com *doesn’t* return the result in the “results” wrapper. So then, our transformer simply deals with this and adds the wrapper so that the reader will deal with both scenarios the same.
Step 3: The Writer
The writer configuration is pretty sparse. The only config we need to add is this:
writeRecordId: false
This is needed because by default Ext JS will send the phantom record ID _as data_ when making POSTs. Parse.com does not particularly appreciate this, so we simply tell Ext JS not to send it. This won’t harm other indempotent requests, like PUT/DELETE, since the record id will be appended to the URL while not being added to the data of the request.
Step 4: Default Fields
All classes that you create in your Parse.com datastore will have the following columns:
- objectId
- createdAt
- updatedAt
You can’t rename them (in Parse.com), so you can either deal with field mappings in your models, or just deal with the names as they are. Your choice.
Step 5: Putting it all Together
Pretty easy, right? Here’s our full base model definition with all configuration in place:
Ext.define('CarTracker.model.Base', { extend: 'Ext.data.Model', idProperty: 'objectId', fields: [{ type: 'string', name: 'objectId' }, { type: 'date', name: 'updatedAt', persist: false }, { type: 'date', name: 'createdAt', persist: false }], schema: { namespace: 'CarTracker.model', proxy: { type: 'rest', url: 'https://api.parse.com/1/classes/{entityName:lowercase}', useDefaultXhrHeader: false, withCredentials: false, headers: { 'X-Parse-Application-Id': 'XXXXXX', 'X-Parse-REST-API-Key': 'XXXXXX', 'Content-Type': 'application/json' }, reader: { type: 'json', rootProperty: 'results', transform: function(data) { return data.results ? data.results : { results: data }; } }, writer: { type: 'json', writeRecordId: false } } } });
Conclusion
The cool thing about Parse.com is that, for Ext JS developers, it works on several levels. First, in terms of dealing with remote requests and persistence in the context of Sencha Fiddle, it provides an easy-to-maintain datastore. However, as you being to use Parse.com, you may find that it is robust enough to be THE datastore for your app as well. That’s what it’s there for, and given how simple it is to integrate with Ext JS, why not?
Happy coding!
Print article | This entry was posted by existdissolve on November 25, 2014 at 11:45 pm, and is filed under Ext JS 5, Parse.com, Sencha Fiddle. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
about 9 years ago
Thanks for posting. Hopefully you have saved me a lot of time and headaches.
about 9 years ago
Hi, I have my base model set up like yours and I also am using the Facebook login.
I am trying to load my model with the parse data, but it is always returning an error. Here is what my code looks like:
u.id is the objectId of my facebook user.
this.curUser = top10.model.User.load(u.id,{
success: function(user){
console.log(user.getId());
}
});
about 9 years ago
What’s the error?
about 9 years ago
code: 101
error: “object not found for get”
But in my parse data I can see the object right there with the objectId I am sending.
My request looks like this: https://api.parse.com/1/classes/user/1xpZiFC1Bx?_dc=1423442491011
about 9 years ago
Do you have any examples of this working that I could see?
about 8 years ago
Very useful. Initially I got 401’s on my parse requests, but I changed ‘X-Parse-REST-API-Key’ in the proxy headers to ‘X-Parse-Javascript-Key’ and was good to go.