Skip to content

Commit bf1667c

Browse files
author
Johnny Ruiz
committed
Fix #7 Expose path-parameter function to get path parameter from URI
1 parent 9c72da3 commit bf1667c

3 files changed

Lines changed: 55 additions & 5 deletions

File tree

README.org

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
(define-get "/" () ; (2)
8484
(ok "alive")) ; (3)
8585
(define-get "/accounts/:account-id" (request) ; (4)
86-
(let ((account-id (path-param request :account-id))) ; (5)
86+
(let ((account-id (path-parameter request :account-id))) ; (5)
8787
(ok (format nil "Your account id: ~a." account-id)))) ; (6)
8888
(define-any "*" () ; (7)
8989
(not-found "not-found"))) ; (8)

src/middleware/path-template.lisp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
#:scan-to-strings)
1111
(:import-from :tiny-routes.request
1212
#:request-append
13+
#:request-get
1314
#:path-info)
1415
(:import-from :tiny-routes.util
1516
#:compose)
16-
(:export #:wrap-request-path-info-matcher
17+
(:export #:path-parameter
18+
#:with-path-parameters
19+
#:wrap-request-path-info-matcher
1720
#:wrap-request-matches-path-template))
1821

1922
(in-package :tiny-routes.middleware.path-template)
@@ -87,15 +90,16 @@ then it is made available to the request under `:path-parameters'."
8790
"Wrap HANDLER such that it is called only if the request path matches
8891
the PATH-TEMPLATE.
8992
90-
If PATH-TEMPLATE is t, nil, or an empty string, then return HANDLER
91-
unchanged.
93+
If PATH-TEMPLATE is t, nil, the empty string, or \"*\", then return
94+
HANDLER unchanged.
9295
9396
If REGEX is non-nil, then interpret path-template as a regular
9497
expression."
9598
(check-type path-template (or symbol string))
9699
(cond ((or (null path-template)
97100
(eq path-template t)
98-
(string= path-template ""))
101+
(string= path-template "")
102+
(string= path-template "*"))
99103
handler)
100104
;; If regex is non-nil, then interpret path-info as a regex
101105
(regex
@@ -105,3 +109,15 @@ expression."
105109
(wrap-request-path-info-matcher handler (make-path-template-keyword-matcher path-template)))
106110
(t
107111
(wrap-request-path-info-matcher handler (make-path-template-exact-matcher path-template)))))
112+
113+
(defun path-parameter (request path-parameter &optional default)
114+
"Return the value mapped to PATH-PARAMETER from REQUEST or DEFAULT."
115+
(getf (getf request :path-parameters) path-parameter default))
116+
117+
(defmacro with-path-parameters (vars path-parameters &body body)
118+
"Bind the variables in VARS to the corresponding values present in
119+
PATH-PARAMETERS."
120+
(let ((gpath-parameters (gensym "path-parameters")))
121+
`(let* ((,gpath-parameters ,path-parameters))
122+
(destructuring-bind (&key ,@vars &allow-other-keys) ,gpath-parameters
123+
,@body))))

t/tiny-routes-test.lisp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,37 @@
120120
(is (null (funcall (define-post "/bar" () response) request)))
121121
(is (equalp response (funcall (define-post "/foo" () response) request)))
122122
(is (equalp response (funcall (define-post "/:foo" () response) request)))))
123+
124+
(test route-matching1
125+
(let ((request (mock-request :get "/accounts/A123/users/U42"))
126+
(ok-response (make-response :status 200 :body "OK"))
127+
(expected (list "A123" "U42")))
128+
(is (equalp ok-response (funcall (define-any "*" () ok-response) request)))
129+
(is (equalp expected
130+
(funcall (define-get "/accounts/:account-id/users/:user-id" (request)
131+
(let ((account-id (path-parameter request :account-id))
132+
(user-id (path-parameter request :user-id)))
133+
(list account-id user-id)))
134+
request)))
135+
(is (equalp expected
136+
(funcall (define-get "/accounts/:account-id/users/:user-id" (request)
137+
(with-request (path-parameters) request
138+
(with-path-parameters (account-id user-id) path-parameters
139+
(list account-id user-id))))
140+
request)))))
141+
142+
(test readme-example
143+
(let ((app (routes
144+
(define-get "/" ()
145+
(ok "alive"))
146+
(define-get "/accounts/:account-id" (request)
147+
(let ((account-id (path-parameter request :account-id)))
148+
(ok (format nil "Your account id: ~a." account-id))))
149+
(define-any "*" ()
150+
(not-found "not-found")))))
151+
(is (equalp '(200 NIL ("alive"))
152+
(funcall app (mock-request :get "/"))))
153+
(is (equalp '(200 NIL ("Your account id: A123."))
154+
(funcall app (mock-request :get "/accounts/A123"))))
155+
(is (equalp '(404 NIL ("not-found"))
156+
(funcall app (mock-request :get "/unknown"))))))

0 commit comments

Comments
 (0)