Peony Web Framework
1 Full Example
2 Reference
webapp
webpage
2.1 Defining Pages
page
textpage
datapage
page/  headers
textpage/  headers
datapage/  headers
page/  proto
7.8

Peony Web Framework

 (require peony) package: peony

Peony is a small frontend on Web Applications in Racket which makes web development fit closer to the idiom familiar to people who’ve mainly used php or similar in the past. With Peony, each webpage lives at a fixed path and corresponds to a chunk of code that’s executed to produce html when the page is accessed. As long as that’s all that’s needed, the details of dispatching and such can be avoided.

Peony is under active development and the api should not be considered stable.

See also DB: Database Connectivity.

1 Full Example

As an example of use, say we want to create a webapp to demonstrate the use of GET and POST parameters.

First, we can set up a main page like so:
(define index (page index.html
                    '(html (body (h1 "demo webapp")
                                 (a [[href "demos/get"]] "test get")
                                 (br)
                                 (a [[href "demos/post"]] "test post")))))
Which defines index as a webpage with the path index.html and a static body. Since we’ll be using it as the index of our webapp it will be accessible at www.address.com/. we call it index.html just for the sake of tradition, since it has to have a non-empty name as well.

The GET page can be implemented using the GET binding like so:
(define getpage (page demos/get
                      `(html (body (h1 "GET demo")
                                   (form [[method "get"]]
                                         (p "submit a GET request with paramenters:")
                                         (p "p1: " (input [[type "text"][name "p1"]]))
                                         (p "p2: " (input [[type "text"][name "p2"]]))
                                         (br)
                                         (button "submit"))
                                   (table
                                    (tr (th "Name") (th "Value"))
                                    ,@(hash-map GET (λ (key val) `(tr (td ,key) (td ,val)))))
                                   (a [[href "index.html"]] "back")))))
(where ",@" is unquote-splicing). The resulting page is generated with new GET values each time it’s loaded.

The POST page can be identical except for replacing each instance of ’get’ with ’post’ (noting that the one referencing the actual binding must be all-caps POST):
(define postpage (page demos/post
                      `(html (body (h1 "POST demo")
                                   (form [[method "post"]]
                                         (p "submit a POST request with paramenters:")
                                         (p "p1: " (input [[type "text"][name "p1"]]))
                                         (p "p2: " (input [[type "text"][name "p2"]]))
                                         (br)
                                         (button "submit"))
                                   (table
                                    (tr (th "Name") (th "Value"))
                                    ,@(hash-map POST (λ (key val) `(tr (td ,key) (td ,val)))))
                                   (a [[href "index.html"]] "back")))))

Then we can put it all together into a webapp and serve it:
(define app (webapp index getpage postpage))
(serve/servlet app #:servlet-regexp #rx"" #:servlet-path "")
serve/servlet with #:servlet-regexp #rx"" and #:servlet-path "" is equivalent to serve/dispatch, but doing it this way allows us to add other serve/servlet-specific parameters later (such as #:start-web-browser? and #:port).

2 Reference

procedure

(webapp index pages ...)  (-> request? response?)

  index : webpage?
  pages : webpage?
Returns a servlet that can be passed to Web Applications in Racket’s serve/dispatch (or similar, but the servlet-regexp must be #rx"" in any case). The servlet serves each page at the url matching its path, and a fixed 404 page at all other paths. The first page, the index, is also served at the empty path.

struct

(struct webpage (path body)
    #:extra-constructor-name make-webpage)
  path : symbol?
  body : (-> request? response?)
A structure for webpages, consisting of a path the page can be found at and a function mapping an http request to a response. The forms below generate slightly limited webpages automatically.

2.1 Defining Pages

syntax

(page name contents)

 
  name : symbol?
  contents : xexpr?
Returns a webpage whose path is name and whose body is a Web Applications in Racket servlet - a function taking an http request and returning a response. The response is a standard 200 response whose body consists of the html corresponding to the xexpr? provided by contents. The contents expression has access to four values: GET, POST, COOKIE and REQ, containing respectively a hash mapping GET arguments to their values, a hash mapping POST arguments to their values, a hash mapping cookies to their values, and the literal request in full. In GET, POST and COOKIE, if there are multiple parameters with the same name then the earlier ones are shadowed by the later ones, the full query can be extracted by manually processing REQ if this is a problem.

(page name contents) is a shorthand for (page/proto name (hash "Content-Type" "text/html; charset=utf-8") (list (string->bytes/utf-8 (xexpr->string contents)))).

syntax

(textpage name contents)

 
  name : symbol?
  contents : string?
Returns a webpage whose path is name and whose body is the string provided in the contents expression. As with page, the expression for contents has access to GET, POST, COOKIE and REQ.

(textpage name contents) is a shorthand for a page/proto expression.

syntax

(datapage name mime-type contents)

 
  name : symbol?
  mime-type : bytes?
  contents : bytes?
Returns a webpage whose path is name and whose body is the bytestring data provided by the contents expression, served with the specified mime-type. Again, based on page/proto.

syntax

(page/headers name headers contents)

 
  name : symbol?
  headers : hash?
  contents : xexpr?
Works like page, but with an additional headers expression. The headers expression has access to GET, POST, COOKIE and REQ like contents does, and it should return a hash of strings to strings describing any HTTP headers that should be set in the response. These headers override any implicit headers (ie. the default Content-Type of ’text/html; charset=utf-8’ and those mentioned in the documentation for response).

syntax

(textpage/headers name headers contents)

 
  name : symbol?
  headers : hash?
  contents : string?

syntax

(datapage/headers name mime-type headers contents)

 
  name : symbol?
  mime-type : bytes?
  headers : hash?
  contents : bytes?
To datapage as page/headers is to page. Note that any Content-Type specified in the headers will override the mime-type argument.

syntax

(page/proto name headers contents)

 
  name : symbol?
  headers : hash?
  contents : (listof? bytes?)
This is a generic form to construct pages. It works like page/headers and textpage/headers, but without making any assumptions about the nature and purpose of the contents or what Content-Type is appropriate (a list of bytestrings is the form that web-server servlets expect page contents to be in). Again, the headers hash should take strings to strings.