Browse code
documentation: finish documenting routing
Ed Langley authored on 30/08/2019 07:15:55
Showing 3 changed files
Showing 3 changed files
... | ... |
@@ -132,6 +132,22 @@ |
132 | 132 |
sequence of endpoint descriptions which contain nested definitions |
133 | 133 |
for HTTP verbs and expands to ningle's functions for manipulating |
134 | 134 |
routes. |
135 |
+ |
|
136 |
+ #+NAME: defroutes |
|
137 |
+ #+BEGIN_SRC lisp |
|
138 |
+ (defmacro defroutes (app &body routes) |
|
139 |
+ (alexandria:once-only (app) |
|
140 |
+ `(setf |
|
141 |
+ ,@(loop for (target . descriptors) in routes |
|
142 |
+ append (loop for (method callback) in descriptors |
|
143 |
+ append `((ningle:route ,app ,target |
|
144 |
+ :method method) |
|
145 |
+ ,callback)))))) |
|
146 |
+ #+END_SRC |
|
147 |
+ |
|
148 |
+ This macro organizes all the HTTP verbs for a given endpoint under |
|
149 |
+ the path to that endpoint. A more complete version might allow for |
|
150 |
+ a list of verbs =(:GET :POST)= in the head of each handler clause. |
|
135 | 151 |
|
136 | 152 |
#+BEGIN_SRC lisp :exports both :tangle no :results verbatim |
137 | 153 |
(macroexpand-1 |
... | ... |
@@ -141,6 +157,7 @@ |
141 | 157 |
(:POST (handler (v) (new-todo v))) |
142 | 158 |
(:DELETE (handler () (clear-todos)))))) |
143 | 159 |
#+END_SRC |
160 |
+ |
|
144 | 161 |
|
145 | 162 |
#+RESULTS: |
146 | 163 |
#+begin_example |
... | ... |
@@ -156,20 +173,16 @@ |
156 | 173 |
(CLEAR-TODOS)))) |
157 | 174 |
T |
158 | 175 |
#+end_example |
176 |
+ |
|
177 |
+ Finally, there are some simple helpers to handle some of the |
|
178 |
+ boilerplate in a clack webserver. Of particular interest is the |
|
179 |
+ =handler= macro, which (since this is a json-only API) makes sure |
|
180 |
+ that all the API results get JSON encoded. |
|
159 | 181 |
|
160 | 182 |
#+NAME: routing-helpers |
161 | 183 |
#+BEGIN_SRC lisp |
162 |
- (defmacro defroutes (app &body routes) |
|
163 |
- (alexandria:once-only (app) |
|
164 |
- `(setf |
|
165 |
- ,@(loop for (target . descriptors) in routes |
|
166 |
- append (loop for (method callback) in descriptors |
|
167 |
- append `((ningle:route ,app ,target |
|
168 |
- :method method) |
|
169 |
- ,callback)))))) |
|
170 |
- |
|
171 | 184 |
(defun success (value) |
172 |
- (list 200 nil value)) |
|
185 |
+ (list 200 '(:conent-type "application/json") value)) |
|
173 | 186 |
|
174 | 187 |
(defmacro handler ((&optional (sym (gensym "PARAMS"))) &body body) |
175 | 188 |
`(lambda (,sym) |
... | ... |
@@ -177,7 +190,36 @@ |
177 | 190 |
(success |
178 | 191 |
(fwoar.lack.json.middleware:wrap-result |
179 | 192 |
(progn ,@body))))) |
180 |
- #+end_SRC |
|
193 |
+ #+END_SRC |
|
194 |
+ |
|
195 |
+** todo routes |
|
196 |
+ |
|
197 |
+ =setup-routes= binds the endpoints to handlers: "/" to handlers |
|
198 |
+ that handle the todo lists while "/todo/:id" to handlers that |
|
199 |
+ handle individual todos. The =:id= indicates that the |
|
200 |
+ corresponding segment of the path is bound to =:id= in the param |
|
201 |
+ alist. =get-id= handles this, and extracts an integer for the id |
|
202 |
+ (since we are using successive integers for the todo ids). |
|
203 |
+ |
|
204 |
+ #+NAME: todo-routes |
|
205 |
+ #+BEGIN_SRC lisp |
|
206 |
+ ;; routing |
|
207 |
+ (defun get-id (params) |
|
208 |
+ (parse-integer (serapeum:assocdr :id params))) |
|
209 |
+ |
|
210 |
+ (defun setup-routes (app) |
|
211 |
+ (defroutes app |
|
212 |
+ ("/" (:GET (handler () (todos))) |
|
213 |
+ (:POST (handler (v) (new-todo v))) |
|
214 |
+ (:DELETE (handler () (clear-todos)))) |
|
215 |
+ ("/todo/:id" (:GET (handler (v) (todo (get-id v)))) |
|
216 |
+ (:DELETE (handler (v) |
|
217 |
+ (delete-todo (get-id v)) |
|
218 |
+ nil)) |
|
219 |
+ (:PATCH (handler (v) |
|
220 |
+ (update-todo (get-id v) |
|
221 |
+ (remove :id v :key #'car))))))) |
|
222 |
+ #+END_SRC |
|
181 | 223 |
|
182 | 224 |
* Source |
183 | 225 |
** model.lisp source code |
... | ... |
@@ -206,24 +248,11 @@ |
206 | 248 |
#+BEGIN_SRC lisp :tangle routing.lisp :noweb yes :comments noweb |
207 | 249 |
<<package-include>> |
208 | 250 |
|
209 |
- <<routing-helpers>> |
|
251 |
+ <<defroutes>> |
|
210 | 252 |
|
211 |
- ;; routing |
|
212 |
- (defun get-id (params) |
|
213 |
- (parse-integer (serapeum:assocdr :id params))) |
|
253 |
+ <<routing-helpers>> |
|
214 | 254 |
|
215 |
- (defun setup-routes (app) |
|
216 |
- (defroutes app |
|
217 |
- ("/" (:GET (handler () (todos))) |
|
218 |
- (:POST (handler (v) (new-todo v))) |
|
219 |
- (:DELETE (handler () (clear-todos)))) |
|
220 |
- ("/todo/:id" (:GET (handler (v) (todo (get-id v)))) |
|
221 |
- (:DELETE (handler (v) |
|
222 |
- (delete-todo (get-id v)) |
|
223 |
- nil)) |
|
224 |
- (:PATCH (handler (v) |
|
225 |
- (update-todo (get-id v) |
|
226 |
- (remove :id v :key #'car))))))) |
|
255 |
+ <<todo-routes>> |
|
227 | 256 |
#+END_SRC |
228 | 257 |
|
229 | 258 |
** main.lisp source |
... | ... |
@@ -3,7 +3,7 @@ |
3 | 3 |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
4 | 4 |
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> |
5 | 5 |
<head> |
6 |
-<!-- 2019-08-30 Fri 02:00 --> |
|
6 |
+<!-- 2019-08-30 Fri 02:15 --> |
|
7 | 7 |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> |
8 | 8 |
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
9 | 9 |
<title>TODO backend implementation using CL and fukamachi/ningle</title> |
... | ... |
@@ -285,33 +285,34 @@ for the JavaScript code in this tag. |
285 | 285 |
<h2>Table of Contents</h2> |
286 | 286 |
<div id="text-table-of-contents"> |
287 | 287 |
<ul> |
288 |
-<li><a href="#orgf719c2d">1. Setup</a></li> |
|
289 |
-<li><a href="#org5024541">2. todo API</a> |
|
288 |
+<li><a href="#org2b6564f">1. Setup</a></li> |
|
289 |
+<li><a href="#org152326b">2. todo API</a> |
|
290 | 290 |
<ul> |
291 |
-<li><a href="#org066a36a">2.1. List-level APIs</a></li> |
|
292 |
-<li><a href="#org8f0d41e">2.2. Getting/Replacing a todo</a></li> |
|
293 |
-<li><a href="#org5e267ef">2.3. Adding and modifying todos</a></li> |
|
294 |
-<li><a href="#org856ed57">2.4. Examples</a></li> |
|
291 |
+<li><a href="#org006b1f9">2.1. List-level APIs</a></li> |
|
292 |
+<li><a href="#orge19ce57">2.2. Getting/Replacing a todo</a></li> |
|
293 |
+<li><a href="#orgf298702">2.3. Adding and modifying todos</a></li> |
|
294 |
+<li><a href="#orgd0dd01c">2.4. Examples</a></li> |
|
295 | 295 |
</ul> |
296 | 296 |
</li> |
297 |
-<li><a href="#org8f02b65">3. Routing</a> |
|
297 |
+<li><a href="#org42229a6">3. Routing</a> |
|
298 | 298 |
<ul> |
299 |
-<li><a href="#org93dcda5">3.1. Routing utilities</a></li> |
|
299 |
+<li><a href="#org84376ba">3.1. Routing utilities</a></li> |
|
300 |
+<li><a href="#orgb1f34fd">3.2. todo routes</a></li> |
|
300 | 301 |
</ul> |
301 | 302 |
</li> |
302 |
-<li><a href="#orgdec30ec">4. Source</a> |
|
303 |
+<li><a href="#org7d68735">4. Source</a> |
|
303 | 304 |
<ul> |
304 |
-<li><a href="#org1cf20cf">4.1. model.lisp source code</a></li> |
|
305 |
-<li><a href="#orgbce9205">4.2. routing.lisp source</a></li> |
|
306 |
-<li><a href="#orgc91e7f6">4.3. main.lisp source</a></li> |
|
305 |
+<li><a href="#org8b89d94">4.1. model.lisp source code</a></li> |
|
306 |
+<li><a href="#org031a2d2">4.2. routing.lisp source</a></li> |
|
307 |
+<li><a href="#org04fe926">4.3. main.lisp source</a></li> |
|
307 | 308 |
</ul> |
308 | 309 |
</li> |
309 | 310 |
</ul> |
310 | 311 |
</div> |
311 | 312 |
</div> |
312 | 313 |
|
313 |
-<div id="outline-container-orgf719c2d" class="outline-2"> |
|
314 |
-<h2 id="orgf719c2d"><span class="section-number-2">1</span> Setup</h2> |
|
314 |
+<div id="outline-container-org2b6564f" class="outline-2"> |
|
315 |
+<h2 id="org2b6564f"><span class="section-number-2">1</span> Setup</h2> |
|
315 | 316 |
<div class="outline-text-2" id="text-1"> |
316 | 317 |
<ul class="org-ul"> |
317 | 318 |
<li><code class="src src-sh">git clone https://github.com/fiddlerwoaroof/data-lens.git ~/quicklisp/local-projects/data-lens</code></li> |
... | ... |
@@ -331,8 +332,8 @@ After this, all the tests <a href="http://www.todobackend.com/specs/index.html?h |
331 | 332 |
</div> |
332 | 333 |
</div> |
333 | 334 |
|
334 |
-<div id="outline-container-org5024541" class="outline-2"> |
|
335 |
-<h2 id="org5024541"><span class="section-number-2">2</span> todo API</h2> |
|
335 |
+<div id="outline-container-org152326b" class="outline-2"> |
|
336 |
+<h2 id="org152326b"><span class="section-number-2">2</span> todo API</h2> |
|
336 | 337 |
<div class="outline-text-2" id="text-2"> |
337 | 338 |
<p> |
338 | 339 |
We use a fairly simple structure for our "database": a fset map (a |
... | ... |
@@ -342,8 +343,8 @@ referenced as <code>*todo*</code>, but this is a detail hidden behind the API. |
342 | 343 |
</p> |
343 | 344 |
</div> |
344 | 345 |
|
345 |
-<div id="outline-container-org066a36a" class="outline-3"> |
|
346 |
-<h3 id="org066a36a"><span class="section-number-3">2.1</span> List-level APIs</h3> |
|
346 |
+<div id="outline-container-org006b1f9" class="outline-3"> |
|
347 |
+<h3 id="org006b1f9"><span class="section-number-3">2.1</span> List-level APIs</h3> |
|
347 | 348 |
<div class="outline-text-3" id="text-2-1"> |
348 | 349 |
<p> |
349 | 350 |
These are functions for getting the todo list and clearing |
... | ... |
@@ -352,7 +353,7 @@ and <code>clear-todos</code> for DELETE requests. |
352 | 353 |
</p> |
353 | 354 |
|
354 | 355 |
<div class="org-src-container"> |
355 |
-<pre class="src src-lisp" id="orgb828d62"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">todos</span> <span style="color: #93a8c6;">()</span> |
|
356 |
+<pre class="src src-lisp" id="org8067877"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">todos</span> <span style="color: #93a8c6;">()</span> |
|
356 | 357 |
<span style="color: #93a8c6;">(</span>gmap:gmap <span style="font-weight: bold;">:seq</span> |
357 | 358 |
<span style="color: #b0b1a3;">(</span><span style="color: #F0DFAF;">lambda</span> <span style="color: #97b098;">(</span>_ b<span style="color: #97b098;">)</span> |
358 | 359 |
<span style="color: #97b098;">(</span><span style="color: #F0DFAF;">declare</span> <span style="color: #aebed8;">(</span>ignore _<span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> |
... | ... |
@@ -367,8 +368,8 @@ and <code>clear-todos</code> for DELETE requests. |
367 | 368 |
</div> |
368 | 369 |
</div> |
369 | 370 |
|
370 |
-<div id="outline-container-org8f0d41e" class="outline-3"> |
|
371 |
-<h3 id="org8f0d41e"><span class="section-number-3">2.2</span> Getting/Replacing a todo</h3> |
|
371 |
+<div id="outline-container-orge19ce57" class="outline-3"> |
|
372 |
+<h3 id="orge19ce57"><span class="section-number-3">2.2</span> Getting/Replacing a todo</h3> |
|
372 | 373 |
<div class="outline-text-3" id="text-2-2"> |
373 | 374 |
<p> |
374 | 375 |
This uses lisp's <a href="http://www.lispworks.com/documentation/HyperSpec/Body/05_a.htm">generalized references</a> to abstract away the |
... | ... |
@@ -378,7 +379,7 @@ the GET request for a specific todo by id. |
378 | 379 |
</p> |
379 | 380 |
|
380 | 381 |
<div class="org-src-container"> |
381 |
-<pre class="src src-lisp" id="org160aa97"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">todo</span> <span style="color: #93a8c6;">(</span>id<span style="color: #93a8c6;">)</span> |
|
382 |
+<pre class="src src-lisp" id="orga61555f"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">todo</span> <span style="color: #93a8c6;">(</span>id<span style="color: #93a8c6;">)</span> |
|
382 | 383 |
<span style="color: #93a8c6;">(</span><span style="color: #F0DFAF;">let</span> <span style="color: #b0b1a3;">(</span><span style="color: #97b098;">(</span>todo <span style="color: #aebed8;">(</span>fset:@ *todos* id<span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span> |
383 | 384 |
todo<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
384 | 385 |
|
... | ... |
@@ -394,8 +395,8 @@ the GET request for a specific todo by id. |
394 | 395 |
</div> |
395 | 396 |
</div> |
396 | 397 |
|
397 |
-<div id="outline-container-org5e267ef" class="outline-3"> |
|
398 |
-<h3 id="org5e267ef"><span class="section-number-3">2.3</span> Adding and modifying todos</h3> |
|
398 |
+<div id="outline-container-orgf298702" class="outline-3"> |
|
399 |
+<h3 id="orgf298702"><span class="section-number-3">2.3</span> Adding and modifying todos</h3> |
|
399 | 400 |
<div class="outline-text-3" id="text-2-3"> |
400 | 401 |
<p> |
401 | 402 |
<code>new-todo</code> is fairly trivial. It's main feature is that it has to |
... | ... |
@@ -405,7 +406,7 @@ properly. <code>new-todo</code> backs POST requests to the root endpoint. |
405 | 406 |
</p> |
406 | 407 |
|
407 | 408 |
<div class="org-src-container"> |
408 |
-<pre class="src src-lisp" id="orgc33e5ab"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defvar</span> <span style="color: #DC8CC3;">*external-host*</span> |
|
409 |
+<pre class="src src-lisp" id="org525fb01"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defvar</span> <span style="color: #DC8CC3;">*external-host*</span> |
|
409 | 410 |
<span style="color: #D0BF8F;">"localhost"</span><span style="color: #8c8c8c;">)</span> |
410 | 411 |
<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defvar</span> <span style="color: #DC8CC3;">*external-port*</span> |
411 | 412 |
5000<span style="color: #8c8c8c;">)</span> |
... | ... |
@@ -430,7 +431,7 @@ todo endpoint for a specific ID. |
430 | 431 |
</p> |
431 | 432 |
|
432 | 433 |
<div class="org-src-container"> |
433 |
-<pre class="src src-lisp" id="org1d7bd54"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">update-todo</span> <span style="color: #93a8c6;">(</span>id v<span style="color: #93a8c6;">)</span> |
|
434 |
+<pre class="src src-lisp" id="org0d08c54"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">update-todo</span> <span style="color: #93a8c6;">(</span>id v<span style="color: #93a8c6;">)</span> |
|
434 | 435 |
<span style="color: #93a8c6;">(</span>setf <span style="color: #b0b1a3;">(</span>todo id<span style="color: #b0b1a3;">)</span> |
435 | 436 |
<span style="color: #b0b1a3;">(</span>serapeum:merge-tables <span style="color: #97b098;">(</span>or <span style="color: #aebed8;">(</span>todo id<span style="color: #aebed8;">)</span> |
436 | 437 |
<span style="color: #aebed8;">(</span>make-hash-table <span style="font-weight: bold;">:test</span> 'equal<span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> |
... | ... |
@@ -444,8 +445,8 @@ todo endpoint for a specific ID. |
444 | 445 |
</div> |
445 | 446 |
</div> |
446 | 447 |
|
447 |
-<div id="outline-container-org856ed57" class="outline-3"> |
|
448 |
-<h3 id="org856ed57"><span class="section-number-3">2.4</span> Examples</h3> |
|
448 |
+<div id="outline-container-orgd0dd01c" class="outline-3"> |
|
449 |
+<h3 id="orgd0dd01c"><span class="section-number-3">2.4</span> Examples</h3> |
|
449 | 450 |
<div class="outline-text-3" id="text-2-4"> |
450 | 451 |
<div class="org-src-container"> |
451 | 452 |
<pre class="src src-lisp"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">in-package</span> <span style="font-weight: bold;">:fwoar.todo</span><span style="color: #8c8c8c;">)</span> |
... | ... |
@@ -460,10 +461,10 @@ todo endpoint for a specific ID. |
460 | 461 |
</div> |
461 | 462 |
|
462 | 463 |
<pre class="example"> |
463 |
-(#<hash-table "url": "http://localhost:5000/todo/121", |
|
464 |
+(#<hash-table "url": "http://localhost:5000/todo/129", |
|
464 | 465 |
"title": "get groceries", |
465 | 466 |
"completed": YASON:FALSE> |
466 |
- #<hash-table "url": "http://localhost:5000/todo/122", |
|
467 |
+ #<hash-table "url": "http://localhost:5000/todo/130", |
|
467 | 468 |
"title": "write-better-documentation", |
468 | 469 |
"completed": YASON:FALSE>) |
469 | 470 |
</pre> |
... | ... |
@@ -472,12 +473,12 @@ todo endpoint for a specific ID. |
472 | 473 |
</div> |
473 | 474 |
|
474 | 475 |
|
475 |
-<div id="outline-container-org8f02b65" class="outline-2"> |
|
476 |
-<h2 id="org8f02b65"><span class="section-number-2">3</span> Routing</h2> |
|
476 |
+<div id="outline-container-org42229a6" class="outline-2"> |
|
477 |
+<h2 id="org42229a6"><span class="section-number-2">3</span> Routing</h2> |
|
477 | 478 |
<div class="outline-text-2" id="text-3"> |
478 | 479 |
</div> |
479 |
-<div id="outline-container-org93dcda5" class="outline-3"> |
|
480 |
-<h3 id="org93dcda5"><span class="section-number-3">3.1</span> Routing utilities</h3> |
|
480 |
+<div id="outline-container-org84376ba" class="outline-3"> |
|
481 |
+<h3 id="org84376ba"><span class="section-number-3">3.1</span> Routing utilities</h3> |
|
481 | 482 |
<div class="outline-text-3" id="text-3-1"> |
482 | 483 |
<p> |
483 | 484 |
The core utility here is the <code>defroutes</code> macro. This takes a |
... | ... |
@@ -486,6 +487,24 @@ for HTTP verbs and expands to ningle's functions for manipulating |
486 | 487 |
routes. |
487 | 488 |
</p> |
488 | 489 |
|
490 |
+<div class="org-src-container"> |
|
491 |
+<pre class="src src-lisp" id="org6e29078"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defmacro</span> <span style="color: #8CD0D3;">defroutes</span> <span style="color: #93a8c6;">(</span>app <span style="color: #CC9393;">&body</span> routes<span style="color: #93a8c6;">)</span> |
|
492 |
+ <span style="color: #93a8c6;">(</span>alexandria:once-only <span style="color: #b0b1a3;">(</span>app<span style="color: #b0b1a3;">)</span> |
|
493 |
+ `<span style="color: #b0b1a3;">(</span>setf |
|
494 |
+ ,@<span style="color: #97b098;">(</span><span style="color: #F0DFAF;">loop</span> for <span style="color: #aebed8;">(</span>target . descriptors<span style="color: #aebed8;">)</span> in routes |
|
495 |
+ append <span style="color: #aebed8;">(</span><span style="color: #F0DFAF;">loop</span> for <span style="color: #b0b0b3;">(</span>method callback<span style="color: #b0b0b3;">)</span> in descriptors |
|
496 |
+ append `<span style="color: #b0b0b3;">(</span><span style="color: #90a890;">(</span>ningle:route ,app ,target |
|
497 |
+ <span style="font-weight: bold;">:method</span> method<span style="color: #90a890;">)</span> |
|
498 |
+ ,callback<span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
499 |
+</pre> |
|
500 |
+</div> |
|
501 |
+ |
|
502 |
+<p> |
|
503 |
+This macro organizes all the HTTP verbs for a given endpoint under |
|
504 |
+the path to that endpoint. A more complete version might allow for |
|
505 |
+a list of verbs <code>(:GET :POST)</code> in the head of each handler clause. |
|
506 |
+</p> |
|
507 |
+ |
|
489 | 508 |
<div class="org-src-container"> |
490 | 509 |
<pre class="src src-lisp"><span style="color: #8c8c8c;">(</span>macroexpand-1 |
491 | 510 |
'<span style="color: #93a8c6;">(</span>defroutes app |
... | ... |
@@ -496,32 +515,31 @@ routes. |
496 | 515 |
</pre> |
497 | 516 |
</div> |
498 | 517 |
|
518 |
+ |
|
499 | 519 |
<pre class="example"> |
500 |
-(LET ((#:APP1855 APP)) |
|
501 |
- (SETF (NINGLE/APP:ROUTE #:APP1855 "/" :METHOD METHOD) |
|
520 |
+(LET ((#:APP1859 APP)) |
|
521 |
+ (SETF (NINGLE/APP:ROUTE #:APP1859 "/" :METHOD METHOD) |
|
502 | 522 |
(HANDLER NIL |
503 | 523 |
(TODOS)) |
504 |
- (NINGLE/APP:ROUTE #:APP1855 "/" :METHOD METHOD) |
|
524 |
+ (NINGLE/APP:ROUTE #:APP1859 "/" :METHOD METHOD) |
|
505 | 525 |
(HANDLER (V) |
506 | 526 |
(NEW-TODO V)) |
507 |
- (NINGLE/APP:ROUTE #:APP1855 "/" :METHOD METHOD) |
|
527 |
+ (NINGLE/APP:ROUTE #:APP1859 "/" :METHOD METHOD) |
|
508 | 528 |
(HANDLER NIL |
509 | 529 |
(CLEAR-TODOS)))) |
510 | 530 |
T |
511 | 531 |
</pre> |
512 | 532 |
|
513 |
-<div class="org-src-container"> |
|
514 |
-<pre class="src src-lisp" id="org9d33ed2"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defmacro</span> <span style="color: #8CD0D3;">defroutes</span> <span style="color: #93a8c6;">(</span>app <span style="color: #CC9393;">&body</span> routes<span style="color: #93a8c6;">)</span> |
|
515 |
- <span style="color: #93a8c6;">(</span>alexandria:once-only <span style="color: #b0b1a3;">(</span>app<span style="color: #b0b1a3;">)</span> |
|
516 |
- `<span style="color: #b0b1a3;">(</span>setf |
|
517 |
- ,@<span style="color: #97b098;">(</span><span style="color: #F0DFAF;">loop</span> for <span style="color: #aebed8;">(</span>target . descriptors<span style="color: #aebed8;">)</span> in routes |
|
518 |
- append <span style="color: #aebed8;">(</span><span style="color: #F0DFAF;">loop</span> for <span style="color: #b0b0b3;">(</span>method callback<span style="color: #b0b0b3;">)</span> in descriptors |
|
519 |
- append `<span style="color: #b0b0b3;">(</span><span style="color: #90a890;">(</span>ningle:route ,app ,target |
|
520 |
- <span style="font-weight: bold;">:method</span> method<span style="color: #90a890;">)</span> |
|
521 |
- ,callback<span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
533 |
+<p> |
|
534 |
+Finally, there are some simple helpers to handle some of the |
|
535 |
+boilerplate in a clack webserver. Of particular interest is the |
|
536 |
+<code>handler</code> macro, which (since this is a json-only API) makes sure |
|
537 |
+that all the API results get JSON encoded. |
|
538 |
+</p> |
|
522 | 539 |
|
523 |
-<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">success</span> <span style="color: #93a8c6;">(</span>value<span style="color: #93a8c6;">)</span> |
|
524 |
- <span style="color: #93a8c6;">(</span>list 200 nil value<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
540 |
+<div class="org-src-container"> |
|
541 |
+<pre class="src src-lisp" id="org83a717f"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">success</span> <span style="color: #93a8c6;">(</span>value<span style="color: #93a8c6;">)</span> |
|
542 |
+ <span style="color: #93a8c6;">(</span>list 200 '<span style="color: #b0b1a3;">(</span><span style="font-weight: bold;">:conent-type</span> <span style="color: #D0BF8F;">"application/json"</span><span style="color: #b0b1a3;">)</span> value<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
525 | 543 |
|
526 | 544 |
<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defmacro</span> <span style="color: #8CD0D3;">handler</span> <span style="color: #93a8c6;">(</span><span style="color: #b0b1a3;">(</span><span style="color: #CC9393;">&optional</span> <span style="color: #97b098;">(</span>sym <span style="color: #aebed8;">(</span>gensym <span style="color: #D0BF8F;">"PARAMS"</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span> <span style="color: #CC9393;">&body</span> body<span style="color: #93a8c6;">)</span> |
527 | 545 |
`<span style="color: #93a8c6;">(</span><span style="color: #F0DFAF;">lambda</span> <span style="color: #b0b1a3;">(</span>,sym<span style="color: #b0b1a3;">)</span> |
... | ... |
@@ -533,14 +551,48 @@ T |
533 | 551 |
</div> |
534 | 552 |
</div> |
535 | 553 |
</div> |
554 |
+ |
|
555 |
+<div id="outline-container-orgb1f34fd" class="outline-3"> |
|
556 |
+<h3 id="orgb1f34fd"><span class="section-number-3">3.2</span> todo routes</h3> |
|
557 |
+<div class="outline-text-3" id="text-3-2"> |
|
558 |
+<p> |
|
559 |
+<code>setup-routes</code> binds the endpoints to handlers: "<i>" to handlers |
|
560 |
+that handle the todo lists while "/todo</i>:id" to handlers that |
|
561 |
+handle individual todos. The <code>:id</code> indicates that the |
|
562 |
+corresponding segment of the path is bound to <code>:id</code> in the param |
|
563 |
+alist. <code>get-id</code> handles this, and extracts an integer for the id |
|
564 |
+(since we are using successive integers for the todo ids). |
|
565 |
+</p> |
|
566 |
+ |
|
567 |
+<div class="org-src-container"> |
|
568 |
+<pre class="src src-lisp" id="orgceff44a"><span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">routing</span> |
|
569 |
+<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">get-id</span> <span style="color: #93a8c6;">(</span>params<span style="color: #93a8c6;">)</span> |
|
570 |
+ <span style="color: #93a8c6;">(</span>parse-integer <span style="color: #b0b1a3;">(</span>serapeum:assocdr <span style="font-weight: bold;">:id</span> params<span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
571 |
+ |
|
572 |
+<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">setup-routes</span> <span style="color: #93a8c6;">(</span>app<span style="color: #93a8c6;">)</span> |
|
573 |
+ <span style="color: #93a8c6;">(</span>defroutes app |
|
574 |
+ <span style="color: #b0b1a3;">(</span><span style="color: #D0BF8F;">"/"</span> <span style="color: #97b098;">(</span><span style="font-weight: bold;">:GET</span> <span style="color: #aebed8;">(</span>handler <span style="color: #b0b0b3;">()</span> <span style="color: #b0b0b3;">(</span>todos<span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> |
|
575 |
+ <span style="color: #97b098;">(</span><span style="font-weight: bold;">:POST</span> <span style="color: #aebed8;">(</span>handler <span style="color: #b0b0b3;">(</span>v<span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span>new-todo v<span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> |
|
576 |
+ <span style="color: #97b098;">(</span><span style="font-weight: bold;">:DELETE</span> <span style="color: #aebed8;">(</span>handler <span style="color: #b0b0b3;">()</span> <span style="color: #b0b0b3;">(</span>clear-todos<span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span> |
|
577 |
+ <span style="color: #b0b1a3;">(</span><span style="color: #D0BF8F;">"/todo/:id"</span> <span style="color: #97b098;">(</span><span style="font-weight: bold;">:GET</span> <span style="color: #aebed8;">(</span>handler <span style="color: #b0b0b3;">(</span>v<span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span>todo <span style="color: #90a890;">(</span>get-id v<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> |
|
578 |
+ <span style="color: #97b098;">(</span><span style="font-weight: bold;">:DELETE</span> <span style="color: #aebed8;">(</span>handler <span style="color: #b0b0b3;">(</span>v<span style="color: #b0b0b3;">)</span> |
|
579 |
+ <span style="color: #b0b0b3;">(</span>delete-todo <span style="color: #90a890;">(</span>get-id v<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> |
|
580 |
+ nil<span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> |
|
581 |
+ <span style="color: #97b098;">(</span><span style="font-weight: bold;">:PATCH</span> <span style="color: #aebed8;">(</span>handler <span style="color: #b0b0b3;">(</span>v<span style="color: #b0b0b3;">)</span> |
|
582 |
+ <span style="color: #b0b0b3;">(</span>update-todo <span style="color: #90a890;">(</span>get-id v<span style="color: #90a890;">)</span> |
|
583 |
+ <span style="color: #90a890;">(</span>remove <span style="font-weight: bold;">:id</span> v <span style="font-weight: bold;">:key</span> #'car<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
584 |
+</pre> |
|
585 |
+</div> |
|
586 |
+</div> |
|
587 |
+</div> |
|
536 | 588 |
</div> |
537 | 589 |
|
538 |
-<div id="outline-container-orgdec30ec" class="outline-2"> |
|
539 |
-<h2 id="orgdec30ec"><span class="section-number-2">4</span> Source</h2> |
|
590 |
+<div id="outline-container-org7d68735" class="outline-2"> |
|
591 |
+<h2 id="org7d68735"><span class="section-number-2">4</span> Source</h2> |
|
540 | 592 |
<div class="outline-text-2" id="text-4"> |
541 | 593 |
</div> |
542 |
-<div id="outline-container-org1cf20cf" class="outline-3"> |
|
543 |
-<h3 id="org1cf20cf"><span class="section-number-3">4.1</span> model.lisp source code</h3> |
|
594 |
+<div id="outline-container-org8b89d94" class="outline-3"> |
|
595 |
+<h3 id="org8b89d94"><span class="section-number-3">4.1</span> model.lisp source code</h3> |
|
544 | 596 |
<div class="outline-text-3" id="text-4-1"> |
545 | 597 |
<div class="org-src-container"> |
546 | 598 |
<pre class="src src-lisp"><span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">[[file:~/git_repos/lisp-sandbox/todo/README.org::package-include][package-include]]</span> |
... | ... |
@@ -627,8 +679,8 @@ T |
627 | 679 |
</div> |
628 | 680 |
</div> |
629 | 681 |
|
630 |
-<div id="outline-container-orgbce9205" class="outline-3"> |
|
631 |
-<h3 id="orgbce9205"><span class="section-number-3">4.2</span> routing.lisp source</h3> |
|
682 |
+<div id="outline-container-org031a2d2" class="outline-3"> |
|
683 |
+<h3 id="org031a2d2"><span class="section-number-3">4.2</span> routing.lisp source</h3> |
|
632 | 684 |
<div class="outline-text-3" id="text-4-2"> |
633 | 685 |
<div class="org-src-container"> |
634 | 686 |
<pre class="src src-lisp"><span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">[[file:~/git_repos/lisp-sandbox/todo/README.org::package-include][package-include]]</span> |
... | ... |
@@ -636,7 +688,7 @@ T |
636 | 688 |
|
637 | 689 |
<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">package-include ends here</span> |
638 | 690 |
|
639 |
-<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">[[file:~/git_repos/lisp-sandbox/todo/README.org::routing-helpers][routing-helpers]]</span> |
|
691 |
+<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">[[file:~/git_repos/lisp-sandbox/todo/README.org::defroutes][defroutes]]</span> |
|
640 | 692 |
<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defmacro</span> <span style="color: #8CD0D3;">defroutes</span> <span style="color: #93a8c6;">(</span>app <span style="color: #CC9393;">&body</span> routes<span style="color: #93a8c6;">)</span> |
641 | 693 |
<span style="color: #93a8c6;">(</span>alexandria:once-only <span style="color: #b0b1a3;">(</span>app<span style="color: #b0b1a3;">)</span> |
642 | 694 |
`<span style="color: #b0b1a3;">(</span>setf |
... | ... |
@@ -645,9 +697,11 @@ T |
645 | 697 |
append `<span style="color: #b0b0b3;">(</span><span style="color: #90a890;">(</span>ningle:route ,app ,target |
646 | 698 |
<span style="font-weight: bold;">:method</span> method<span style="color: #90a890;">)</span> |
647 | 699 |
,callback<span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
700 |
+<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">defroutes ends here</span> |
|
648 | 701 |
|
702 |
+<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">[[file:~/git_repos/lisp-sandbox/todo/README.org::routing-helpers][routing-helpers]]</span> |
|
649 | 703 |
<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">success</span> <span style="color: #93a8c6;">(</span>value<span style="color: #93a8c6;">)</span> |
650 |
- <span style="color: #93a8c6;">(</span>list 200 nil value<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
704 |
+ <span style="color: #93a8c6;">(</span>list 200 '<span style="color: #b0b1a3;">(</span><span style="font-weight: bold;">:conent-type</span> <span style="color: #D0BF8F;">"application/json"</span><span style="color: #b0b1a3;">)</span> value<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
|
651 | 705 |
|
652 | 706 |
<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defmacro</span> <span style="color: #8CD0D3;">handler</span> <span style="color: #93a8c6;">(</span><span style="color: #b0b1a3;">(</span><span style="color: #CC9393;">&optional</span> <span style="color: #97b098;">(</span>sym <span style="color: #aebed8;">(</span>gensym <span style="color: #D0BF8F;">"PARAMS"</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span> <span style="color: #CC9393;">&body</span> body<span style="color: #93a8c6;">)</span> |
653 | 707 |
`<span style="color: #93a8c6;">(</span><span style="color: #F0DFAF;">lambda</span> <span style="color: #b0b1a3;">(</span>,sym<span style="color: #b0b1a3;">)</span> |
... | ... |
@@ -657,6 +711,7 @@ T |
657 | 711 |
<span style="color: #aebed8;">(</span><span style="color: #F0DFAF;">progn</span> ,@body<span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
658 | 712 |
<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">routing-helpers ends here</span> |
659 | 713 |
|
714 |
+<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">[[file:~/git_repos/lisp-sandbox/todo/README.org::todo-routes][todo-routes]]</span> |
|
660 | 715 |
<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">routing</span> |
661 | 716 |
<span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">defun</span> <span style="color: #8CD0D3;">get-id</span> <span style="color: #93a8c6;">(</span>params<span style="color: #93a8c6;">)</span> |
662 | 717 |
<span style="color: #93a8c6;">(</span>parse-integer <span style="color: #b0b1a3;">(</span>serapeum:assocdr <span style="font-weight: bold;">:id</span> params<span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
... | ... |
@@ -673,13 +728,14 @@ T |
673 | 728 |
<span style="color: #97b098;">(</span><span style="font-weight: bold;">:PATCH</span> <span style="color: #aebed8;">(</span>handler <span style="color: #b0b0b3;">(</span>v<span style="color: #b0b0b3;">)</span> |
674 | 729 |
<span style="color: #b0b0b3;">(</span>update-todo <span style="color: #90a890;">(</span>get-id v<span style="color: #90a890;">)</span> |
675 | 730 |
<span style="color: #90a890;">(</span>remove <span style="font-weight: bold;">:id</span> v <span style="font-weight: bold;">:key</span> #'car<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> |
731 |
+<span style="color: #A6A689; background-color: #2B2B2B;">;; </span><span style="color: #A6A689; background-color: #2B2B2B;">todo-routes ends here</span> |
|
676 | 732 |
</pre> |
677 | 733 |
</div> |
678 | 734 |
</div> |
679 | 735 |
</div> |
680 | 736 |
|
681 |
-<div id="outline-container-orgc91e7f6" class="outline-3"> |
|
682 |
-<h3 id="orgc91e7f6"><span class="section-number-3">4.3</span> main.lisp source</h3> |
|
737 |
+<div id="outline-container-org04fe926" class="outline-3"> |
|
738 |
+<h3 id="org04fe926"><span class="section-number-3">4.3</span> main.lisp source</h3> |
|
683 | 739 |
<div class="outline-text-3" id="text-4-3"> |
684 | 740 |
<div class="org-src-container"> |
685 | 741 |
<pre class="src src-lisp"><span style="color: #8c8c8c;">(</span><span style="color: #F0DFAF;">in-package</span> <span style="font-weight: bold;">:fwoar.todo</span><span style="color: #8c8c8c;">)</span> |
... | ... |
@@ -725,7 +781,7 @@ T |
725 | 781 |
</div> |
726 | 782 |
<div id="postamble" class="status"> |
727 | 783 |
<p class="author">Author: Langley</p> |
728 |
-<p class="date">Created: 2019-08-30 Fri 02:00</p> |
|
784 |
+<p class="date">Created: 2019-08-30 Fri 02:15</p> |
|
729 | 785 |
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p> |
730 | 786 |
</div> |
731 | 787 |
</body> |
... | ... |
@@ -4,7 +4,7 @@ |
4 | 4 |
|
5 | 5 |
;; package-include ends here |
6 | 6 |
|
7 |
-;; [[file:~/git_repos/lisp-sandbox/todo/README.org::routing-helpers][routing-helpers]] |
|
7 |
+;; [[file:~/git_repos/lisp-sandbox/todo/README.org::defroutes][defroutes]] |
|
8 | 8 |
(defmacro defroutes (app &body routes) |
9 | 9 |
(alexandria:once-only (app) |
10 | 10 |
`(setf |
... | ... |
@@ -13,9 +13,11 @@ |
13 | 13 |
append `((ningle:route ,app ,target |
14 | 14 |
:method method) |
15 | 15 |
,callback)))))) |
16 |
+;; defroutes ends here |
|
16 | 17 |
|
18 |
+;; [[file:~/git_repos/lisp-sandbox/todo/README.org::routing-helpers][routing-helpers]] |
|
17 | 19 |
(defun success (value) |
18 |
- (list 200 nil value)) |
|
20 |
+ (list 200 '(:conent-type "application/json") value)) |
|
19 | 21 |
|
20 | 22 |
(defmacro handler ((&optional (sym (gensym "PARAMS"))) &body body) |
21 | 23 |
`(lambda (,sym) |
... | ... |
@@ -25,6 +27,7 @@ |
25 | 27 |
(progn ,@body))))) |
26 | 28 |
;; routing-helpers ends here |
27 | 29 |
|
30 |
+;; [[file:~/git_repos/lisp-sandbox/todo/README.org::todo-routes][todo-routes]] |
|
28 | 31 |
;; routing |
29 | 32 |
(defun get-id (params) |
30 | 33 |
(parse-integer (serapeum:assocdr :id params))) |
... | ... |
@@ -41,4 +44,5 @@ |
41 | 44 |
(:PATCH (handler (v) |
42 | 45 |
(update-todo (get-id v) |
43 | 46 |
(remove :id v :key #'car))))))) |
47 |
+;; todo-routes ends here |
|
44 | 48 |
;; routing.lisp source:1 ends here |