From ab08f05c6b853ce970508d29aec68e36a40c08dc Mon Sep 17 00:00:00 2001 From: Colin Okay Date: Sun, 13 Feb 2022 07:32:00 -0600 Subject: renamed lazybones-test to lazybones-example --- example/lazybones-example-docs.md | 84 +++++++++++++++++++++++++ example/lazybones-example.lisp | 129 ++++++++++++++++++++++++++++++++++++++ example/lazybones-test-docs.md | 84 ------------------------- example/lazybones-test.lisp | 129 -------------------------------------- 4 files changed, 213 insertions(+), 213 deletions(-) create mode 100644 example/lazybones-example-docs.md create mode 100644 example/lazybones-example.lisp delete mode 100644 example/lazybones-test-docs.md delete mode 100644 example/lazybones-test.lisp diff --git a/example/lazybones-example-docs.md b/example/lazybones-example-docs.md new file mode 100644 index 0000000..281b98c --- /dev/null +++ b/example/lazybones-example-docs.md @@ -0,0 +1,84 @@ +# Lazybones Demo App - v0.0.0 + +Just an API that defines some endpoints. These + endpoints aren't meant to accomplish anything. Merely testing out + the lazybones HTTP routing framework. + +## Endpoints + +### POST /crapshoot +*text/plain* + +Authorization Required: + +> Randomly decides that the request is authorized + + + +Echos back 'You made it' if the request was authorized + +### POST /hello/:who: +*text/plain* + +Authorization Required: + +> Request is authorized if it contains the right TESTAPPSESSION +> cookie. Obtain such a cookie by posting to the /login endpoint. + + + +Route Variables: + +- WHO + + +Echo's back 'Hello WHO, I got your message BODY' where BODY is the post body. + +### GET /hello/:who: +*text/plain* + +Route Variables: + +- WHO + + +Echos back Hello WHO + +### POST /login +*text/plain* + +Dummy login endpoint for returning a session cookie. Always returns + the "true" and sends a set-cookie header, setting 'testappsession' + to 'coolsessionbro'. + +### GET /person/:person: +*application/json* + +Route Variables: + +- PERSON: ID of a person + + +Returns a json representation of the person. + +### GET /random/:lo:/:hi: +*text/plain* + +Route Variables: + +- LO: An Integer +- HI: An Integer + + +Echo back a random number between lo and hi + +### GET /search +*text/plain* + +Documented Query Parameters: + +- name: A String +- age: An Integer + + +Echo the search parameters in a nice list. \ No newline at end of file diff --git a/example/lazybones-example.lisp b/example/lazybones-example.lisp new file mode 100644 index 0000000..9300467 --- /dev/null +++ b/example/lazybones-example.lisp @@ -0,0 +1,129 @@ +(asdf:load-system "lazybones-hunchentoot") + +(defpackage #:lazybones-test + (:use #:cl) + (:local-nicknames (#:lzb #:lazybones)) + (:import-from #:lazybones + #:defendpoint* + #:http-ok + #:http-err)) + +(in-package :lazybones-test) + + +;; First make a server and add some custom error responses + +(defvar *server* (lzb:create-server :port 8888)) + +(defun custom-404 () + (format nil "~a wasn't found :o~%" (lzb:request-path))) ; can use request functiosn + +(defun custom-403 () + "You, in particular, can't do that. :P ") + +(defun custom-500 () + "Bah. Error.") + +(lzb:set-canned-response *server* 404 'custom-404 "text/plain" ) +(lzb:set-canned-response *server* 403 'custom-403 "text/plain" ) +(lzb:set-canned-response *server* 500 'custom-500 "text/plain") + +;; PPROVISION-APP makes an app. You can supply an optional name, a symbol. +;; In lieu of a supplied name, the name of the package is used as the app's name. +(lzb:provision-app () + :title "Lazybones Demo App" + :version "0.0.0" + :description "Just an API that defines some endpoints. These + endpoints aren't meant to accomplish anything. Merely testing out + the lazybones HTTP routing framework." + + :content-type "text/plain" ; default content type of server responses. + :auth 'post-authorizer) ; default authorizor for requests that need it + +(defun post-authorizer () + "Request is authorized if it contains the right TESTAPPSESSION + cookie. Obtain such a cookie by posting to the /login endpoint." + (string-equal "coolsessionbro" (lzb:request-cookie "testappsession"))) + +;; now we install the app to the server +(lzb:install-app *server* (lzb:app)) ; (app) is the default app for this package + +;; DEFENDPOINT* is a macro to define an endpoint and install it into the +;; app whose name is the current package anme. DEFENDPOINT (without the *) +;; allows you to explictly specify the app where the endpoint is installed. + +;; The general syntax is: DEFENDPOINT* HTTP-METHOD ROUTE-TEMPLATE QUERY-PARAMETERS OPTIONS DOCSTRING BODY ... + +(defendpoint* :post "/login" () () + "Dummy login endpoint for returning a session cookie. Always returns + the \"true\" and sends a set-cookie header, setting 'testappsession' + to 'coolsessionbro'." + (print (lzb:request-body)) ; dummy implementation, prints post body to stdout + (setf (lzb:response-cookie "testappsession") "coolsessionbro") + (http-ok "true")) + + +;; The next route defines a route variable WHO +(defendpoint* :get "/hello/:who:" () () + "Echos back Hello WHO" + (http-ok (format nil "Hello ~a~%" who))) ; use the route variable here + +(defendpoint* :post "/hello/:who:" () + (:auth t) ; use the app's default authorizor + "Echo's back 'Hello WHO, I got your message BODY' where BODY is the post body." + (print (lzb:request-header :content-type)) + (let ((body (lzb:request-body))) + (http-ok (format nil "Hello ~a, I got your message ~a~%" + who body)))) + +;; Some helpers, these are used to parse url variables and query +;; parameters. Their docstrings are used in the API documentation + +(defun int (string) + "An Integer" + (parse-integer string)) + +(defun str (string) + "A String" + string) + +;; In the following, two query parameters are specififed. NAME is +;; meant to be a string and AGE is an integer. If AGE is not an integer, +;; a 500 error will be returned. The syntax is (VAR PARSER) +(defendpoint* :get "/search" ((name str) (age int)) () + "Echo the search parameters in a nice list." + (http-ok (format nil "Name: ~a~%age: ~a~%" name age))) + +(defun crapshoot-authorizer () + "Randomly decides that the request is authorized" + (< 5 (random 10))) + +(defendpoint* :post "/crapshoot" () + (:auth 'crapshoot-authorizer) ; use a custom authorizer + "Echos back 'You made it' if the request was authorized" + (http-ok "You made it")) + +;; Route variables can accept parsers / preformatters +;; these will parse a value and supply it to the argument of the handler. +(defendpoint* :get "/random/:lo int:/:hi int:" () () + "Echo back a random number between lo and hi" + (if (< lo hi) + (http-ok + (format nil "The number is: ~a~%" + (+ lo (random (- hi lo))))) + (http-err 404))) ; Can't find a number X such that LO >= HI and LO < X < HI + +(defun person-by-id (id) + "ID of a person" + ;; The real thing might perform some database operation here. If the + ;; operation failed, an error could be signalled, in which case a + ;; 500 response would be sent to the client. + (list :name "Colin" :occupation "Macrologist" :id (parse-integer id))) + + +(defendpoint* :get "/person/:person person-by-id:" () + (:content-type "application/json") ; override the app's default content type for HTTP responses + "Returns a json representation of the person." + (http-ok + (jonathan:to-json person))) + diff --git a/example/lazybones-test-docs.md b/example/lazybones-test-docs.md deleted file mode 100644 index 281b98c..0000000 --- a/example/lazybones-test-docs.md +++ /dev/null @@ -1,84 +0,0 @@ -# Lazybones Demo App - v0.0.0 - -Just an API that defines some endpoints. These - endpoints aren't meant to accomplish anything. Merely testing out - the lazybones HTTP routing framework. - -## Endpoints - -### POST /crapshoot -*text/plain* - -Authorization Required: - -> Randomly decides that the request is authorized - - - -Echos back 'You made it' if the request was authorized - -### POST /hello/:who: -*text/plain* - -Authorization Required: - -> Request is authorized if it contains the right TESTAPPSESSION -> cookie. Obtain such a cookie by posting to the /login endpoint. - - - -Route Variables: - -- WHO - - -Echo's back 'Hello WHO, I got your message BODY' where BODY is the post body. - -### GET /hello/:who: -*text/plain* - -Route Variables: - -- WHO - - -Echos back Hello WHO - -### POST /login -*text/plain* - -Dummy login endpoint for returning a session cookie. Always returns - the "true" and sends a set-cookie header, setting 'testappsession' - to 'coolsessionbro'. - -### GET /person/:person: -*application/json* - -Route Variables: - -- PERSON: ID of a person - - -Returns a json representation of the person. - -### GET /random/:lo:/:hi: -*text/plain* - -Route Variables: - -- LO: An Integer -- HI: An Integer - - -Echo back a random number between lo and hi - -### GET /search -*text/plain* - -Documented Query Parameters: - -- name: A String -- age: An Integer - - -Echo the search parameters in a nice list. \ No newline at end of file diff --git a/example/lazybones-test.lisp b/example/lazybones-test.lisp deleted file mode 100644 index 9300467..0000000 --- a/example/lazybones-test.lisp +++ /dev/null @@ -1,129 +0,0 @@ -(asdf:load-system "lazybones-hunchentoot") - -(defpackage #:lazybones-test - (:use #:cl) - (:local-nicknames (#:lzb #:lazybones)) - (:import-from #:lazybones - #:defendpoint* - #:http-ok - #:http-err)) - -(in-package :lazybones-test) - - -;; First make a server and add some custom error responses - -(defvar *server* (lzb:create-server :port 8888)) - -(defun custom-404 () - (format nil "~a wasn't found :o~%" (lzb:request-path))) ; can use request functiosn - -(defun custom-403 () - "You, in particular, can't do that. :P ") - -(defun custom-500 () - "Bah. Error.") - -(lzb:set-canned-response *server* 404 'custom-404 "text/plain" ) -(lzb:set-canned-response *server* 403 'custom-403 "text/plain" ) -(lzb:set-canned-response *server* 500 'custom-500 "text/plain") - -;; PPROVISION-APP makes an app. You can supply an optional name, a symbol. -;; In lieu of a supplied name, the name of the package is used as the app's name. -(lzb:provision-app () - :title "Lazybones Demo App" - :version "0.0.0" - :description "Just an API that defines some endpoints. These - endpoints aren't meant to accomplish anything. Merely testing out - the lazybones HTTP routing framework." - - :content-type "text/plain" ; default content type of server responses. - :auth 'post-authorizer) ; default authorizor for requests that need it - -(defun post-authorizer () - "Request is authorized if it contains the right TESTAPPSESSION - cookie. Obtain such a cookie by posting to the /login endpoint." - (string-equal "coolsessionbro" (lzb:request-cookie "testappsession"))) - -;; now we install the app to the server -(lzb:install-app *server* (lzb:app)) ; (app) is the default app for this package - -;; DEFENDPOINT* is a macro to define an endpoint and install it into the -;; app whose name is the current package anme. DEFENDPOINT (without the *) -;; allows you to explictly specify the app where the endpoint is installed. - -;; The general syntax is: DEFENDPOINT* HTTP-METHOD ROUTE-TEMPLATE QUERY-PARAMETERS OPTIONS DOCSTRING BODY ... - -(defendpoint* :post "/login" () () - "Dummy login endpoint for returning a session cookie. Always returns - the \"true\" and sends a set-cookie header, setting 'testappsession' - to 'coolsessionbro'." - (print (lzb:request-body)) ; dummy implementation, prints post body to stdout - (setf (lzb:response-cookie "testappsession") "coolsessionbro") - (http-ok "true")) - - -;; The next route defines a route variable WHO -(defendpoint* :get "/hello/:who:" () () - "Echos back Hello WHO" - (http-ok (format nil "Hello ~a~%" who))) ; use the route variable here - -(defendpoint* :post "/hello/:who:" () - (:auth t) ; use the app's default authorizor - "Echo's back 'Hello WHO, I got your message BODY' where BODY is the post body." - (print (lzb:request-header :content-type)) - (let ((body (lzb:request-body))) - (http-ok (format nil "Hello ~a, I got your message ~a~%" - who body)))) - -;; Some helpers, these are used to parse url variables and query -;; parameters. Their docstrings are used in the API documentation - -(defun int (string) - "An Integer" - (parse-integer string)) - -(defun str (string) - "A String" - string) - -;; In the following, two query parameters are specififed. NAME is -;; meant to be a string and AGE is an integer. If AGE is not an integer, -;; a 500 error will be returned. The syntax is (VAR PARSER) -(defendpoint* :get "/search" ((name str) (age int)) () - "Echo the search parameters in a nice list." - (http-ok (format nil "Name: ~a~%age: ~a~%" name age))) - -(defun crapshoot-authorizer () - "Randomly decides that the request is authorized" - (< 5 (random 10))) - -(defendpoint* :post "/crapshoot" () - (:auth 'crapshoot-authorizer) ; use a custom authorizer - "Echos back 'You made it' if the request was authorized" - (http-ok "You made it")) - -;; Route variables can accept parsers / preformatters -;; these will parse a value and supply it to the argument of the handler. -(defendpoint* :get "/random/:lo int:/:hi int:" () () - "Echo back a random number between lo and hi" - (if (< lo hi) - (http-ok - (format nil "The number is: ~a~%" - (+ lo (random (- hi lo))))) - (http-err 404))) ; Can't find a number X such that LO >= HI and LO < X < HI - -(defun person-by-id (id) - "ID of a person" - ;; The real thing might perform some database operation here. If the - ;; operation failed, an error could be signalled, in which case a - ;; 500 response would be sent to the client. - (list :name "Colin" :occupation "Macrologist" :id (parse-integer id))) - - -(defendpoint* :get "/person/:person person-by-id:" () - (:content-type "application/json") ; override the app's default content type for HTTP responses - "Returns a json representation of the person." - (http-ok - (jonathan:to-json person))) - -- cgit v1.2.3