Saturday, April 24, 2010

Fab.js Request Methods

‹prev | My Chain | next›

I actually made a little progress in my fab.js exploration last night. I hope to build on that tonight by getting GET, POST, and PUTs working. I am fairly optimistic that this should be easy. Let's see if I really am getting the hang of this...

First up, I start with a fab.js skeleton application:
with ( require( "../" ) )

( fab )

( listen( 0xFAB ) )

// code goes here

( 404 );
As is, that actually works, but every request falls through to the 404 statement:
cstrom@whitefall:~/repos/fab$ curl localhost:4011/couch -i
HTTP/1.1 404 Not Found
Connection: keep-alive
Transfer-Encoding: chunked
In the place of the // code goes here, I add a ternary regexp that tries to match a string of characters. If that fails, the ternary falls through to the 404, otherwise it makes a call to my CouchDB DB:
  ( /^\/couch/ )

( fab.nodejs.http("http://localhost:5984/_all_dbs") )

( 404 );
Right now I am pulling back the list of all DBs from my CouchDB server. Instead, I'd like to pull back a specific document from my seed db. The URL for the "test" document in seed DB would be http://localhost:5984/seed/test. But how on earth do I use fab.js to pull the last part of the request out to use as part of the argument in the fab.nodejs.http call?

Aw nuts... guess I do not quite understand this as well as I thought I did, because I have no answer. I think it is time to go back to the slides. In the meantime, I happen upon this solution through trial and error:
  ( /^\/couch/ )

( fab.nodejs.http("http://localhost:5984/seed") )

( 404 );
If I make a request in the /couch namespace, the fab.nodejs.http function is called with the root URL of my CouchDB database. Then somehow the document is magically appended because I find:
cstrom@whitefall:~/repos/fab$ curl localhost:4011/couch/test -i
HTTP/1.1 200 OK
server: CouchDB/0.10.0 (Erlang OTP/R13B)
etag: "3-0e7f02311e98bbef014799959a076b01"
date: Sun, 25 Apr 2010 02:21:01 GMT
content-type: text/plain;charset=utf-8
content-length: 170
cache-control: must-revalidate
Connection: keep-alive

{"_id":"test","_rev":"3-0e7f02311e98bbef014799959a076b01","_attachments":{"e_mummy_salmon_0008.jpg":{"stub":true,"content_type":"image/jpeg","length":18048,"revpos":3}}}
That's just crazy. I really have no idea how the unmatched portion of the request URL gets appended. I will have to investigate that another day, for tonight, I would at least like to get PUT, POST, DELETE working.

It is at this point that I realize that I have no idea how to pass an HTTP method onto fab.nodejs.http. It takes a single argument (a URL). There is no way to do this!

Aw nuts again! This was an ill-conceived plan of attack for learning tonight.

Still, it is at least worth looking at fab.nodejs.http to see if there is anyway to change the function to pass the method in. What I notice is:
//...
client
.request(
head.method,
loc.pathname + head.url.pathname + ( head.url.search || "" ),
head.headers
)
//...
The first thing I see in there is that the downstream (closer to the requesting client) app's URL is being appended to the location that I am requesting. Mystery solved—that is how my document ID gets magically appended to the database URL.

The other thing I see is that it is already using the HTTP method from the downstream app! So can I just access my fab.js script as-is with a DELETE method?
cstrom@whitefall:~/repos/fab$ curl localhost:4011/couch/test?rev=3-0e7f02311e98bbef014799959a076b01 -i -X DELETE
HTTP/1.1 200 OK
server: CouchDB/0.10.0 (Erlang OTP/R13B)
etag: "4-f978f8bdedb4886d7e3e64647bc41726"
date: Sun, 25 Apr 2010 02:27:56 GMT
content-type: text/plain;charset=utf-8
content-length: 67
cache-control: must-revalidate
Connection: keep-alive

{"ok":true,"id":"test","rev":"4-f978f8bdedb4886d7e3e64647bc41726"}
Yes, I can.

The lesson learned from today: I need to stop fooling around with CouchDB while learning fab.js—at least for now. There are some definite interop opportunities, but it is starting to get in my way.

Day #83

2 comments:

  1. Chris,

    Just letting you know I landed a binary version of the http app:

    http://github.com/jed/fab/commit/42b15703634d10ab48407da2809f209391d3a44c

    Unlike before, where the information needed to complete the call was provided by both the downstream and upstream apps, all information now needs to be provided by the upstream app.

    so you should be able to get away with this:

    ( fab.nodejs.http, "http://localhost:5984/_all_dbs" )

    since the upstream app is just sending the url back to the http app.

    if you need to modify the headers and other information more before sending the request, try something like this

    ( fab.map( function( obj ){ ... do what you need to do here ... } ) )
    ( fab.echo )

    this takes the current incoming request, and "echoes" it back outgoing. this means you can use fab.map to adjust the request as needed.

    Hope this doesn't derail you, but let me know what you think!

    Jed

    ReplyDelete
  2. Jed, thanks for the info. I made use of it the next night. I am a little unclear on what to do in the "... do what you need to do here ..." part. Can you provide an example by any chance?

    I tried returning something like {url: {loc: "test"} }, then running it through the echo app in an attempt to influence fab.nodejs.http, but to no avail. I probably just need to noodle this through a bit more, but I wouldn't mind a hint :)

    ReplyDelete