Seth Barrett

Daily Blog Post: March 12th, 2023

racket9

Mar 12th, 2023

Building Web Applications in Racket: A Beginner's Guide with Examples

Racket is a versatile programming language that can be used for a wide range of applications, including web development. In fact, Racket has built-in support for running as a web backend, which makes it a great choice for building scalable and efficient web applications.

Racket provides several libraries for building web applications, including the web-server and net/url libraries. These libraries make it easy to handle HTTP requests, generate dynamic content, and interact with databases. In this post, we will explore the basics of building web applications in Racket using the web-server library.

Setting Up a Simple Web Server

To get started, we need to set up a simple web server that can handle HTTP requests. We can do this using the serve/servlet function provided by the web-server/servlet library. Here is an example of how to set up a simple web server that responds to HTTP GET requests with the text "Hello, world!":

#lang racket

(require web-server/servlet)

(define (hello-world request)
    (response/xexpr `(html (body (p "Hello, world!")))))

(serve/servlet hello-world
                #:launch-browser? #t
                #:port 8080
                #:servlet-path "/")

In this example, we define a function called hello-world that takes an HTTP request object as an argument and returns an HTTP response object. The response object is created using the response/xexpr function, which takes an S-expression that represents HTML content. The serve/servlet function is then used to start the web server and bind the hello-world function to the root path ("/").

Running this program will start a web server on port 8080 and launch a web browser to display the "Hello, world!" message.

Handling HTTP Requests

Now that we have a basic web server set up, let's look at how to handle different types of HTTP requests. We can use pattern matching on the request object to determine the type of request and take different actions based on the request method and path.

Here is an example of how to handle a POST request that submits a form with a name field:

#lang racket

(require web-server/servlet)

(define (handle-form request)
    (match (request-method request)
    ["POST"
        (match-define (cons 'name (list name)) (request-post-params request))
        (response/xexpr `(html (body (p ,(string-append "Hello, " name "!")))))]
    [_
        (response/xexpr `(html (body (form ((method "POST") (action "/")) "Name: " (input ((type "text") (name "name")))))))])
        
(serve/servlet handle-form
                #:launch-browser? #t
                #:port 8080
                #:servlet-path "/")

In this example, we define a function called handle-form that takes an HTTP request object as an argument and returns an HTTP response object. We use pattern matching to check if the request method is "POST" and extract the value of the "name" field from the request body. If the request method is not "POST", we return an HTML form that allows the user to submit a name.

Handling URL Parameters

Another common use case in web applications is to handle URL parameters, such as query parameters or path segments. Racket provides several functions for parsing and extracting URL parameters, including url-decode and regexp-match*.

Here is an example of how to handle a GET request with a name parameter in the URL:

#lang racket

(require web-server/servlet)

(define (handle-name request)
    (match-define (list "" name) (regexp-match* #px"\\A/([^/]*)\\z" (request-uri request)))
    (response/xexpr `(html (body (p ,(string-append "Hello, " name "!"))))))

(serve/servlet handle-name
                #:launch-browser? #t
                #:port 8080
                #:servlet-path "/name/*"))

In this example, we define a function called handle-name that takes an HTTP request object as an argument and returns an HTTP response object. We use the regexp-match* function to extract the value of the name parameter from the URL path. We then return an HTML response that includes the value of the name parameter in a greeting.

Conclusion

Racket's built-in support for running as a web backend makes it a great choice for building web applications. The web-server library provides a simple and efficient way to handle HTTP requests, generate dynamic content, and interact with databases. With Racket's powerful macro system and functional programming features, it's easy to build scalable and maintainable web applications that can handle a wide range of use cases.