2007-01-08
JSON Web Services with Factor
There's a post on Matt Croydon's weblog about using Lua to process JSON Web Services. The resulting Lua code is very easy to read. Here's my attempt at the same code in Factor:
REQUIRES: libs/http-client libs/json ;
USING: kernel io http-client json hashtables
prettyprint sequences math namespaces ;
[
"http://local.yahooapis.com/MapsService/V1/" %
"trafficData?appid=YahooDemo&street=" %
"701+First+Street&city=Sunnyvale&state=CA" %
"&output=json" %
] "" make http-get rot 200 = [
nip json>
"Result" "ResultSet" rot hash hash
1 swap [
"Result: " write
>r dup . 1+ r> [
swap write ": " write .
] hash-each
] each drop
] [
2drop
] if
I split the URL up into a 'make' block so it wouldn't wrap in this weblog post. I could have used the long string itself. It looks ok and is readable if you know Factor but not as readable as the Lua example.
In Factor the tendancy is to factor things out into small words to make things more readable and to reduce the use of stack manipulation words. Here's a refactored version:
REQUIRES: libs/http-client libs/json ;
USING: kernel io http-client json hashtables
prettyprint sequences math namespaces
errors ;
: json-get ( url -- object )
http-get rot 200 = [
nip json>
] [
"Could not process result" throw
] if ;
: hash-path ( hash seq -- object )
swap [ swap hash ] reduce ;
: counted-each ( seq quot -- )
#! Call the quotation for each element in
#! the sequence. The quotation receives a count
#! of the number of times the quotation has been called
#! and should have stack effect ( element count -- ).
0 -rot swap [ >r >r 1+ dup r> r> -rot call ] each-with drop ;
: print-hashtable ( hash -- )
[ swap write ": " write . ] hash-each ;
[
"http://local.yahooapis.com/MapsService/V1/" %
"trafficData?appid=YahooDemo&street=" %
"701+First+Street&city=Sunnyvale&state=CA" %
"&output=json" %
] "" make json-get { "ResultSet" "Result" } hash-path [
"Result: " write . print-hashtable
] counted-each
While longer the result is some words that are immediately reusable in other contexts. Especially 'json-get', 'hash-path' and 'counted-each'. Anyone want to contribute a different Factor version in the comments below?
Please note that I didn't do this exercise to prove that language A is better than language B, it just gave me a chance to use the JSON library in Factor and see how usable it was. In fact I found a bug in my JSON implementation while doing it so you'll need the fixes from my repository:
darcs get http://www.bluishcoder.co.nz/repos/factor