rest-bind hygeine pasted by andyjpb on Tue Oct 14 20:11:16 2014
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; REST Procedure Call ;;; Generates wrappers to REST-like HTTP APIs ;;; ;;; Copyright (C) 2012, Andy Bennett ;;; All rights reserved. ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions are met: ;;; ;;; Redistributions of source code must retain the above copyright notice, this ;;; list of conditions and the following disclaimer. ;;; Redistributions in binary form must reproduce the above copyright notice, ;;; this list of conditions and the following disclaimer in the documentation ;;; and/or other materials provided with the distribution. ;;; Neither the name of the author nor the names of its contributors may be ;;; used to endorse or promote products derived from this software without ;;; specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ;;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ;;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ;;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ;;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ;;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ;;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ;;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ;;; POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Andy Bennett, 2012/10/29 ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (module rest-bind (define-method) (import chicken scheme) (import-for-syntax chicken srfi-1) (use data-structures) (use intarweb uri-common) ; (define-method (name args...) endpoint writer reader #!optional header) ; -> if no writer is provided, generates a procedure (name #!optional args...) ; otherwise generates a procedure (name body #!optional args...) ; endpoint is the URI provided for the API call ; writer is a procedure of one argument. ; writer is called with body ; writer should return something suitable for passing to ; call-with-input-request ; i.e. a string containing the raw data to send, an alist or a pair of ; values: a procedure that accepts a port and writes the response data to ; it and an alist of extra headers. If you supply a pair of values then do ; not forget to include a content-length header in the accompanying alist. (define-syntax define-method (ir-macro-transformer (lambda (expr inject compare) (assert (pair? expr)) (let* ((proc (car expr)) (defn (cdr expr)) (_ (assert (list? defn))) (_ (assert (or (= 4 (length defn)) (= 5 (length defn))))) (sig (first defn)) (name (car sig)) (args (cdr sig)) (pred (lambda (x) (not (eqv? '#!key x)))) (params (drop-while pred args)) (params (if (null? params) params (cdr params))) (uri-args (take-while pred args)) (mutate-args (reverse (fold (lambda (arg args) (if (list? arg) (cons `(,(first arg) (,(second arg) ,(first arg))) args))) '() uri-args))) (uri-args (reverse (fold (lambda (arg args) (cons (if (list? arg) (first arg) arg) args)) '() uri-args))) (proc-args (reverse (fold (lambda (arg args) (cond ((symbol? arg) (cons arg args)) ((string? arg) args) (else (abort (conc "Cannot handle " arg))))) '() uri-args))) (uri/req (second defn)) (writer (third defn)) (reader (fourth defn)) (header-reader (if (= 5 (length defn)) (fifth defn) #f)) (proc-args (if writer `(,@proc-args body) `(,@proc-args))) (proc-args (if (not (null? params)) `(,@proc-args #!key ,@params) `(,@proc-args)))) ;(list 'quote `(define ,name (let* ((writer ,writer) ,@(if header-reader `((header-reader ,header-reader)) '()) (uri/req ,uri/req) (uri (cond ((request? uri/req) (request-uri uri/req)) ((uri? uri/req) uri/req) (else (uri-reference uri/req)))) (req (cond ((request? uri/req) uri/req) (else (make-request method: (if writer 'POST 'GET))))) ) (lambda ,proc-args (let* (,@(if (null? mutate-args) '() mutate-args) ,@(if (not (null? uri-args)) `((uri (update-uri uri path: (append (uri-path uri) (map ->string (list ,@uri-args))))) ;(_ (pp (uri-path uri))) ) '()) ,@(if (not (null? params)) `((uri (update-uri uri query: (append (uri-query uri) (list ,@(map (lambda (param) ``(,',param . ,(if ,param (->string ,param) ,param))) params)))))) '()) (req (update-request req uri: uri)) ) (fprintf (current-error-port) "\n\n\nREQUEST\n") (write-request (update-request req port: (current-error-port))) (fprintf (current-error-port) "\n") (receive (reader uri response) (call-with-input-request req ,(if writer '(writer body) #f) ,reader) ,(if header-reader '(values (header-reader (response-headers response)) reader (list uri response)) '(values reader (list uri response)))) )))) ;) )))) ) ----- (use http-client uri-common intarweb rest-bind medea) (define-method (account/info (path (lambda (arg) (string-append "hello-" path)))) "https://api.dropbox.com/1/account/info" #f read-json) (define-method (account/info (path (lambda (arg) (string-append "hello-" arg)))) "https://api.dropbox.com/1/account/info" #f read-json)
pp output pasted by C-Keen on Tue Oct 14 20:24:05 2014
#;6> (define-method (account/info (path (lambda (arg) (string-append "hello-" arg)))) "https://api.dropbox.com/1/account/info" #f read-json) '(define account/info963 (let* ((writer #f) (uri/req "https://api.dropbox.com/1/account/info") (uri (cond ((request? uri/req) (request-uri uri/req)) ((uri? uri/req) uri/req) (else (uri-reference uri/req)))) (req (cond ((request? uri/req) uri/req) (else (make-request method: (if writer 'POST 'GET)))))) (lambda (path964) (let* ((path964 ((lambda965 (arg966) (string-append967 "hello-" arg966)) path964)) (uri (update-uri uri path: (append (uri-path uri) (map ->string (list path964))))) (req (update-request req uri: uri))) (fprintf (current-error-port) "\n\n\nREQUEST\n") (write-request (update-request req port: (current-error-port))) (fprintf (current-error-port) "\n") (receive (reader uri response) (call-with-input-request req #f read-json968) (values reader (list uri response)))))))
csi pasted by andyjpb on Tue Oct 14 20:25:42 2014
$ csi CHICKEN (c) 2008-2014, The Chicken Team (c) 2000-2007, Felix L. Winkelmann Version 4.9.0rc1 (rev 3cf1967) linux-unix-gnu-x86-64 [ 64bit manyargs dload ptables ] compiled 2014-04-17 on hd-t1179cl (Linux) ; loading /home/local/andyjpb/.csirc ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/parley.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/chicken.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/data-structures.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/extras.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/ports.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/posix.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/srfi-1.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/srfi-13.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/srfi-18.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/stty.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/srfi-69.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/foreign.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/foreigners.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/parley.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/stty.so ... #;1> (use http-client uri-common intarweb rest-bind medea) ; loading /usr/local/chicken-4.9.0/lib/chicken/7/http-client.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/lolevel.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/files.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/tcp.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/intarweb.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/srfi-14.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/irregex.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/base64.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/defstruct.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/uri-common.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/matchable.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/uri-generic.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/srfi-4.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-primitive.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/type-checks.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/type-errors.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-type.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/blob-hexadecimal.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/to-hex.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/string-hexadecimal.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-parameters.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/variable-item.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-bv.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-support.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-int.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/blob-set-int.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-srfi-4.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-update-item.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/miscmacros.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-item.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/md5.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/string-utils.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/memoized-string.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/lookup-table.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/record-variants.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/unicode-utils.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/sendfile.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/rest-bind.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/medea.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/lazy-seq.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/comparse.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/latch.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/trie.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/http-client.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/intarweb.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/base64.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/defstruct.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/uri-common.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/matchable.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/uri-generic.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-primitive.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/type-checks.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/type-errors.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-type.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/blob-hexadecimal.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/to-hex.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/string-hexadecimal.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-parameters.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/variable-item.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-bv.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-support.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-int.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/blob-set-int.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-srfi-4.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-update-item.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/message-digest-item.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/md5.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/string-utils.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/memoized-string.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/lookup-table.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/unicode-utils.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/sendfile.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/openssl.import.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/openssl.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/rest-bind.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/medea.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/lazy-seq.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/comparse.so ... ; loading /usr/local/chicken-4.9.0/lib/chicken/7/trie.so ... #;2> (pp (define-method (account/info (path (lambda (arg) (string-append "hello-" path)))) "https://api.dropbox.com/1/account/info" #f read-json)) (define account/info (let* ((writer #f) (uri/req "https://api.dropbox.com/1/account/info") (uri (cond ((request? uri/req) (request-uri uri/req)) ((uri? uri/req) uri/req) (else (uri-reference uri/req)))) (req (cond ((request? uri/req) uri/req) (else (make-request method: (if writer 'POST 'GET)))))) (lambda (path) (let* ((path ((lambda (arg) (string-append "hello-" path)) path)) (uri (update-uri uri path: (append (uri-path uri) (map ->string (list path))))) (req (update-request req uri: uri))) (fprintf (current-error-port) "\n\n\nREQUEST\n") (write-request (update-request req port: (current-error-port))) (fprintf (current-error-port) "\n") (receive (reader uri response) (call-with-input-request req #f read-json) (values reader (list uri response))))))) #;3>
expand pasted by andyjpb on Tue Oct 14 20:31:08 2014
#;3> (pp (expand (define-method (account/info (path (lambda (arg) (string-append "hello-" path)))) "https://api.dropbox.com/1/account/info" #f read-json))) (##core#set! account/info (let* ((writer #f) (uri/req "https://api.dropbox.com/1/account/info") (uri (cond ((request? uri/req) (request-uri uri/req)) ((uri? uri/req) uri/req) (else (uri-reference uri/req)))) (req (cond ((request? uri/req) uri/req) (else (make-request method: (if writer 'POST 'GET)))))) (lambda (path) (let* ((path ((lambda (arg) (string-append "hello-" path)) path)) (uri (update-uri uri path: (append (uri-path uri) (map ->string (list path))))) (req (update-request req uri: uri))) (fprintf (current-error-port) "\n\n\nREQUEST\n") (write-request (update-request req port: (current-error-port))) (fprintf (current-error-port) "\n") (receive (reader uri response) (call-with-input-request req #f read-json) (values reader (list uri response)))))))
DSSSL-alike added by andyjpb on Tue Oct 14 20:59:40 2014
-a- (define-method (account/info (path (cut string-append "hello-" <>)) pos-arg-2 #!key (key-arg-1 (cut string-append "hi-" <>)) key-arg-2 (key-arg-3 "default")) "http://example.net/" #f read-json) -b- (define-method (account/info (path (cut string-append "hello-" <>)) pos-arg-2 #!key (key-arg-1 (cut string-append "hi-" <>)) key-arg-2 key-arg-3) "http://example.net/?key-arg-3=default" #f read-json)