blob: 2f15a53ee783761f866c4dfbfefff8ffde860965 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
;;;; lazybones.lisp
(in-package #:lazybones)
(defgeneric handle-request (what request)
(:documentation "Implemented for APP and ENDPOINT instances."))
(defclass app ()
((name
:reader app-name
:initarg :name
:initform (error "Appname is required")
:type symbol)
(version
:reader app-version
:initarg :vsn :initarg :version
:initform "0.0.1"
:type string)
(root
:reader app-root
:initarg :root
:initform "/"
:type string)
(default-request-authorizer
:initarg :default-authorizier :initarg :auth-with
:initform nil)
(default-http-responders
:initarg :default-responders
:initform nil
:documentation "A PLIST with keys being integers that represent
HTTP response codes and with values that are symbols naming
responder functions.")
(routes
:accessor app-routes
:initform nil)))
(defgeneric dispatch-handler-p (endpoint request)
(:documentation "T if ENDPOINT should handle REQUEST, NIL otherwise"))
(defclass endpoint ()
((method :reader endpoint-method :initarg :method :initform :get)
(template :reader endpoint-template :initarg :template :initform (error "endpoint template required"))
(dispatch-pattern :reader endpoint-dispatch-pattern)
(handler-function :reader endpoint-request-handler)
(documentation :reader endpoint-documentation :initarg :doc :initform "")))
(defparameter +http-methods+
(list :get :head :put :post :delete :patch))
(defun parse-route-string-template (template)
"Routes are of the form
/foo/bar/<<variable>>/blah
/foo/bar/<<var parse-integer>>/blah
On success returns things like:
(\"foo\" \"bar\" (VARIABLE) \"blah\")
(\"foo\" \"bar\" (VAR PARSE-INTEGER) \"blah\")
Returns NIL on failure"
(when (stringp template)
(cond ((equal "" template) nil)
(t
(loop for field in (str:split #\/ template)
for var? = (parse-route-variable-string field)
when var?
collect var?
else
collect (string-downcase field))))))
(defun parse-route-variable-string (string)
"A route variable string looks like <<foo>> or <<foo bar>>
In the case of a successful parse, a list of one or two symbols is
returned. These symbosl are created using read-from-string, which
allows for these symbols' packages to be specified if desired.
Returns NIL on failre."
(when (and (a:starts-with-subseq "<<" string)
(a:ends-with-subseq ">>" string))
(destructuring-bind
(var-name . decoder?)
(re:split " +"
(string-trim " " (subseq string 2 (- (length string) 2))))
(if decoder?
(list (read-from-string var-name) (read-from-string (first decoder?)))
(list (read-from-string var-name))))))
;; (defun add-route (method routestring handler-function)
;; (assert (member method +http-methods+) nil
;; "~a is not a valid HTTP method indicator."
;; method)
;; )
|