Skip to content

Commit

Permalink
Fix #7 Expose path-parameter function to get path parameter from URI
Browse files Browse the repository at this point in the history
  • Loading branch information
Johnny Ruiz committed Aug 20, 2023
1 parent 9c72da3 commit bf1667c
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.org
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
(define-get "/" () ; (2)
(ok "alive")) ; (3)
(define-get "/accounts/:account-id" (request) ; (4)
(let ((account-id (path-param request :account-id))) ; (5)
(let ((account-id (path-parameter request :account-id))) ; (5)
(ok (format nil "Your account id: ~a." account-id)))) ; (6)
(define-any "*" () ; (7)
(not-found "not-found"))) ; (8)
Expand Down
24 changes: 20 additions & 4 deletions src/middleware/path-template.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
#:scan-to-strings)
(:import-from :tiny-routes.request
#:request-append
#:request-get
#:path-info)
(:import-from :tiny-routes.util
#:compose)
(:export #:wrap-request-path-info-matcher
(:export #:path-parameter
#:with-path-parameters
#:wrap-request-path-info-matcher
#:wrap-request-matches-path-template))

(in-package :tiny-routes.middleware.path-template)
Expand Down Expand Up @@ -87,15 +90,16 @@ then it is made available to the request under `:path-parameters'."
"Wrap HANDLER such that it is called only if the request path matches
the PATH-TEMPLATE.
If PATH-TEMPLATE is t, nil, or an empty string, then return HANDLER
unchanged.
If PATH-TEMPLATE is t, nil, the empty string, or \"*\", then return
HANDLER unchanged.
If REGEX is non-nil, then interpret path-template as a regular
expression."
(check-type path-template (or symbol string))
(cond ((or (null path-template)
(eq path-template t)
(string= path-template ""))
(string= path-template "")
(string= path-template "*"))
handler)
;; If regex is non-nil, then interpret path-info as a regex
(regex
Expand All @@ -105,3 +109,15 @@ expression."
(wrap-request-path-info-matcher handler (make-path-template-keyword-matcher path-template)))
(t
(wrap-request-path-info-matcher handler (make-path-template-exact-matcher path-template)))))

(defun path-parameter (request path-parameter &optional default)
"Return the value mapped to PATH-PARAMETER from REQUEST or DEFAULT."
(getf (getf request :path-parameters) path-parameter default))

(defmacro with-path-parameters (vars path-parameters &body body)
"Bind the variables in VARS to the corresponding values present in
PATH-PARAMETERS."
(let ((gpath-parameters (gensym "path-parameters")))
`(let* ((,gpath-parameters ,path-parameters))
(destructuring-bind (&key ,@vars &allow-other-keys) ,gpath-parameters
,@body))))
34 changes: 34 additions & 0 deletions t/tiny-routes-test.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,37 @@
(is (null (funcall (define-post "/bar" () response) request)))
(is (equalp response (funcall (define-post "/foo" () response) request)))
(is (equalp response (funcall (define-post "/:foo" () response) request)))))

(test route-matching1
(let ((request (mock-request :get "/accounts/A123/users/U42"))
(ok-response (make-response :status 200 :body "OK"))
(expected (list "A123" "U42")))
(is (equalp ok-response (funcall (define-any "*" () ok-response) request)))
(is (equalp expected
(funcall (define-get "/accounts/:account-id/users/:user-id" (request)
(let ((account-id (path-parameter request :account-id))
(user-id (path-parameter request :user-id)))
(list account-id user-id)))
request)))
(is (equalp expected
(funcall (define-get "/accounts/:account-id/users/:user-id" (request)
(with-request (path-parameters) request
(with-path-parameters (account-id user-id) path-parameters
(list account-id user-id))))
request)))))

(test readme-example
(let ((app (routes
(define-get "/" ()
(ok "alive"))
(define-get "/accounts/:account-id" (request)
(let ((account-id (path-parameter request :account-id)))
(ok (format nil "Your account id: ~a." account-id))))
(define-any "*" ()
(not-found "not-found")))))
(is (equalp '(200 NIL ("alive"))
(funcall app (mock-request :get "/"))))
(is (equalp '(200 NIL ("Your account id: A123."))
(funcall app (mock-request :get "/accounts/A123"))))
(is (equalp '(404 NIL ("not-found"))
(funcall app (mock-request :get "/unknown"))))))

0 comments on commit bf1667c

Please # to comment.