Sleepy.Mongoose: A MongoDB HTTP Interface

The first half of the MongoDB book is due this week, so I wrote a REST interface for Mongo (I’m a prolific procrastinator).  Anyway, it’s called Sleepy.Mongoose and it’s available at https://github.com/10gen-labs/sleepy.mongoose.

Installing Sleepy.Mongoose

  1. Install MongoDB.
  2. Install the Python driver:
    $ easy_install pymongo
  3. Download Sleepy.Mongoose.
  4. From the mongoose directory, run:
    $ python httpd.py

You’ll see something that looks like:

=================================
|      MongoDB REST Server      |
=================================

listening for connections on http://localhost:27080

Using Sleepy.Mongoose

First, we’re just going to ping Sleepy.Mongoose to make sure it’s awake. You can use curl:

$ curl 'http://localhost:27080/_hello'

and it’ll send back a Star Wars quote.

To really use the interface, we need to connect to a database server. To do this, we post our database server address to the URI “/_connect” (all actions start with an underscore):

$ curl --data server=localhost:27017 'http://localhost:27080/_connect'

This connects to the database running at localhost:27017.

Now let’s insert something into a collection.

$ curl --data 'docs=[{"x":1}]' 'http://localhost:27080/foo/bar/_insert'

This will insert the document {“x” : 1} into the foo database’s bar collection. If we open up the JavaScript shell (mongo), we can see the document we just added:

> use foo
> db.bar.find()
{ "_id" : ObjectId("4b7edc9a1d41c8137e000000"), "x" : 1 }

But why bother opening the shell when we can query with curl?

$ curl -X GET 'http://localhost:27080/foo/bar/_find'
{"ok": 1, "results": [{"x": 1, "_id": {"$oid": "4b7edc9a1d41c8137e000000"}}], "id": 0}

Note that queries are GET requests, whereas the other requests up to this point have been posts (well, the _hello can be either).

A query returns three fields:

  • “ok”, which will be 1 if the query succeeded, 0 otherwise
  • “results” which is an array of documents from the db
  • “id” which is an identifier for that particular query

In this case “id” is irrelevant as we only have one document in the collection but if we had a bunch, we could use the id to get more results (_find only returns the first 15 matching documents by default, although it’s configurable). This will probably be clearer with an example, so let’s add some more documents to see how this works:

$ curl --data 'docs=[{"x":2},{"x":3}]' 'http://localhost:27080/foo/bar/_insert'
{"ok" : 1}

Now we have three documents. Let’s do a query and ask for it to return one result at a time:

$ curl -X GET 'http://localhost:27080/foo/bar/_find?batch_size=1'
{"ok": 1, "results": [{"x": 1, "_id": {"$oid": "4b7edc9a1d41c8137e000000"}}], "id": 1}

The only difference between this query and the one above is the “?batch_size=1” which means “send one document back.” Notice that the cursor id is 1 now, too (not 0). To get the next result, we can do:

$ curl -X GET 'http://localhost:27080/foo/bar/_more?id=1&batch_size=1'
{"ok": 1, "results": [{"x": 2, "_id": {"$oid": "4b7ee0731d41c8137e000001"}}], "id": 1}
$ curl -X GET 'http://localhost:27080/foo/bar/_more?id=1&batch_size=1'
{"ok": 1, "results": [{"x": 3, "_id": {"$oid": "4b7ee0731d41c8137e000002"}}], "id": 1}

Now let’s remove a document:

$ curl --data 'criteria={"x":2}' 'http://localhost:27080/foo/bar/_remove'
{"ok" : 1}

Now if we do a _find, it only returns two documents:

$ curl -X GET 'http://localhost:27080/foo/bar/_find'
{"ok": 1, "results": [{"x": 1, "_id": {"$oid": "4b7edc9a1d41c8137e000000"}}, {"x": 3, "_id": {"$oid": "4b7ee0731d41c8137e000002"}}], "id": 2}

And finally, updates:

$ curl --data 'criteria={"x":1}&newobj={"$inc":{"x":1}}' 'http://localhost:27080/foo/bar/_update'

