Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
snooze
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Admin message
Setting up 2FA is now mandatory for all users.
Show more breadcrumbs
ehai
snooze
Commits
bb15eebe
Commit
bb15eebe
authored
9 years ago
by
João Távora
Browse files
Options
Downloads
Patches
Plain Diff
Update README.md
parent
2c1f025b
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
README.md
+79
-5
79 additions, 5 deletions
README.md
with
79 additions
and
5 deletions
README.md
+
79
−
5
View file @
bb15eebe
[

](https://travis-ci.org/capitaomorte/snooze)
Snooze
=======
_Snooze_
is a framework for building REST web services in Common Lisp.
_Snooze_
is a framework for building REST web services in Common
Lisp.
Here's a very simple REST API to read and write Lisp documentation via
HTTP:
The primary goal is to make the programmer stay as close to the
regular Lisp idioms as possible, even while writing with HTTP in mind.
Here's one such REST service to access Lisp documentation over HTTP:
```
lisp
(
defpackage
#:readme-demo
(
:use
#:cl
#:snooze
))
...
...
@@ -27,7 +31,7 @@ HTTP:
```
No regular expressions, annotations or funny argument-matching syntax: routes
not only
*look like*
functions, they
*are*
functions.
not only
*
*look like*
*
functions, they
*
*are*
*
functions.
Here are the routes thus defined and some of the error reporting you
get for free:
...
...
@@ -47,7 +51,9 @@ PUT /lispdoc/defun => 415 Unsupported Media Type
Content-type: application/json
```
Checkout the
[
tutorial
](
#tutorial
)
, which builds on this application.
Checkout the
[
tutorial
](
#tutorial
)
, which builds on this
application. If you're intrigued about how and why URI paths become
symbols arguments to your routes,
[
read here
](
#how-snooze-converts-uri-components-to-arguments
)
Rationale
---------
...
...
@@ -88,6 +94,7 @@ how to:
*
[
dispatch on HTTP methods and content-types
](
#content-types
)
*
[
generate and encode compatible URIs
](
#uri-generation
)
*
[
grafully handle failure conditions
](
#controlling-errors
)
*
[
control conversion of URI arguments
](
#how-snooze-converts-uri-components-to-arguments
)
*
[
refactor routes without changing the API
](
#tighter-routes
)
*
[
hook _Snooze_ into the backend of your choice
](
#other-backends
)
...
...
@@ -248,6 +255,73 @@ Finally, you can play around with `*catch-errors*` and
either `
:verbose
` or `
nil
` depending on whether I want to do debugging
in the browser or in Emacs.
How Snooze converts URI components to arguments
-----------------------------------------------
You might have noticed already that the CLOS generic functions that
represent resources take as arguments actual Lisp symbols extracted
from the URI, whereas other frameworks normally pass them as strings.
Let's drift from the `
lispdoc
` example a bit. Consider this app fragment:
```lisp
(defclass beatle () ((id :initarg :id)
(name :initarg :name :accessor name)
(guitars :initarg :guitars :accessor number-of-guitars)))
(defvar *beatles*
(loop for id from 0 for (name nguitars)
in '(("John" 20) ("Paul" 20) ("Ringo" 0) ("George" 300))
collect (make-instance 'beatle :id id :name name :guitars nguitars)))
(defroute beatles (:get "text/plain" &key (key 'number-of-guitars) (predicate '>))
(format nil "~{~a~^~%~}"
(mapcar #'name
(handler-case
(sort (copy-list *beatles*) predicate :key key)
(error (e) (http-condition 400 "Bad sort predicate or key (~a)" e))))))
(defgenpath beatles beatles-path)
```
`
beatles-path
`, when passed actual symbols naming functions that are
have meaning in your application domain, will generate perfect URI's
for accesing the `
beatles
` route. So
```lisp
(beatles-path :key 'name :predicate 'string-lessp)
```
returns
```lisp
"/beatles/?key=name&predicate=string-lessp"
```
Secondly this is only the default behaviour of Snooze, and is entirely
configurable: if you really want to have the path `
foo/bar/baz
` become
the arguments `
"foo"
`, `
"bar"
` and `
"baz"
` to your application you
merely need to add a CLOS method to the each of the generic functions
`
read-for-resource
` and `
write-for-resource
`.
I recommend you keep the default: `
write-for-resource
` uses
`
cl:write-to-string
` and `
read-for-resource
` uses a very locked down
version of `
cl:read-to-string
`, one that doesn't intern symbols, allow
any kind of reader macros or read anything more complicated than a
number, a string or a symbol. This is for security.
Snooze allows even finer control over the way the URI is translated,
so that individual arguments are read differently, or even
combined. One might want, for example:
```
GET beatle/3
```
where `
3
` is an id, to pass an actual `
beatle
` object to the
route. This is explained in the next section.`
Tighter routes
---------------
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment