[plt-scheme] use web service from scheme?
Sigrid Keydana wrote:
> Hi,
>
> I'd like to ask if there is a tutorial or example of how to use a web
> service from scheme? (Already saw flickr.plt on Planet, but a tutorial
> would be even more helpful of course :-) )
I'm not sure this counts as a tutorial, but here is a lightweight way of
interacting with a simple web service, delicious.
The delicious web service basically offers you a number of functions,
which you call by visiting certain URLs. The path part of the URL
determines which function you call, and arguments, which are named, are
given in query part. Results are returned as XML.
You can call these functions without using Scheme at all either by using
a web browser, or a command line program like curl, or wget. For
example, change user:pass appropriately, and visit:
https://user:pass@api.del.icio.us/v1/posts/recent?tag=scheme
You get an XML document listing all you bookmarks tagged with "scheme".
The function in this case is "posts/recent" and the "tag" argument is
"scheme".
With this example, I get:
<?xml version="1.0" encoding="UTF-8"?>
<posts user="dvanhorn" tag="scheme">
<post href="http://plt-scheme.org/"
hash="4ffc3abae9db52de059f66944ef834f9"
description="PLT Scheme" tag="scheme plt awesome"
time="2009-01-25T19:32:05Z"/>
</posts>
<!-- fe04.api.del.ac4.yahoo.net uncompressed/chunked Sun Jan 25 12:24:23
PST 2009 -->
Moving into the Scheme world, suppose we have a function that takes one
of the designated delicious function names and named arguments. A
natural way to model named arguments is with keywords. Rather than
return an XML document, let's return an S-Expression representing the
XML result (an X-Expr).
The example becomes:
(delicious "posts/get" #:tags "scheme")
Which evaluates to:
(posts
((dt "2009-01-25T08:00:00Z") (tag "") (user "dvanhorn"))
(post
((description "PLT Scheme")
(hash "4ffc3abae9db52de059f66944ef834f9")
(href "http://plt-scheme.org/")
(tag "scheme plt awesome")
(time "2009-01-25T19:32:05Z"))))
This is just a plain ol' list in Scheme. You can use all your familiar
list functions to operate on these values. You can construct new values
with quasiquote and friends. Generating HTML pages or RSS feeds are
really simple exercises (compare this to just about any other
programming language).
Here are some more examples:
(delicious "posts/update")
(delicious "posts/recent")
(delicious "posts/dates")
(delicious "posts/add"
#:url "http://plt-scheme.org/"
#:description "PLT Scheme"
#:extended
(string-append "PLT Scheme is an innovative programming "
"language that builds on a rich academic "
"and practical tradition.")
#:tags "scheme plt awesome")
The details between each web service will vary (flickr, for example, has
a much more complicated authentication scheme), but more or less they're
all variations of the above.
Ask if you have more questions.
David
;; Lightweight delicious API wrapper.
;; For a more complete solution see planet: untyped/delicious.
#lang scheme
(require scheme/system
net/uri-codec
xml)
(define usr (make-parameter ""))
(define pwd (make-parameter ""))
;; A MethodName is one of:
;; - "posts/update"
;; - "posts/add"
;; - "posts/delete"
;; ...
;; MethodName [Keyword Arg] ... -> S-Expr
;; Invoke the given method with the given arguments.
;; http://delicious.com/help/api
(define delicious
(make-keyword-procedure
(lambda (kws kw-args method)
(let ((in (fetch (delicious-url method kws kw-args))))
(xml->xexpr
((eliminate-whitespace '(posts tags dates bundles)
(lambda (x) x))
(document-element (read-xml in))))))))
;; String -> InputPort
;; Fetch a URL (represented as a string) as a port.
(define (fetch str-url)
;; Alt: (get-pure-port (string->url str-url))
(match (process (string-append "curl \"" str-url "\""))
[(list in out pid err send)
(begin (send 'wait)
in)]))
;; MethodName [Listof Keyword] [Listof String] -> String
;; Construct a delicious API URL.
(define (delicious-url method args vals)
(format "https://~a:~a@api.del.icio.us/v1/~a?~a"
(usr)
(pwd)
method
(interpolate-&
(map (lambda (s1 s2) (string-append s1 "=" s2))
(map keyword->string args)
(map uri-encode vals)))))
;; [Listof String] -> String
;; Interpolate the list of strings (list s1 s2 .. sN) as "s1&s2..&sN".
(define (interpolate-& los)
(cond [(empty? los) ""]
[(empty? (rest los)) (first los)]
[else (string-append (first los)
"&"
(interpolate-& (rest los)))]))
;; Examples
(usr "dvanhorn")
(pwd "********")
(delicious "posts/update")
(delicious "posts/recent")
(delicious "posts/dates")
(delicious "posts/add"
#:url "http://plt-scheme.org/"
#:description "PLT Scheme"
#:extended
(string-append "PLT Scheme is an innovative programming "
"language that builds on a rich academic "
"and practical tradition.")
#:tags "scheme plt awesome")
(delicious "posts/get"
#:tags "scheme")