Let’s do a _find to see the updated object, this time using criteria: {“x”:2}. To put this in a URL, we need to escape the ‘{‘ and ‘}’ characters. You can do this by copy-pasting it into any javascript interpreter (Rhino, Spidermonkey, mongo, Firebug, Chome’s dev tools) as follows:

> escape('{"x":2}')
%7B%22x%22%3A2%7D

And now we can use that in our URL:

$ curl -X GET 'http://localhost:27080/foo/bar/_find?criteria=%7B%22x%22%3A2%7D'
{"ok": 1, "results": [{"x": 2, "_id": {"$oid": "4b7edc9a1d41c8137e000000"}}], "id": 0}

If you’re looking to go beyond the basic CRUD, there’s more documentation in the wiki.

This code is super-alpha. Comments, questions, suggestions, patches, and forks are all welcome.

Note: Sleepy.Mongoose is an offshoot of something I’m actually supposed to be working on: a JavaScript API we’re going to use to make an awesome sharding tool.  Administrating your cluster will be a point-and-click interface.  You’ll be able to see how everything is doing, drag n’ drop chunks, visually split collections… it’s going to be so cool.

  • Scott Faisal

    How does one make an authenticated call against a database started with –auth option? I know it had been asked a few times here and you have directed to a couple of links  but they do not cover authenticating a REST request. Could you kindly respond on this matter?

  • Anonymous

    You have to authenticate manually.  Basically, that involves running:

    n = run_command: {getnonce : 1}
    key = md5(n.nonce + username + md5(username+”:mongo:”+password))
    run_command:  {authenticate:1, user:username, nonce:n.nonce, key:key}

  • manny

    Kristina,
    Can you give the curl command to find y in foo/bar if it exists

    Thanks a lot.

  • Anonymous

    I’m not sure what you mean, the equivalent of db.getSisterDB(“foo”).bar.find({y : {$exists : true}})?

  • manny

    Yeah, more like db.foo.find({‘bar’: {$exists:true}})

    Thanks again.

  • Anonymous

    That would be something like http://localhost:27080/dbname/foo/_find?criteria=encodedQuery, where encodedQuery is the result of encodeURI(‘{“bar” : {“$exists” : true}}’).

    See https://github.com/kchodorow/sleepy.mongoose/wiki/Querying and https://github.com/kchodorow/sleepy.mongoose/wiki for info on encoding.

  • jl

    Hi, Very impressive module. Once pymongo was installed, the CRUD interfaces worked smoothly even though I would get the following messages on _connect:
    {“ok” : 0, “errmsg” : “invalid server uri given”, “server” : “:27017”}
    in http log:xxx.systemsbiology.net – – [11/Oct/2011 14:48:16] “POST /_connect HTTP/1.1” 200 –
    :27017
    ‘module’ object has no attribute ‘_parse_uri’
    The post/get worked fine though

  • Zohrab

    Can someone help me why I keep getting this exception with sleepymongoose? It is very urgent and I truly appreciates it. thanks

    here is exception stack trace. It happens sometimes, but not all of time

    Exception happened during processing of request from
    (‘IP ADDRESS’, 63921)

    Traceback (most recent call last):

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 222, in handle_request

        self.process_request(request,
    client_address)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 241, in process_request

        self.finish_request(request,
    client_address)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 254, in finish_request

        self.RequestHandlerClass(request,
    client_address, self)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 522, in __init__

        self.handle()

      File
    “/usr/lib64/python2.5/BaseHTTPServer.py”, line 316, in handle

        self.handle_one_request()

      File
    “/usr/lib64/python2.5/BaseHTTPServer.py”, line 299, in
    handle_one_request

        self.raw_requestline =
    self.rfile.readline()

      File “/usr/lib64/python2.5/socket.py”, line
    346, in readline

        data = self._sock.recv(self._rbufsize)

    error: (104, ‘Connection reset by peer’)

  • Zohrab

    Hi Kristina, I been using sleepymongoose as our rest interface to get data. I am running into this issue. can you help me out?

     

    Exception happened during processing of request from
    (‘10.182.13.108’, 63921)

    Traceback (most recent call last):

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 222, in handle_request

        self.process_request(request,
    client_address)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 241, in process_request

        self.finish_request(request,
    client_address)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 254, in finish_request

        self.RequestHandlerClass(request,
    client_address, self)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 522, in __init__

        self.handle()

      File
    “/usr/lib64/python2.5/BaseHTTPServer.py”, line 316, in handle

        self.handle_one_request()

      File
    “/usr/lib64/python2.5/BaseHTTPServer.py”, line 299, in
    handle_one_request

        self.raw_requestline =
    self.rfile.readline()

      File “/usr/lib64/python2.5/socket.py”, line
    346, in readline

        data = self._sock.recv(self._rbufsize)

    error: (104, ‘Connection reset by peer’)

  • Zohrab

     Hey Kristina, I am running into this issue when I run sleepymongoose on our rest service calls. Can you help me out please? 

    Exception happened during processing of request from
    (‘10.182.13.108’, 63921)

    Traceback (most recent call last):

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 222, in handle_request

        self.process_request(request,
    client_address)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 241, in process_request

        self.finish_request(request,
    client_address)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 254, in finish_request

        self.RequestHandlerClass(request,
    client_address, self)

      File
    “/usr/lib64/python2.5/SocketServer.py”, line 522, in __init__

        self.handle()

      File
    “/usr/lib64/python2.5/BaseHTTPServer.py”, line 316, in handle

        self.handle_one_request()

      File
    “/usr/lib64/python2.5/BaseHTTPServer.py”, line 299, in
    handle_one_request

        self.raw_requestline =
    self.rfile.readline()

      File “/usr/lib64/python2.5/socket.py”, line
    346, in readline

        data = self._sock.recv(self._rbufsize)

    error: (104, ‘Connection reset by peer’)

  • Anonymous

    What argument(s) are you sending to _connect?  It looks like it’s only getting the port.

  • Anonymous

    That sounds like MongoDB is closing the connection.  You can probably just retry the operation and it should reconnect.

  • Colin Svingen

    Came here to say what he/she said.  HTTP RPC yes.  REST, not so much.  Not sure why not though.

  • Colin Svingen

    To get around the cross domain issue, you can proxy sleepy.mongoose through your web server.  I use nginx.  Here is my config:

       location /database/ {
          proxy_pass      http://sleepy;
       }

      upstream sleepy {
        server 127.0.0.1:27080;
      }

    Note that nginx and sleepy are on the same server.  Then just use:

    var request = new XMLHttpRequest(); request.open(‘GET’, ‘/database/collection/_find’, true); … var data = JSON.parse(request.responseText)[‘results’];

  • Anonymous

    Mostly because I was implementing it as a side project, I’m not very familiar with Python, and I didn’t immediately find examples of how to handle DELETE and PUT with Python’s HTTPServer package.  If I had realized this would be my most popular blog post ever I would have been a lot more careful!

  • Boler Guo

    Hi kristina,  

    The mongodb is stated but – 
    C:>curl –data server=localhost:27017 http://localhost:27080/_connect
    {“ok” : 0, “errmsg” : “invalid server uri given”, “server” : “localhost:27017”}

  • Anonymous

    Can you file this at https://github.com/kchodorow/sleepy.mongoose/issues? Definitely an issue, someone did some refactoring and broke this. 

  • Zbasmaji

    It is not actually. It happens under load when i run my tests. If I just run it manually, it works. we have set of tests built on sleepymongoose that gets data and then validates against web service response message.

  • Andreas

    Hi Kristina,
    I have used your mongoDB REST interface for the last couple of months, and its been working without any problems. Thanks for a great and useful interface!

    However, I just upgraded to Lion OSX and had to do some re-install of my some software + libraries. I’m now getting the following error when running $ python httpd.py:

    Traceback (most recent call last):  File “httpd.py”, line 17, in     from handlers import MongoHandler  File “/Users/Andreas/mongoose/sleepy.mongoose/sleepymongoose/handlers.py”, line 16, in     from pymongo.son import SONImportError: No module named sonI have no idea what went wrong. Do you have any idea, what is causing this?Thanks

  • Andreas

    I commented out the line that was throwing the error “from pymongo.son import SON” and everything seems to be working fine now. Will this give me any problems at a later point?

  • Anonymous

    That probably is going to cause problems.  It looks like pymongo’s package structure has changed in newer versions.  Can you try changing that line to “from bson.son import SON”?

  • I’m also getting this error when trying:
        curl –data server=’localhost:27017′ ‘http://localhost:27080/_connect’

    Please help!

  • Adam Nichols

    Thanks for this very useful software module! One thing that I haven’t been able to figure out is working with HTTPS: I start sleepy mongoose with the ‘-s’ option pointing to my .pem file, but as soon as a client tries to communicate, I get an error that looks something like this:

    Exception happened during processing of request from (‘xxx.xxx.xxx.xxx’, xxxxx)

    Traceback (most recent call last):

      File “/usr/lib/python2.6/SocketServer.py”, line 281, in _handle_request_noblock

        self.process_request(request, client_address)

      File “/usr/lib/python2.6/SocketServer.py”, line 307, in process_request

        self.finish_request(request, client_address)

      File “/usr/lib/python2.6/SocketServer.py”, line 320, in finish_request

        self.RequestHandlerClass(request, client_address, self)

      File “/usr/lib/python2.6/SocketServer.py”, line 615, in __init__

        self.handle()

      File “/usr/lib/python2.6/BaseHTTPServer.py”, line 329, in handle

        self.handle_one_request()

      File “/usr/lib/python2.6/BaseHTTPServer.py”, line 312, in handle_one_request

        self.raw_requestline = self.rfile.readline()

      File “/usr/lib/python2.6/socket.py”, line 406, in readline

        data = self._sock.recv(self._rbufsize)

    SysCallError: (-1, ‘Unexpected EOF’)

    I have worked with HTTP before, but I am new to SSL. Can you give me a few pointers on getting sleepy mongoose to work properly with HTTPS?

  • Adam Nichols

    Thanks for this very useful software module! One thing that I haven’t been able to figure out is working with HTTPS: I start sleepy mongoose with the ‘-s’ option pointing to my .pem file, but as soon as a client tries to communicate, I get an error that looks something like this:

    Exception happened during processing of request from (‘xxx.xxx.xxx.xxx’, xxxxx)

    Traceback (most recent call last):

      File “/usr/lib/python2.6/SocketServer.py”, line 281, in _handle_request_noblock

        self.process_request(request, client_address)

      File “/usr/lib/python2.6/SocketServer.py”, line 307, in process_request

        self.finish_request(request, client_address)

      File “/usr/lib/python2.6/SocketServer.py”, line 320, in finish_request

        self.RequestHandlerClass(request, client_address, self)

      File “/usr/lib/python2.6/SocketServer.py”, line 615, in __init__

        self.handle()

      File “/usr/lib/python2.6/BaseHTTPServer.py”, line 329, in handle

        self.handle_one_request()

      File “/usr/lib/python2.6/BaseHTTPServer.py”, line 312, in handle_one_request

        self.raw_requestline = self.rfile.readline()

      File “/usr/lib/python2.6/socket.py”, line 406, in readline

        data = self._sock.recv(self._rbufsize)

    SysCallError: (-1, ‘Unexpected EOF’)

    I have worked with HTTP before, but I am new to SSL. Can you give me a few pointers on getting sleepy mongoose to work properly with HTTPS?

  • Simone

    change the code

    connection._parse_uri(uri)
     in
    connection.uri_parser.parse_uri(uri)

  • Nathan

    Hi Kristina,

    After installing the Python Driver and downloading Sleepy Mongoose, the httpd.py file can’t be located when I use the python command.

    Here is the error I receive:

    python: can’t open file ‘httpd.py’: [Errno 2] No such file or directory

    Any ideas?

    Thanks,

    Nathan

  • kristina1

    You have to be in the sleepy.mongoose directory you downloaded.  You can see the file in the top-level directory on github, see? https://github.com/10gen-labs/sleepy.mongoose  <- that's the httpd.py file you want.

  • Seb

    Hi !
    I have installed Sleepy Mongoose and everything works fine as long as I use curl : curl –data ‘docs=[{“x”:1}]’ ‘http://localhost:27080/foo/bar/_insert’ insert a document in the bar collection :)Now, I would like to do the same in a asynchronous call on my webpage. On the onClick event of a button, I added : jQuery.ajax({url: ‘http://localhost:27080/foo/bar/_insert’, type: ‘POST’, data:’docs=[{x:1}]’})In the sleepy mongoose console, I was getting :localhost – – [01/Nov/2012 16:05:52] “POST /foo/bar/_insert HTTP/1.1” 200 -But the document was not inserted. I noticed a XMLHttpRequest Exception on the client site (not allowed by Acces Control Allow Origin), so I added dataType:’jsonp’ to make my request cross domain safe. I am now getting in the sleepy mongoose console : localhost – – [01/Nov/2012 15:59:46] “GET /foo/bar/_insert?callback=jQuery17103283173660747707_1351781973974&docs=[{x:1}]&_=1351781986136 HTTP/1.1” 200 -Why is it considered as a GET request now ? And still, unfortunately this doesn’t add any document in my collection.Does anyone know what I did wrong ? I would appreciate any help ! Thank you for reading 🙂

  • Seb

    (Sorry for the last comment, I have no idea why everything is in a block after posting it ! )

    Hi !I have installed Sleepy Mongoose and everything works fine as long as I use curl : curl –data ‘docs=[{“x”:1}]’ ‘http://localhost:27080/foo/bar/_insert’ insert a document in the bar collection :)Now, I would like to do the same in a asynchronous call on my webpage. On the onClick event of a button, I added : jQuery.ajax({url: ‘http://localhost:27080/foo/bar/_insert’, type: ‘POST’, data:’docs=[{x:1}]’})

    In the sleepy mongoose console, I was getting :
    localhost – – [01/Nov/2012 16:05:52] “POST /foo/bar/_insert HTTP/1.1” 200 –

    But the document was not inserted. I noticed a XMLHttpRequest Exception on the client site (not allowed by Acces Control Allow Origin), so I added dataType:’jsonp’ to make my request cross domain safe.
     I am now getting in the sleepy mongoose console : 

    localhost – – [01/Nov/2012 15:59:46] “GET /foo/bar/_insert?callback=jQuery17103283173660747707_1351781973974&docs=[{x:1}]&_=1351781986136 HTTP/1.1” 200 –

    Why is it considered as a GET request now ? 

    And still, unfortunately this doesn’t add any document in my collection.Does anyone know what I did wrong ? 
    I would appreciate any help ! Thank you for reading 🙂

  • kristina1

    Apparently you can’t use jsonp+POST: http://stackoverflow.com/questions/4508198/how-to-use-type-post-in-jsonp-ajax-call.  Can you try either try starting sleepy.mongoose with the –xorigin option or using your hostname?

  • Yannick

    Thank’s for this usefull tool ! 
    I am currently trying to use the command functionnality in order to do a group by. I followed the exemple provided in the wiki but it looks like I have some issues with the reduce function. 
    When I do the group directly in mongo DB, i get the result I am expecting :db.testcol.group({key: {v_id:true}, reduce: function(obj, prev) {prev.csum += 1;}, initial: {csum:0}}); gives ==> [ { “v_id” : 172, “csum” : 3 }, { “v_id” : 279, “csum” : 2 } ]But when I try the same with Sleepy mongoose, i get csum : 1 for all the result object. curl –data ‘cmd={“group” : {“ns” : “testcol”, “$reduce” : “function(obj, prev) {prev.csum += 1}”, “key” : {“v_id” : true}, “initial” : {“csum”:0}}}’ http://localhost:27080/test/_cmd gives ==> {“count”: 5.0, “keys”: 2, “retval”: [{“csum”: 1.0, “v_id”: 172.0}, {“csum”: 1.0, “v_id”: 279.0}], “ok”: 1.0}Am I doing something wrong in the way I run the database command ? The second question I have: is it possible to use MapReduce ? Thank you very much ! 

  • Seb

    Hi Kristina ! Thank you very much for your answer, the –xorigin resolved my problem 🙂 

  • kristina1

    That’s weird.  You can debug JavaScript with print() statements (e.g., add ‘print(tojson(obj)+” “+tojson(prev));” to your reduce.  It’ll be printed to your mongod’s log.  That might help you figure out what’s happening.

    I don’t think MapReduce works with sleepy.mongoose (because Python reorders the JSON fields), but it’s worth a try.

  • coffee_err

    Hi kristina.

    Does Sleepy.mongoose has the ACL function ?
    This is great work, realy. 

  • kristina1

    Thanks!  ACL function?

  • Jas karan

    Hi Kristina,

    Thanks alot for this fantastic software!!
    I needed some help.
    On inserting and find operations i am getting the below error:
    {“ok”: 0, “errmsg”: “auto reconnecting, please try again”}

    Also does Sleepy Mongoose work with mongo replica sets?

    Thanks alot
    Jaskaran

  • kristina1

    See https://github.com/10gen-labs/sleepy.mongoose/issues/37.

  • smcka

    Hi all, I’m using the –xorigin option to GET (HTTP) requests, which works great. When I try to POST (HTTP) back to :27080, however, I get an Access-Control-Allow-Origin error. Is there any way to configure this to allow POST? 
    Best, 
    Sam

  • Anagnostopoulos George

    looks great so far! congrats!

  • Libidli

    Hi kristina,         You’ve  done a great work! Impressive!
              But I don’t think sleepy.mongoose is really RESTful. The basic idea of REST is to use the GETPUTPOSTDELETE of http protocol to do CRUD operations. However, the ‘create’ operation in your work is  to add ‘_insert’ after the URI  instead of using the standard POST operation. Why should I bother adding extra parts such as  ‘_insert’, ‘_find’ and ‘_update’ at each URI ?

  • kristina1

    Thanks!  You’ve quite correct, it would have been much more REST-y use the request types.  

  • harish

    I couldn’t get the existing pyOpenSSL-based HTTPS to work. Apparently this is because PyOpenSSL breaks on Python v2.7 or higher. By using Python’s built in SSL, I was able to make it work. 
    I do import SSL, and then I replaced the following:        BaseServer.__init__(self, server_address, HandlerClass)
            ctx = SSL.Context(SSL.SSLv23_METHOD)

            ctx.use_privatekey_file(fpem)
            ctx.use_certificate_file(fpem)

            self.socket = SSL.Connection(ctx, socket.socet(self.address_family, self.socket_type))
            self.server_bind()
            self.server_activate()with:        BaseServer.__init__(self, server_address, HandlerClass)
            self.socket = ssl.SSLSocket(sock=socket.socket(self.address_family,self.socket_type), ssl_version=ssl.PROTOCOL_SSLv23, certfile=fpem, keyfile=fpem, server_side=True)
            self.server_bind()
            self.server_activate()

  • Phoebe Bright

    Kristina, Thanks for the app and the many useful comments below. Wrote a short post on using Sleepy Mongoose and jQuery to save and load datasets for a D3 dataviz – http://pbjots.blogspot.ie/2013/04/using-mongodb-and-sleepy-mongoose-and.html

  • Georg

    Installing on Windows I encounter this problem:

    C:sleepy.mongoosesleepymongoose>c:/Python33/Python.exe httpd.py

    File “httpd.py”, line 222

    print “n=================================n”
    ^
    SyntaxError: invalid syntax

    Any ideas?

    Thank you!

  • kristina1

    Unfortunately, I’ve never updated it to work with Python 3. You’ll have to use Python 2.* for it to work, as the syntax for “print” has changed.

  • Matyas

    Hello Kristina first of all thank you very much for this software!

    I am using this tool to make HTTP Queries to my MongoDB Database but somehow I cannot figure out how to do more complex search request than the simple find() method you described in your blog post. I would like to use $and and $or expressions for my search eg:

    { $and: [ { }, { } , … , { } ] }
    But if I escape a statement like this and pass it to the criteria variable I keep getting JSON errors.

    Is it possible to do this types of queries through your REST API?

    Thank you very much in advance for your help!

  • Vijay Bharwani

    Hi kristina,

    While running this command “$ python httpd.py”, its giving an error on line 221. When I opened the file, Its the print line code on that line 221. Please help me, what may be the issue.

  • kristina1

    Sleepy.Mongoose only works with Python 2.*. Sounds like you’re running with Python 3.*.

  • kristina1

    It supports that type of query. I recommend using http://jsonlint.com/ to fix your JSON before trying to encode it.

  • waslap

    Hi, a bit of a REST newby question: Is the fact that you can traverse a cursor not in violation of REST principles where there is no state to be stored by the server ?

kristina chodorow's blog