sigildocs

HTTP

HTTP/1.1 client and server functionality.
(import (sigil http))

Client

http-get

Make an HTTP GET request.

(let ((response (http-get "https://example.com/")))
  (display (http-response-body response)))

;; With custom headers
(http-get "https://api.example.com/data"
          '(("Authorization" . "Bearer token123")))

http-post

Make an HTTP POST request.

;; Form data (default Content-Type: application/x-www-form-urlencoded)
(http-post "https://example.com/login"
           "username=alice&password=secret")

;; JSON body
(import (sigil json))
(http-post "https://api.example.com/users"
           (json-encode #{ name: "Alice" })
           '(("Content-Type" . "application/json")))

http-put / http-delete

(http-put "https://api.example.com/users/1"
          (json-encode #{ name: "Bob" })
          '(("Content-Type" . "application/json")))

(http-delete "https://api.example.com/users/1")

http-request

Low-level request function for any HTTP method.

(http-request 'PATCH "https://api.example.com/resource"
              '(("Content-Type" . "application/json"))
              (json-encode #{ status: "active" }))

Response Accessors

(let ((response (http-get "https://example.com/")))
  (http-response-status response)   ; => 200
  (http-response-headers response)  ; => #{ content-type: "text/html" ... }
  (http-response-body response))    ; => "<html>..."

URL Parsing

(let ((url (parse-url "https://example.com:8080/path?query=1")))
  (url-scheme url)  ; => "https"
  (url-host url)    ; => "example.com"
  (url-port url)    ; => 8080
  (url-path url)    ; => "/path"
  (url-query url))  ; => "query=1"

Server

http-serve

Start a blocking HTTP server.

(http-serve 8080
  (lambda (request)
    (http-response/html 200 "<h1>Hello!</h1>")))

Request Accessors

(lambda (req)
  (http-request-method req)   ; => 'GET, 'POST, etc.
  (http-request-path req)     ; => "/users/123"
  (http-request-query req)    ; => "format=json" or #f
  (http-request-headers req)  ; => #{ content-type: "..." ... }
  (http-request-body req)     ; => string or #f
  (http-request-header req content-type:))  ; => "application/json"

Response Constructors

;; Plain text
(http-response/text 200 "Hello, World!")

;; HTML
(http-response/html 200 "<h1>Welcome</h1>")

;; JSON (auto-encodes)
(http-response/json 200 #{ status: "ok" users: #[1 2 3] })

;; Redirect
(http-response/redirect "/new-location")
(http-response/redirect "/new-location" 301)  ; Permanent

;; Error
(http-response/error 500 "Internal Server Error")

;; Not Found
(http-response/not-found)

Custom Response

(http-response
  status: 201
  headers: #{ content-type: "application/json"
              x-custom-header: "value" }
  body: (json-encode #{ id: 123 }))

Form Parsing

;; URL-encoded form data
(let ((form (parse-form-urlencoded (http-request-body req))))
  (dict-ref form username:))

;; Multipart form data (file uploads)
(let ((parts (parse-form-data req)))
  (dict-ref parts file:))

Server-Sent Events (SSE)

;; Single client SSE stream
(http-response/sse
  (lambda (send)
    (send (sse-event "message" (json-encode #{ count: 1 })))
    (send (sse-data "plain text data"))))

;; Broadcast to multiple clients
(http-response/sse-broadcast channel)

Status Code Constants

HTTP-OK                    ; 200
HTTP-CREATED               ; 201
HTTP-NO-CONTENT            ; 204
HTTP-MOVED-PERMANENTLY     ; 301
HTTP-FOUND                 ; 302
HTTP-NOT-MODIFIED          ; 304
HTTP-BAD-REQUEST           ; 400
HTTP-UNAUTHORIZED          ; 401
HTTP-FORBIDDEN             ; 403
HTTP-NOT-FOUND             ; 404
HTTP-INTERNAL-SERVER-ERROR ; 500

Common Patterns

REST API Server

(import (sigil http)
        (sigil json))

(define users #{ 1: #{ name: "Alice" } 2: #{ name: "Bob" } })

(http-serve 8080
  (lambda (req)
    (let ((method (http-request-method req))
          (path (http-request-path req)))
      (cond
        ;; GET /users
        ((and (eq? method 'GET) (string=? path "/users"))
         (http-response/json 200 users))

        ;; GET /users/:id
        ((and (eq? method 'GET) (string-starts-with? path "/users/"))
         (let* ((id (string->number (substring path 7 (string-length path))))
                (user (dict-ref users id #f)))
           (if user
               (http-response/json 200 user)
               (http-response/not-found))))

        ;; POST /users
        ((and (eq? method 'POST) (string=? path "/users"))
         (let ((data (json-decode (http-request-body req))))
           (http-response/json 201 #{ id: 3 name: (dict-ref data name:) })))

        (else (http-response/not-found))))))

Fetch and Process JSON API

(import (sigil http)
        (sigil json))

(define (fetch-user id)
  (let ((response (http-get (format "https://api.example.com/users/~a" id))))
    (if (= (http-response-status response) 200)
        (json-decode (http-response-body response))
        #f)))

(let ((user (fetch-user 123)))
  (when user
    (display (dict-ref user name:))))