• Stars
    star
    232
  • Rank 172,847 (Top 4 %)
  • Language
    Racket
  • License
    MIT License
  • Created about 13 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Write RESTful web apps in Racket.

Spin

Write RESTful web apps in Racket.

Spin layers some convenience functions on top of Racket's built-in web server to simplify defining routes and route handlers.

Installation

From the command line, run raco pkg install https://github.com/dmac/spin.git to install the package.

Overview

Define routes with one of get, post, put, patch, delete and pass it the route string and a handler function.

#lang racket

(require (planet dmac/spin))

(get "/"
  (lambda () "Hello!"))

(run)

Params

Your handler function will be passed the request object if an argument is specified.

It can be given to the params function along with a key to search for values in the query-string, post-body, or url.

(get "/hi" (lambda (req)
  (string-append "Hello, " (params req 'name) "!")))
$ curl "http://localhost:8000/hi?name=Charlotte"
Hello, Charlotte!
$ curl "http://localhost:8000/hi" -X POST -d "name=Anansi"
Hello, Anansi!

Retrieve params from the url string itself:

(get "/hi/:name" (lambda (req)
  (string-append "Hello, " (params req 'name) "!")))
$ curl "http://localhost:8000/hi/Peter"
Hello, Peter!

Templating

Your handler function need only return a string to render. You can easily use existing templating libraries with Spin.

app.rkt

(require web-server/templates)

(get "/template" (lambda (req)
  (define name (params req 'name))
  (include-template "index.html")))

(run)

index.html

<html>
  <body>
    <p>Hello, @|name|!</p>
  </body>
</html>
$ curl "http://localhost:8000/template?name=Aragog"
<html>
  <body>
    <p>Hello, Aragog!</p>
  </body>
</html>

Advanced Responses

In addition to the response body, you can specify response status and custom headers if you return a list instead of a string from your handler:

(get "/headers" (lambda ()
  (define h (header #"Custom-Header" #"Itsy bitsy"))
  `(201 (,h) "Look for the custom header!")))

Response Makers

Response makers are middleware that transform a response before it is sent to the client.

A global default response maker can be defined by passing it to the run function:

(define (json-404-response-maker status headers body)
  (response status
            (status->message status)
            (current-seconds)
            #"application/json; charset=utf-8"
            headers
            (let ([jsexpr-body (case status
                                 [(404) (string->jsexpr
                                         "{\"error\": 404, \"message\": \"Not Found\"}")]
                                 [else body])])
              (lambda (op) (write-json (force jsexpr-body) op)))))

(run #:response-maker json-404-response-maker)

It is also possible to define new handler types that use different response makers:

(define (json-response-maker status headers body)
  (response status
            (status->message status)
            (current-seconds)
            #"application/json; charset=utf-8"
            headers
            (let ([jsexpr-body (string->jsexpr body)])
              (lambda (op) (write-json (force jsexpr-body) op)))))

(define (json-get path handler)
  (define-handler "GET" path handler json-response-maker))

(json-get "/json" (lambda (req)
  "{\"body\":\"JSON GET\"}"))

Contributors