Adding page
This commit is contained in:
parent
e999daa871
commit
8320517192
|
@ -69,6 +69,8 @@
|
|||
(build-path example-servlets "add-ssd.rkt"))
|
||||
(test-add-two-numbers mkd "add-formlets.rkt - send/formlet"
|
||||
(build-path example-servlets "add-formlets.rkt"))
|
||||
(test-add-two-numbers mkd "add-page.rkt"
|
||||
(build-path example-servlets "add-page.rkt"))
|
||||
(test-equal? "count.rkt - state"
|
||||
(let* ([d (mkd (build-path example-servlets "count.rkt"))]
|
||||
[ext (lambda (c)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#lang racket/base
|
||||
(require web-server/servlet
|
||||
web-server/page)
|
||||
(provide (all-defined-out))
|
||||
(define interface-version 'v1)
|
||||
(define timeout +inf.0)
|
||||
|
||||
(define (request-number which-number)
|
||||
(let/ec esc
|
||||
(page
|
||||
`(html (head (title "Enter a Number to Add"))
|
||||
(body ([bgcolor "white"])
|
||||
(form ([action ,(embed/url
|
||||
(lambda/page ()
|
||||
(esc
|
||||
(string->number
|
||||
(get-binding 'number)))))]
|
||||
[method "post"])
|
||||
"Enter the " ,which-number " number to add: "
|
||||
(input ([type "text"] [name "number"] [value ""]))
|
||||
(input ([type "submit"] [name "enter"] [value "Enter"]))))))))
|
||||
|
||||
(define/page (start)
|
||||
`(html (head (title "Sum"))
|
||||
(body ([bgcolor "white"])
|
||||
(p "The answer is "
|
||||
,(number->string (+ (request-number "first") (request-number "second")))))))
|
3
collects/web-server/page.rkt
Normal file
3
collects/web-server/page.rkt
Normal file
|
@ -0,0 +1,3 @@
|
|||
#lang racket/base
|
||||
(require "page/page.rkt")
|
||||
(provide (all-from-out "page/page.rkt"))
|
|
@ -1,6 +1,8 @@
|
|||
#lang racket/base
|
||||
(require web-server/servlet
|
||||
racket/stxparam
|
||||
racket/list
|
||||
racket/contract
|
||||
(for-syntax racket/base))
|
||||
|
||||
(define-syntax-parameter embed/url
|
||||
|
@ -48,20 +50,22 @@
|
|||
[(binding)
|
||||
b]))
|
||||
|
||||
(define (get-binding id #:format [format 'string])
|
||||
(define (get-binding id [req (current-request)]
|
||||
#:format [format 'string])
|
||||
(convert-binding
|
||||
format
|
||||
(bindings-assq
|
||||
(binding-id->bytes id)
|
||||
(request-bindings/raw (current-request)))))
|
||||
(request-bindings/raw req))))
|
||||
|
||||
(define (get-bindings id #:format [format 'string])
|
||||
(define (get-bindings id [req (current-request)]
|
||||
#:format [format 'string])
|
||||
(define id-bs (binding-id->bytes id))
|
||||
(filter-map
|
||||
(λ (b)
|
||||
(and (bytes=? id-bs (binding-id b))
|
||||
(convert-binding format b)))
|
||||
(request-bindings/raw (current-request))))
|
||||
(request-bindings/raw req)))
|
||||
|
||||
(provide embed/url
|
||||
page
|
||||
|
@ -71,7 +75,7 @@
|
|||
[current-request (parameter/c (or/c false/c request?))]
|
||||
[binding-id/c contract?]
|
||||
[binding-format/c contract?]
|
||||
[get-binding (->* (binding-id/c) (#:format binding-format/c)
|
||||
[get-binding (->* (binding-id/c) (request? #:format binding-format/c)
|
||||
(or/c false/c string? bytes? binding?))]
|
||||
[get-bindings (->* (binding-id/c) (#:format binding-format/c)
|
||||
[get-bindings (->* (binding-id/c) (request? #:format binding-format/c)
|
||||
(listof (or/c string? bytes? binding?)))])
|
70
collects/web-server/scribblings/page.scrbl
Normal file
70
collects/web-server/scribblings/page.scrbl
Normal file
|
@ -0,0 +1,70 @@
|
|||
#lang scribble/doc
|
||||
@(require "web-server.rkt")
|
||||
@(require (for-label web-server/servlet
|
||||
web-server/page
|
||||
racket/promise
|
||||
racket/list
|
||||
xml))
|
||||
|
||||
@title[#:tag "page"]{Page: Short-hand for Common Patterns}
|
||||
|
||||
@defmodule[web-server/page]
|
||||
|
||||
The @web-server provides a simple utility library for building Web applications that consistent mostly of @racket[send/suspend/dispatch]-created pages and request handling.
|
||||
|
||||
Most Web applications rely heavily on @racket[send/suspend/dispatch] and typically use the pattern:
|
||||
@racketblock[
|
||||
(send/suspend/dispatch
|
||||
(λ (my-embed/url)
|
||||
.... (my-embed/url other-page) ....))]
|
||||
|
||||
@defform[(page e ...)]{
|
||||
|
||||
The @racket[page] macro automates this by expanding @racket[(page e ...)] to a usage of @racket[send/suspend/dispatch] where the syntax parameter @racket[embed/url] is bound to the argument of @racket[send/suspend/dispatch].
|
||||
|
||||
}
|
||||
|
||||
@defidform[embed/url]{
|
||||
When used inside @racket[page] syntactically, a rename transformer for the procedure embedding function; otherwise, a syntax error.}
|
||||
|
||||
A simple example:
|
||||
@racketblock[
|
||||
(page
|
||||
`(html
|
||||
(body
|
||||
(a ([href
|
||||
,(embed/url
|
||||
(λ (req)
|
||||
"You clicked!"))])
|
||||
"Click me"))))]
|
||||
|
||||
Similarly, many Web applications make use almost exclusively of functions that are arguments to @racket[embed/url] and immediately invoke @racket[send/suspend/dispatch].
|
||||
|
||||
@deftogether[[@defform[(lambda/page formals e ...)]
|
||||
@defform[(define/page (id . formals) e ...)]]]{
|
||||
The @racket[lambda/page] and @racket[define/page] automate this by expanding to functions that accept a request as the first argument (followed by any arguments specified in @racket[formals]) and immediately wrap their body in @racket[page]. This functions also cooperate with @racket[get-binding] by binding the request to the @racket[current-request] parameter.
|
||||
}
|
||||
|
||||
The binding interface of @racketmodname[web-server/http] is powerful, but subtle to use conveniently due to its protection against hostile clients.
|
||||
|
||||
@deftogether[[
|
||||
@defparam[current-request req request?]
|
||||
@defthing[binding-id/c contract?]
|
||||
@defthing[binding-format/c contract?]
|
||||
@defproc[(get-binding [id binding-id/c] [req request? (current-request)] [#:format format binding-format/c 'string])
|
||||
(or/c false/c string? bytes? binding?)]
|
||||
@defproc[(get-bindings [id binding-id/c] [req request? (current-request)] [#:format format binding-format/c 'string])
|
||||
(listof (or/c string? bytes? binding?))]
|
||||
]]{
|
||||
|
||||
The @racket[get-binding](s) interface attempts to resolve this by providing a powerful interface with convenient defaults.
|
||||
|
||||
@racket[get-binding] extracts the first binding of a form input from a request, while @racket[get-bindings] extracts them all.
|
||||
|
||||
They accept a form identifier (@racket[id]) as either a byte string, a string, or a symbol. In each case, the user input is compared in a case-sensitive way with the form input.
|
||||
|
||||
They accept an optional request argument (@racket[req]) that defaults to the value of the @racket[current-request] parameter used by @racket[lambda/page] and @racket[define/page].
|
||||
|
||||
Finally, they accept an optional keyword argument (@racket[format]) that specifies the desired return format. The default, @racket['string], produces a UTF-8 string (or @racket[#f] if the byte string cannot be converted to UTF-8.) The @racket['bytes] format always produces the raw byte string. The @racket['file] format produces the file upload content (or @racket[#f] if the form input was not an uploaded file.) The @racket['binding] format produces the binding object.
|
||||
|
||||
}
|
|
@ -16,8 +16,7 @@ This manual describes the Racket libraries for building Web applications.
|
|||
The @secref["http"] section describes the common library function for manipulating HTTP requests and creating HTTP responses.
|
||||
In particular, this section covers cookies, authentication, and request bindings.
|
||||
|
||||
The final three sections (@secref["dispatch"], @secref["formlets"], and @secref["templates"]) cover utility libraries that
|
||||
ease the creation of typical Web applications.
|
||||
The final four sections (@secref["dispatch"], @secref["formlets"], @secref["templates"], and @secref["page"]) cover utility libraries that ease the creation of typical Web applications.
|
||||
|
||||
This manual closes with a frequently asked questions section: @secref["faq"].
|
||||
|
||||
|
@ -33,6 +32,7 @@ This manual closes with a frequently asked questions section: @secref["faq"].
|
|||
@include-section["dispatch.scrbl"]
|
||||
@include-section["formlets.scrbl"]
|
||||
@include-section["templates.scrbl"]
|
||||
@include-section["page.scrbl"]
|
||||
|
||||
@include-section["faq.scrbl"]
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user