Clack is a Web Application Environment for Common Lisp inspired by Python's WSGI and Ruby's Rack. Your awesome framework should base on this.
(defpackage simple-app
(:use :cl
:clack))
(in-package :simple-app)
(clackup
#'(lambda (req)
'(200 (:content-type "text/plain") ("Hello, Clack!"))))
Now access http://localhost:5000/ and Clack may show you "Hello, Clack!".
Clack is now available on Quicklisp.
(ql:quickload :clack)
Clack Application is just a lambda. It takes exactly one argument, the "Request", and returns the "Response" as a list containing exactly three values.
(defvar app
#'(lambda (req)
'(200 (:content-type "text/plain") ("Hello, World"))))
Clack is not a Web Application Framework. But Clack can also be used as such way.
Clack bundles "Clack.App.Route", written by Tomohiro Matsuyama. It allows you to write an URL-based dispatcher, like Ruby's Sinatra.
(defroutes app (req)
(GET \"/\" #'index)
(GET \"/login\" #'login)
(POST \"/login\" #'authorize)
(GET \"/member/:id\" #'member))
(clackup #'app)
Example: http://localhost:4242/sns/member?id=3
(:request-method :GET
:script-name ""
:path-info "/sns/member"
:query-string "id=3"
:server-name "localhost"
:server-port 4242
:request-uri "/sns/member?id=3"
:server-protocol :HTTP/1.1
:http-user-agent "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) ..."
:http-remote-addr "127.0.0.1"
:http-remote-port 26077
:http-referer nil
:http-host "localhost:4242"
:http-cookies nil
:http-server :hunchentoot
:%request #<request {11A02249}>)
The Request is a list containing at least the following keys and corresponding values.
:request-method
(Required, Keyword): The HTTP request method, must be one of :GET
, :HEAD
, :OPTIONS
, :PUT
, :POST
, or :DELETE
.
:script-name
(Required, String): The initial portion of the request URL's path, corresponding to the application. This may be an empty string if the application corresponds to the server's root URI. If this key is not empty, it must start with a forward slash (/
).
:path-info
(Required, String): The remainder of the request URL's path. This may be an empty string if the request URL targets the application root and does no have a trailing slash.
:query-string
(Optional, String): The portion of the request URL that follows the ?
, if any. This key may be empty, but must always be present, even if empty.
:server-name
(Required, String): The resolved server name, or the server IP address.
:server-port
(Required, Integer): The port on which the request is being handled.
:server-protocol
(Required, Keyword): The version of the protocol the client used to send the request. Typically this will be something like :HTTP/1.0
or :HTTP/1.1
.
:request-uri
(Required, String): The request URI. Must start with "/".
:server-protocol
(Required, Keyword)
:raw-body
(Optional, Stream)
:http-user-agent
(Optional, String)
:http-referer
(Optional, String)
:remote-addr
(Required, String)
:remote-port
(Required, Integer)
:http-server
(Required, Keyword): The name of Clack Handler, such as :hunchentoot
.
Example:
(200
(:content-type "text/html")
("<b>Hello, Lispers!</b>"))
Applications must return a response as a list containing three values.
Clack Applications run via Clack Handlers, which are in turn responsible for implementing the HTTP protocol and abstracting the server.
Now Clack Applications works on Hunchentoot and Apache, by using following handler.
If you hope them to run on other server (such as AllegroServe or teepeedee2), you can write a handler for it easily.
Middleware is one of the Clack Component. It takes another Application and runs it.
All you have to do is to inherit from <middleware>
and then implement the callback call
method (or make-app
method that would return a function) to do the actual work. You can use call-next
to call the original (wrapped) application.
(defpackage clack.middleware.example
(:use :cl :clack)
(:export :<simple-middleware>))
(in-package :clack.middleware.example)
(defclass <simple-middleware> (<middleware>) ())
(defmethod call ((this <simple-middleware>) req)
`(200 (:content-type "text/html")
,(cons "Hello, Clack Middleware!<br />"
(nth 2 (call-next this req)))))
(defpackage simple-app
(:use :cl
:clack
:clack.builder
:clack.middleware.example))
(in-package :simple-app)
(defvar app
#'(lambda (req)
'(200 (:content-type "text/plain") ("Hello, Clack!"))))
(clackup (builder <simple-middleware> app))
And you should get following response in time.
Hello, Clack Middleware!
Hello, Clack!
Copyright (c) 2011 Eitarow Fukamachi
Licensed under the LLGPL License.