A Proxy Server for Parse.com

<< See the full series of posts          Making Backbone.js work with Parse.com >>

In my previous post, I asked the question: “Is there any reason why can’t we use a service like [Parse.com] in an HTML5/Javascript single-paged app?”  The answer is “yes”.

The reason: the same origin policy.  The browser won’t let you request Parse.com data from a different domain.  There are certainly tricks you can play if you just want to GET the data (like JSONP for example), but there is no good way to make POST/PUT/DELETE requests.  You have to stay on your own domain if you want to use all that a REST API has to offer.

Using my newfound CoffeeScript skills, I came up with this proxy server based on Node.js with Express and Restler.  While I’m at it, the server can return my index.html and all other assets (images, Javascript, CSS and HTML templates).

Here is the code (full code for this post is available on GitHub https://github.com/BrianGenisio/Parseback/tree/parse.com-proxy-with-readme):

proxy.coffee

express = require 'express'
restler = require 'restler'
config = require './config'

app = express.createServer()
app.use express.bodyParser()

app.get "/", (req, res) =>
  res.sendfile "#{__dirname}/index.html"

app.all "#{config.apiPath}*", (req, res) =>
  console.log "REQUEST: ", req.url, req.body || "no body"

  data = JSON.stringify(req.body)

  restOptions =
    username:  config.applicationID
    password:  config.masterKey
    data:      data
    method:    req.method.toLowerCase()
    headers:
      'Content-Type':  'application/json'
      'Content-Length': data?.length || 0

  complete = (data) =>
    console.log "COMPLETE: ", data
    res.json JSON.parse(data)

  error = (data, res) =>
    console.log "FAILURE: ", data, res

  restler.request("https://api.parse.com/1/classes/#{req.url.replace(config.apiPath, '')}", restOptions)
    .on("complete", complete)
    .on("error", error)

app.get "/*", (req, res) =>
  res.sendfile "#{__dirname}#{req.url}"

app.listen config.port

console.log "Server started on #{config.port}"

This light-weight proxy will open a port and listen to requests.  If you request “/” or any other file, it will dump it back.  If you request “/data/*”, it will proxy your request off to Parse.com and return the result back.  It will handle all of the GET/POST/PUT/DELETE requests that Parse.com supports.

This proxy server loads a config file:

config.coffee

module.exports =
  applicationID: 'Your Parse.com Application ID'
  masterKey:     'Your Parse.com Master Key'
  apiPath:  '/data/'
  port:     3001

The first two configuration options are provided to you by Parse.com when you create a new “App” with them.  All of your entities for that “App” will have the same Application ID and Master Key.

Next is the path you want the proxy to use when passing data requests on.  In this example, http://mydomain.com/data/People would proxy off to http://api.parse.com/1/classes/People.

Finally you can specify the port to run the proxy on.  This is self explanatory.

Now all I can run my server: coffee proxy.coffee

Using curl, I can test all of the actions that my new server supports:

Create

> curl -X POST -H "Content-Type: application/json" \

> -d ‘{"first": "Brian", "last": "Genisio"}’ \

>

http://localhost:3001/data/People

{"createdAt":"2011-11-05T19:11:25.873Z","objectId":"fiIMd53m0j"} 

List 

> curl -X GET http://localhost:3001/data/People

{"results":[{"updatedAt":"2011-11-05T19:11:25.873Z","last":"Genisio","createdAt":"2011-11-05T19:11:25.873Z","first":"Brian","objectId":"fiIMd53m0j"}]} 

Update 

> curl -X PUT -H "Content-Type: application/json" \ 
> -d ‘{"middle": "Michael"}’ \ 
>
http://localhost:3001/data/People/fiIMd53m0j

{"updatedAt":"2011-11-05T19:15:25.122Z"} 

Show 

> curl -X GET http://localhost:3001/data/People/fiIMd53m0j                         
{"middle":"Michael","updatedAt":"2011-11-05T19:15:25.122Z","last":"Genisio","createdAt":"2011-11-05T19:11:25.873Z","first":"Brian","objectId":"fiIMd53m0j"}  

Delete 

> curl -X DELETE http://localhost:3001/data/People/fiIMd53m0j

{} 

Index.html

> curl http://localhost:3001

I AM AN HTML FILE

Other assets

> curl http://localhost:3001/foo.bar

I AM A TEXT FILE

Considering my entire server is less than 50 lines of code, I am happy with this compromise.  My technology (the browser) does not allow me to go completely server-less but this gets me pretty close.

In the next post, I will show how I got Backbone.js to talk to my proxy server.

Making Backbone.js work with Parse.com >>

Tags: , , , , , , ,

7 Responses to “A Proxy Server for Parse.com”

  1. [...] Captive Runtime packaging in Air 3.0 A Proxy Server for Parse.com [...]

  2. [...] is the post where I put it all together.  I showed how to create a proxy to use Parse.com as your data store.  I also showed how to modify Backbone.js to use Parse.com.  Now, I will show how easy it [...]

  1. Christopher says:

    Good Day Brian.
    While trying this I am experiencing incredible lag response from parse.com com. Do you? The console.log’s let me know that the request hits my proxy right away but it takes some time to get back the response from parse.com after Restler makes the call. We are talking almost 8-9 secs. Basically doing exactly what is doen here except I make the call to the proxy using the Parse JS SDK, just had to change the Parse Server line in the code to point to localhost and all the libraries are the latest (express, restler, coffee)

    Any idea what is happening? Any help would be great. Other than the lag everything else works great. Response comes back as if I called Parse directly.

  2. admin says:

    Christopher,

    It has been a year since I mussed around with it, but I recall that the round-trip was quite speedy when I did it. The need for the proxy server has been a bit diminished since Parse.com came out with their direct JS library, so I haven’t played with it in a while. I’ve already migrated my app that used that mechanism to the Parse.js library.

    Sorry I can’t be of further help,
    Brian

  3. Christopher says:

    I agree one does not need to use the proxy at this point, but I have my reasons. As far as the above issue. Just to rule everything out I restarted the virtualbox that the app was running on…. and what do you know, roundtrip down to 619ms. Looks liek a good ole’ reboot done the trick. Unfortunately will never know what it was if it doesn’t come back which I hope it doesn’t. Thanks for the quick reply and good work on the proxy. It solved a lot of issues for me.

    Cheers

Leave a Reply