aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Okay <okay@toyful.space>2022-02-12 10:51:27 -0600
committerColin Okay <okay@toyful.space>2022-02-12 10:51:27 -0600
commit46ce31534cf631eeb25963c759979fa4bf19f72b (patch)
tree030abfdab084b4dd5045837d7b5f52fe8e4e2c74
parent656377642153987217d50d41bf724ceabc90f7cd (diff)
bumped minor version. explicit support for query params in endpoints
-rw-r--r--lazybones.asd3
-rw-r--r--lazybones.lisp50
-rw-r--r--macros.lisp32
3 files changed, 52 insertions, 33 deletions
diff --git a/lazybones.asd b/lazybones.asd
index 7ed7adf..415b2c1 100644
--- a/lazybones.asd
+++ b/lazybones.asd
@@ -4,7 +4,7 @@
:description "http route handling"
:author "Colin Okay <okay@toyful.space>"
:license "AGPLv3"
- :version "0.2.0"
+ :version "0.3.0"
:serial t
:depends-on (#:alexandria
#:str
@@ -13,6 +13,7 @@
#:jonathan
#:lisp-namespace)
:components ((:file "package")
+ (:file "macros")
(:file "lazybones")
(:file "lazybones-documentation")))
diff --git a/lazybones.lisp b/lazybones.lisp
index c0f1550..03f6c70 100644
--- a/lazybones.lisp
+++ b/lazybones.lisp
@@ -114,6 +114,13 @@ app, named with the package name. If no app can be found, return NIL"
:reader endpoint-route
:initarg :route
:initform (error "endpoint route required"))
+ (params
+ :reader endpoint-params
+ :initarg :params
+ :initform nil
+ :documentation "A list of (SYMBOL-NAME FUNCTION-SYMBOL),
+ documenting the query parameters this endpoint expects. Used for
+ generating both documentation and client functions.")
(content-type
:reader endpoint-content-type
:initarg :content-type
@@ -309,6 +316,7 @@ any way to do it, hence NIL is returned."
(defmacro defendpoint
(appname method route
+ query-params
(&key
(auth nil)
content-type)
@@ -322,12 +330,16 @@ making a new one if not."
(a:with-gensyms (the-app auth-method)
(let* ((dispatch-pattern
(parse-route-string-template route))
- (params
+ (lambda-list
(mapcar 'intern (route-variables dispatch-pattern)))
(documentation
(when (stringp (first body)) (first body)))
+ (body-without-docstring
+ (if (stringp (first body)) (rest body) body))
(real-body
- (if (stringp (first body)) (rest body) body)))
+ (if query-params
+ `((map-parameters ,query-params ,@body-without-docstring))
+ body-without-docstring)))
`(let* ((,the-app
(or (app ',appname) (make-instance 'lazybones:app :name ',appname)))
(,auth-method
@@ -338,52 +350,26 @@ making a new one if not."
'lazybones:endpoint
:method ,method
:route ,route
+ :params ',query-params
:content-type ,content-type
:pattern ',dispatch-pattern
:doc ,documentation
:auth ,auth-method
:function
- (lambda ,params
+ (lambda ,lambda-list
(setf (lazybones:response-header :content-type)
(or ,content-type (lazybones::default-content-type ,the-app)))
,@real-body)))))))
-(defmacro defendpoint* (method route options &rest body)
+(defmacro defendpoint* (method route params options &rest body)
"Like DEFENDPOINT but uses the current package name as the app name."
- `(defendpoint ,(default-app-name) ,method ,route ,options ,@body))
+ `(defendpoint ,(default-app-name) ,method ,route ,params ,options ,@body))
;;; ENDPOINT HANDLING UTILITIES
-(defmacro let-parameters ((&rest names) &body body)
- "NAMES is a list of symbols. Binds the names to the value of the
-request parameters whose keys compare string-equal to the symbol-name
-of each NAME, or NIL if there is no such parameter."
- (let ((params (gensym)))
- `(let ((,params (lazybones:request-parameters)))
- (let ,(loop for name in names
- for string-name = (symbol-name name)
- collect `(,name (cdr (assoc ,string-name ,params :test #'string-equal))))
- ,@body))))
-
-(defmacro map-parameters ((&rest params) &body body)
- "PARAMS is a list of pairs (NAME PARSER). MAP-PARAMETERS behaves
-exactly like LET-PARAMETERS except that the values boudn to NAMEs are
-first mapped with the PARSER function."
- (assert (loop for (name parser) in params
- always (and (symbolp name)
- (or (symbolp parser) (functionp parser))))
- ()
- "Malformed PARAMS in MAP-PARAMETERS macro")
-
- (let ((names (mapcar #'car params)))
- `(let-parameters ,names
- (let ,(loop for name in names
- collect `(,name (when ,name (funcall ',(second (assoc name params)) ,name))))
- ,@body))))
-
(defun http-ok (content)
"Content should be a string, a byte-vector, or a pathname to a local
diff --git a/macros.lisp b/macros.lisp
new file mode 100644
index 0000000..3832296
--- /dev/null
+++ b/macros.lisp
@@ -0,0 +1,32 @@
+;;;; macros.lisp --- utility macros
+
+
+(in-package :lazybones)
+
+(defmacro let-parameters ((&rest names) &body body)
+ "NAMES is a list of symbols. Binds the names to the value of the
+request parameters whose keys compare string-equal to the symbol-name
+of each NAME, or NIL if there is no such parameter."
+ (let ((params (gensym)))
+ `(let ((,params (lazybones:request-parameters)))
+ (let ,(loop for name in names
+ for string-name = (symbol-name name)
+ collect `(,name (cdr (assoc ,string-name ,params :test #'string-equal))))
+ ,@body))))
+
+(defmacro map-parameters ((&rest params) &body body)
+ "PARAMS is a list of pairs (NAME PARSER). MAP-PARAMETERS behaves
+exactly like LET-PARAMETERS except that the values boudn to NAMEs are
+first mapped with the PARSER function."
+ (assert (loop for (name parser) in params
+ always (and (symbolp name)
+ (or (symbolp parser) (functionp parser))))
+ ()
+ "Malformed PARAMS in MAP-PARAMETERS macro")
+
+ (let ((names (mapcar #'car params)))
+ `(let-parameters ,names
+ (let ,(loop for name in names
+ collect `(,name (when ,name (funcall ',(second (assoc name params)) ,name))))
+ ,@body))))
+