### Quick Server Setup with Wookie Helper Functions Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet demonstrates using the `wookie-helper` package for quick server setup. It includes examples for starting a basic static file server, a static server with custom directory and binding, and serving a single-page HTML5 application. ```lisp ;; Quick static file server - serves current directory on port 8080 (wookie-helper:start-static-server :port 8080) ;; Static server with custom directory and binding (wookie-helper:start-static-server :asset-dir "/var/www/public/" :bind "127.0.0.1" :port 3000) ;; Serve a single-page HTML5 application ;; All non-existent routes redirect to index.html for client-side routing (wookie-helper:serve-html5-app :bind "0.0.0.0" :port 8080 :index-file "index.html") ``` -------------------------------- ### Start SSL/HTTPS Server with Wookie Source: https://context7.com/orthecreedence/wookie/llms.txt This example shows how to configure and start an HTTPS server using Wookie. It utilizes the `ssl-listener` class and requires specifying paths to SSL certificate and key files. A secure route returning JSON is defined. ```lisp ;; HTTPS server with SSL certificates (defun run-ssl-server () (wookie:load-plugins) (wookie:defroute (:get "/secure") (req res) (wookie:send-response res :status 200 :headers '(:content-type "application/json") :body "{\"secure\": true}")) (as:with-event-loop (:catch-app-errors t) (let ((listener (make-instance 'wookie:ssl-listener :bind "0.0.0.0" :port 443 :certificate "/path/to/cert.pem" :key "/path/to/key.pem" :password "optional-key-password"))) (wookie:start-server listener)))) (run-ssl-server) ;; => SSL Server listening on 0.0.0.0:443 ``` -------------------------------- ### Start Basic HTTP Server with Wookie Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet demonstrates how to start a basic HTTP server using Wookie. It loads plugins, defines a root route for 'Hello, World!', and starts the server on port 8080. It also includes graceful shutdown handling for the event loop. ```lisp ;; Load required systems (ql:quickload :wookie) ;; Basic HTTP server startup (defun run-server () (wookie:load-plugins) ;; Define a simple route (wookie:defroute (:get "/") (req res) (wookie:send-response res :body "Hello, World!")) ;; Start the event loop and server (as:with-event-loop (:catch-app-errors t) (let ((listener (make-instance 'wookie:listener :bind "0.0.0.0" :port 8080 :backlog 128))) (wookie:start-server listener)) ;; Handle Ctrl+C gracefully (as:signal-handler 2 (lambda (sig) (declare (ignore sig)) (as:exit-event-loop))))) ;; Run the server (run-server) ;; => Server listening on 0.0.0.0:8080 ``` -------------------------------- ### GET /flexible - Using http-var Plugin Source: https://context7.com/orthecreedence/wookie/llms.txt Illustrates the use of the `http-var` plugin for flexible access to parameters from GET, POST, or multipart requests. ```APIDOC ## GET /flexible (with http-var plugin) ### Description Illustrates the use of the `http-var` plugin for flexible access to parameters from GET, POST, or multipart requests. ### Method GET ### Endpoint /flexible ### Parameters #### Path Parameters None #### Query Parameters - **param** (string) - The parameter to retrieve. #### Request Body None ### Request Example ```json { "example": "This is a sample request body, if applicable." } ``` ### Response #### Success Response (200) - **body** (string) - The value of the 'param' or 'No value' if not found. #### Response Example ```json { "example": "some_value" } ``` ``` -------------------------------- ### Configure and Load Wookie Plugins Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet demonstrates how to configure which plugins Wookie should load, specify directories to search for plugins, and then load them. It also includes an example of creating a custom plugin with initialization and cleanup functions, and how to access plugin configuration. ```lisp ;; Configure which plugins to load (setf wookie:*enabled-plugins* '(:get :post :multipart :cookie :directory-router :http-var)) ;; Set plugin search directories (setf wookie:*plugin-folders* '("./my-plugins/" "./vendor/wookie-plugins/")) ;; Load all enabled plugins (wookie:load-plugins) ;; Create a custom plugin ;; File: my-plugins/rate-limit/rate-limit.lisp (defpackage :wookie-plugin-rate-limit (:use :cl :wookie)) (in-package :wookie-plugin-rate-limit) (defvar *request-counts* (make-hash-table :test #'equal)) (defun check-rate-limit (request) (let* ((headers (wookie:request-headers request)) (ip (wookie:get-header headers "x-forwarded-for")) (count (incf (gethash ip *request-counts* 0)))) (when (> count 100) (error "Rate limit exceeded")))) (defun init-rate-limit () (wookie:add-hook :parsed-headers #'check-rate-limit :rate-limit-check)) (defun unload-rate-limit () (wookie:remove-hook :parsed-headers :rate-limit-check)) (wookie:register-plugin :rate-limit #'init-rate-limit #'unload-rate-limit) ;; Access plugin configuration (setf (wookie:plugin-config :rate-limit) '(:max-requests 100 :window-seconds 60)) (let ((config (wookie:plugin-config :rate-limit))) (format t "Max requests: ~a~%" (getf config :max-requests))) ``` -------------------------------- ### GET /search - Using get-var Plugin for Query Parameters Source: https://context7.com/orthecreedence/wookie/llms.txt Demonstrates using the `get-var` function from the GET plugin to access URL query string parameters. ```APIDOC ## GET /search (with get-var plugin) ### Description Demonstrates using the `get-var` function from the GET plugin to access URL query string parameters. ### Method GET ### Endpoint /search ### Parameters #### Path Parameters None #### Query Parameters - **q** (string) - The search term. - **page** (string) - The page number. - **sort** (string) - The sorting criteria. - **foo** (string) - A parameter that is not present. #### Request Body None ### Request Example ```json { "example": "This is a sample request body, if applicable." } ``` ### Response #### Success Response (200) - **body** (string) - A formatted string displaying the retrieved query parameters. #### Response Example ```json { "example": "Search: lisp, Page: 2, Sort: date" } ``` ``` -------------------------------- ### Hook System for Request Lifecycle in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt Illustrates how to use the Wookie hook system in Lisp to intercept requests at various stages like `:pre-route`, `:parsed-headers`, and `:response-started`. It shows how to add, remove, and clear hooks, including an example of an authentication hook that rejects unauthorized requests. ```lisp ;; Add authentication hook that runs before route handling (wookie:add-hook :pre-route (lambda (request response) (let* ((headers (wookie:request-headers request)) (auth-header (wookie:get-header headers "authorization"))) (unless (and auth-header (string= auth-header "Bearer valid-token")) ;; Return a promise that rejects to stop processing (wookie:send-response response :status 401 :body "Unauthorized") (error "Unauthorized request")))) :auth-check) ;; Add logging hook (wookie:add-hook :parsed-headers (lambda (request) (format t "[~a] ~a ~a~%" (get-universal-time) (wookie:request-method request) (wookie:request-resource request))) :request-logger) ;; Add response timing hook (wookie:add-hook :response-started (lambda (response request status headers body) (format t "Response ~a sent for ~a~%" status (wookie:request-resource request))) :response-logger) ;; Remove a hook by name (wookie:remove-hook :pre-route :auth-check) ;; Clear all hooks of a specific type (wookie:clear-hooks :parsed-headers) ;; Clear all hooks (wookie:clear-hooks) ``` -------------------------------- ### Define Wookie Routes with defroute Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet illustrates various ways to define routes using Wookie's `defroute` macro. It covers simple GET and POST routes, regex-based routing with capture groups, handling multiple HTTP methods, route priorities, and wildcard matching. ```lisp ;; Simple GET route (wookie:defroute (:get "/hello") (req res) (wookie:send-response res :body "Hello!")) ;; POST route with JSON response (wookie:defroute (:post "/api/users") (req res) (wookie:send-response res :status 201 :headers '(:content-type "application/json") :body "{\"id\": 1, \"created\": true}")) ;; Route with regex capture groups - captures passed as additional arguments (wookie:defroute (:get "/users/([0-9]+)/posts/([0-9]+)" :regex t) (req res args) (let ((user-id (first args)) (post-id (second args))) (wookie:send-response res :body (format nil "User: ~a, Post: ~a" user-id post-id)))) ;; Multiple HTTP methods on same route (wookie:defroute ((:get :post) "/api/resource") (req res) (let ((method (wookie:request-method req))) (wookie:send-response res :body (format nil "Method: ~a" method)))) ;; Route with priority (higher priority routes match first) (wookie:defroute (:get "/admin/.*" :regex t :priority 10) (req res) (wookie:send-response res :status 401 :body "Unauthorized")) ;; Wildcard route (catch-all, should have low priority) (wookie:defroute (:* ".*" :priority -100) (req res) (wookie:send-response res :status 404 :body "Not Found")) ;; Route with chunked transfer support (wookie:defroute (:post "/upload" :chunk t :buffer-body nil) (req res) "Handle streaming uploads" (wookie:with-chunking req (chunk-data finishedp) (format t "Received ~a bytes, finished: ~a~%" (length chunk-data) finishedp) (when finishedp (wookie:send-response res :body "Upload complete")))) ``` -------------------------------- ### Retrieve GET Parameters using get-var Plugin in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet shows how to use the `get-var` function from the Wookie GET plugin to retrieve URL query string parameters. It demonstrates accessing multiple parameters and handling cases where a parameter might be missing. Ensure plugins are loaded before use. ```lisp ;; Ensure plugins are loaded (wookie:load-plugins) ;; Access GET parameters ;; URL: /search?q=lisp&page=2&sort=date (wookie:defroute (:get "/search") (req res) (let ((query (wookie-plugin-export:get-var req "q")) ; => "lisp" (page (wookie-plugin-export:get-var req "page")) ; => "2" (sort-by (wookie-plugin-export:get-var req "sort")) ; => "date" (missing (wookie-plugin-export:get-var req "foo"))) ; => NIL (wookie:send-response res :body (format nil "Search: ~a, Page: ~a, Sort: ~a" query page sort-by)))) ;; Using the http-var plugin for flexible parameter access ;; Checks GET, POST, and multipart in configurable order (wookie:defroute (:get "/flexible") (req res) (let ((value (wookie-plugin-export:http-var req "param" :order '(:get :post :multipart)))) (wookie:send-response res :body (or value "No value")))) ``` -------------------------------- ### GET /search - Accessing Query Parameters Source: https://context7.com/orthecreedence/wookie/llms.txt This endpoint shows how to retrieve and parse query parameters from the URI of a GET request. ```APIDOC ## GET /search ### Description This endpoint shows how to retrieve and parse query parameters from the URI of a GET request. ### Method GET ### Endpoint /search ### Parameters #### Path Parameters None #### Query Parameters - **q** (string) - The search term. - **page** (string) - The page number for search results. #### Request Body None ### Request Example ```json { "example": "This is a sample request body, if applicable." } ``` ### Response #### Success Response (200) - **body** (string) - A formatted string indicating the search term. #### Response Example ```json { "example": "Searching for: search term" } ``` ``` -------------------------------- ### Serve Static Files with Directory Router Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet shows how to use the directory router plugin to serve static files from specified filesystem paths. It covers serving files with and without directory listings, and how to set up a catch-all 404 handler. ```lisp (wookie:load-plugins) ;; Serve static files from ./public directory at /static route (wookie-plugin-export:def-directory-route "/static" "./public/") ;; Serve files without directory listings (wookie-plugin-export:def-directory-route "/assets" "./assets/" :disable-directory-listing t) ;; Serve from root path (wookie-plugin-export:def-directory-route "/" "./www/") ;; Add a catch-all 404 handler after directory routes (wookie:defroute (:get ".*" :priority -100) (req res) (wookie:send-response res :status 404 :body "Not Found")) ``` -------------------------------- ### Virtual Host Routing with with-vhost in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt The `with-vhost` macro scopes route definitions to specific domain names. This is useful for multi-tenant applications running on a single server. It allows different routes to be served based on the incoming request's host header. ```lisp (wookie:with-vhost "api.example.com" (wookie:defroute (:get "/") (req res) (wookie:send-response res :body "API Server")) (wookie:defroute (:get "/v1/status") (req res) (wookie:send-response res :headers '(:content-type "application/json") :body "{\"status\": \"ok\"}"))) (wookie:with-vhost "www.example.com" (wookie:defroute (:get "/") (req res) (wookie:send-response res :headers '(:content-type "text/html") :body "

Welcome

"))) ;; Routes without vhost respond to all domains (wookie:defroute (:get "/health") (req res) (wookie:send-response res :body "OK")) ``` -------------------------------- ### Virtual Host Routing with with-vhost Source: https://context7.com/orthecreedence/wookie/llms.txt The `with-vhost` macro scopes route definitions to specific domain names, enabling multi-tenant applications on a single server. Routes defined within `with-vhost` will only respond to requests matching the specified domain. ```APIDOC ## Virtual Host Routing with with-vhost The `with-vhost` macro scopes route definitions to specific domain names, enabling multi-tenant applications on a single server. ### Description Defines routes that are scoped to a specific virtual host (domain name). ### Method MACRO ### Endpoint N/A (Macro definition) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```lisp (wookie:with-vhost "api.example.com" (wookie:defroute (:get "/") (req res) (wookie:send-response res :body "API Server"))) ``` ### Response #### Success Response (200) Depends on the routes defined within the macro. #### Response Example For `api.example.com`: ``` API Server ``` For `www.example.com`: ```html

Welcome

``` ``` -------------------------------- ### Dynamic Route Management in Wookie Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet illustrates how to dynamically manage routes in Wookie at runtime. It covers clearing all routes, clearing specific routes by method and resource, and using `next-route` to pass control to the next matching route handler. ```lisp ;; Clear all routes (wookie:clear-routes) ;; Clear a specific route by method and resource (wookie:clear-route :get "/old-endpoint") (wookie:clear-route :post "/deprecated-api") ;; Skip to next matching route from within a route handler (wookie:defroute (:get "/conditional") (req res) (let ((headers (wookie:request-headers req))) (if (wookie:get-header headers "x-special") (wookie:send-response res :body "Special handling") ;; Pass to next matching route (wookie:next-route)))) ;; Fallback route catches requests that called next-route (wookie:defroute (:get "/conditional" :priority -1) (req res) (wookie:send-response res :body "Default handling")) ``` -------------------------------- ### Cookie Handling with cookie-var and set-cookie in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt Demonstrates reading cookies using `cookie-var` and setting cookies with attributes like path, http-only, secure, max-age, domain, and expires using `set-cookie` in Lisp. It also shows how to clear a cookie by setting its max-age to 0. ```lisp (wookie:load-plugins) ;; Read cookies from request (wookie:defroute (:get "/dashboard") (req res) (let ((session-id (wookie-plugin-export:cookie-var req "session_id")) (preferences (wookie-plugin-export:cookie-var req "prefs"))) (if session-id (wookie:send-response res :body (format nil "Welcome back! Session: ~a" session-id)) (wookie:send-response res :status 401 :body "Please log in")))) ;; Set cookies in response (wookie:defroute (:post "/login") (req res) ;; Set a session cookie (wookie-plugin-export:set-cookie res "session_id" "abc123xyz" :path "/" :http-only t :secure t :max-age 3600) ; 1 hour ;; Set a persistent cookie with expiration (wookie-plugin-export:set-cookie res "remember_me" "user@example.com" :path "/" :domain ".example.com" :expires "Thu, 01 Jan 2025 00:00:00 GMT") (wookie:send-response res :status 200 :body "Logged in successfully")) ;; Clear a cookie by setting max-age to 0 (wookie:defroute (:post "/logout") (req res) (wookie-plugin-export:set-cookie res "session_id" "" :path "/" :max-age 0) (wookie:send-response res :body "Logged out")) ``` -------------------------------- ### Access Request Details (Method, URI, Headers, Body) in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt Demonstrates how to access the HTTP method, URI, resource path, headers, and raw body from a Wookie request object. It also shows how to extract specific header values and send a response. This method is suitable for basic request introspection. ```lisp (wookie:defroute (:post "/api/process") (req res) ;; Access request method (let ((method (wookie:request-method req)) ; => :POST ;; Access the full URI object (uri (wookie:request-uri req)) ;; Access the resource path (resource (wookie:request-resource req)) ; => "/api/process" ;; Access headers (hash table) (headers (wookie:request-headers req)) ;; Access raw body bytes (when request-store-body is t) (body (wookie:request-body req))) ;; Get specific header values (let ((content-type (wookie:get-header headers "content-type")) (user-agent (wookie:get-header headers "user-agent")) (auth (wookie:get-header headers "authorization"))) (wookie:send-response res :headers '(:content-type "application/json") :body (format nil "{\"method\": \"~a\", \"path\": \"~a\"}" method resource))))) ;; Accessing query parameters via URI (wookie:defroute (:get "/search") (req res) (let* ((uri (wookie:request-uri req)) (query-params (quri:uri-query-params uri))) ;; query-params is an alist: (("q" . "search term") ("page" . "1")) (let ((search-term (cdr (assoc "q" query-params :test #'string=)))) (wookie:send-response res :body (format nil "Searching for: ~a" search-term))))) ``` -------------------------------- ### POST /api/process - Accessing Request Details Source: https://context7.com/orthecreedence/wookie/llms.txt This endpoint demonstrates how to access various components of an incoming POST request, including the HTTP method, URI, resource path, headers, and raw body. ```APIDOC ## POST /api/process ### Description This endpoint demonstrates how to access various components of an incoming POST request, including the HTTP method, URI, resource path, headers, and raw body. ### Method POST ### Endpoint /api/process ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (demonstrates accessing raw body if `request-store-body` is enabled) ### Request Example ```json { "example": "This is a sample request body, if applicable." } ``` ### Response #### Success Response (200) - **method** (string) - The HTTP method of the request. - **path** (string) - The resource path of the request. #### Response Example ```json { "method": "POST", "path": "/api/process" } ``` ``` -------------------------------- ### Streaming Responses with start-response and finish-response in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt The `start-response` and `finish-response` functions facilitate streaming HTTP responses using chunked transfer encoding. This is ideal for sending large amounts of data or dynamically generated content without buffering the entire response in memory. ```lisp ;; Stream a large response in chunks (wookie:defroute (:get "/stream") (req res) (let ((stream (wookie:start-response res :status 200 :headers '(:content-type "text/plain")))) ;; Write data in chunks (dotimes (i 10) (write-sequence (babel:string-to-octets (format nil "Chunk ~a~%" i) :encoding :utf-8) stream) (force-output stream)) ;; Finalize the response (wookie:finish-response res)) ;; Server-sent events style streaming (wookie:defroute (:get "/events") (req res) (let ((stream (wookie:start-response res :headers '(:content-type "text/event-stream" :cache-control "no-cache")))) (flet ((send-event (data) (write-sequence (babel:string-to-octets (format nil "data: ~a~%~%" data) :encoding :utf-8) stream) (force-output stream))) (send-event "Connected") (send-event "{\"type\": \"update\", \"value\": 42}") (wookie:finish-response res)))) ``` -------------------------------- ### Chunked Response Streaming with start-response and finish-response Source: https://context7.com/orthecreedence/wookie/llms.txt The `start-response` and `finish-response` functions enable streaming responses using HTTP chunked transfer encoding. This is useful for large or dynamically generated content. ```APIDOC ## Chunked Response Streaming with start-response and finish-response The `start-response` and `finish-response` functions enable streaming responses using HTTP chunked transfer encoding for large or dynamically generated content. ### Description Allows for streaming response data in chunks, suitable for large responses or server-sent events. ### Method FUNCTIONS (Pair) ### Endpoint N/A (Function definitions) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```lisp ;; Stream a large response in chunks (wookie:defroute (:get "/stream") (req res) (let ((stream (wookie:start-response res :status 200 :headers '(:content-type "text/plain")))) ;; Write data in chunks (dotimes (i 10) (write-sequence (babel:string-to-octets (format nil "Chunk ~a~%" i) :encoding :utf-8) stream) (force-output stream)) ;; Finalize the response (wookie:finish-response res)) ;; Server-sent events style streaming (wookie:defroute (:get "/events") (req res) (let ((stream (wookie:start-response res :headers '(:content-type "text/event-stream" :cache-control "no-cache")))) (flet ((send-event (data) (write-sequence (babel:string-to-octets (format nil "data: ~a~%~%" data) :encoding :utf-8) stream) (force-output stream))) (send-event "Connected") (send-event "{\"type\": \"update\", \"value\": 42}") (wookie:finish-response res)))) ``` ### Response #### Success Response (200) Data is streamed to the client in chunks. The `Content-Type` header dictates the format. #### Response Example For `/stream`: ``` Chunk 0 Chunk 1 Chunk 2 ... Chunk 9 ``` For `/events` (Server-Sent Events): ``` data: Connected data: {"type": "update", "value": 42} ``` ``` -------------------------------- ### Wookie Global Configuration Options Source: https://context7.com/orthecreedence/wookie/llms.txt This snippet shows how to configure global Wookie settings. It covers enabling debug mode, setting maximum request body size, hiding the Wookie version in the Server header, configuring enabled plugins before loading, and setting a temporary file storage location for uploads. ```lisp ;; Enable debug mode - errors won't be caught, allows debugger access (setf wookie-config:*debug-on-error* t) ;; Set maximum request body size (default: 2MB) (setf wookie-config:*max-body-size* (* 1024 1024 10)) ; 10MB ;; Hide Wookie version in Server header (setf wookie-config:*hide-version* t) ;; Configure enabled plugins before loading (setf wookie-config:*enabled-plugins* '(:get :post :cookie)) ;; Set temporary file storage location for uploads (setf wookie-config:*tmp-file-store* #P"/tmp/wookie-uploads/") ``` -------------------------------- ### Cookie Handling API Source: https://context7.com/orthecreedence/wookie/llms.txt APIs for reading and setting cookies with support for various attributes like path, http-only, secure, max-age, and expiration. ```APIDOC ## GET /dashboard ### Description Reads session and preference cookies from the incoming request. Responds with a welcome message if a session ID is found, otherwise returns a 401 Unauthorized status. ### Method GET ### Endpoint /dashboard ### Parameters #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **body** (string) - Welcome message including the session ID. #### Error Response (401) - **body** (string) - "Please log in" #### Response Example ``` Welcome back! Session: abc123xyz ``` ## POST /login ### Description Handles user login by setting session and remember-me cookies in the response. Supports various cookie attributes for security and persistence. ### Method POST ### Endpoint /login ### Parameters #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **body** (string) - "Logged in successfully" #### Response Example ``` Logged in successfully ``` ## POST /logout ### Description Handles user logout by clearing the session cookie by setting its max-age to 0. ### Method POST ### Endpoint /logout ### Parameters #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **body** (string) - "Logged out" #### Response Example ``` Logged out ``` ``` -------------------------------- ### Handle POST Parameters with post-var Plugin in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt This code demonstrates using the `post-var` plugin to retrieve form data from POST requests. It covers handling both URL-encoded data and JSON payloads. The `plugin-request-data` function is also shown for accessing parsed JSON bodies. ```lisp (wookie:load-plugins) ;; Handle URL-encoded form POST ;; Content-Type: application/x-www-form-urlencoded ;; Body: username=john&password=secret (wookie:defroute (:post "/login") (req res) (let ((username (wookie-plugin-export:post-var req "username")) (password (wookie-plugin-export:post-var req "password"))) (if (and username password) (wookie:send-response res :headers '(:content-type "application/json") :body (format nil "{\"user\": \"~a\", \"authenticated\": true}" username)) (wookie:send-response res :status 400 :body "Missing credentials")))) ;; Handle JSON POST body ;; Content-Type: application/json ;; Body: {"name": "John", "email": "john@example.com"} (wookie:defroute (:post "/api/users") (req res) ;; For JSON, post-var returns parsed JSON object (let ((data (wookie:plugin-request-data :post-vars req))) ;; data is a hash table or parsed JSON structure (wookie:send-response res :status 201 :headers '(:content-type "application/json") :body "{\"created\": true}"))) ``` -------------------------------- ### Hook System API Source: https://context7.com/orthecreedence/wookie/llms.txt Allows intercepting and modifying the request lifecycle at various stages using named hooks. Hooks can be added, removed, or cleared. ```APIDOC ## Hook Management ### Description Provides functions to manage hooks that intercept the request lifecycle at predefined stages. Hooks can be added with unique names for later management. ### Methods - **wookie:add-hook** (type, function, name) - Adds a hook function to a specific lifecycle stage. - `type`: The lifecycle stage (e.g., `:pre-route`, `:parsed-headers`). - `function`: The callback function to execute. - `name`: A unique string identifier for the hook. - **wookie:remove-hook** (type, name) - Removes a specific hook by its type and name. - **wookie:clear-hooks** (type=nil) - Removes all hooks of a specified type, or all hooks if no type is provided. ### Lifecycle Stages - **`:parsed-headers`**: After request headers are parsed. - **`:pre-route`**: Before the request is routed to a handler. - **`:body-chunk`**: For each chunk of the request body received. - **`:body-complete`**: When the entire request body has been received. - **`:response-started`**: Just before the response is sent to the client. ### Example Usage #### Adding Hooks ```lisp ;; Add authentication hook (wookie:add-hook :pre-route (lambda (request response) (let* ((headers (wookie:request-headers request)) (auth-header (wookie:get-header headers "authorization"))) (unless (and auth-header (string= auth-header "Bearer valid-token")) (wookie:send-response response :status 401 :body "Unauthorized") (error "Unauthorized request")))) :auth-check) ;; Add logging hook (wookie:add-hook :parsed-headers (lambda (request) (format t "[~a] ~a ~a~%" (get-universal-time) (wookie:request-method request) (wookie:request-resource request))) :request-logger) ``` #### Removing Hooks ```lisp ;; Remove authentication hook (wookie:remove-hook :pre-route :auth-check) ;; Clear all parsed-headers hooks (wookie:clear-hooks :parsed-headers) ;; Clear all hooks (wookie:clear-hooks) ``` ``` -------------------------------- ### Sending Responses with send-response Source: https://context7.com/orthecreedence/wookie/llms.txt The `send-response` function sends a complete HTTP response. It allows specifying the status code, headers, and body content for the response. ```APIDOC ## Sending Responses with send-response The `send-response` function sends a complete HTTP response with status code, headers, and body content. ### Description Sends a fully formed HTTP response to the client. ### Method FUNCTION ### Endpoint N/A (Function definition) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```lisp ;; Basic text response (wookie:defroute (:get "/text") (req res) (wookie:send-response res :body "Plain text response")) ;; JSON response with custom status and headers (wookie:defroute (:get "/api/data") (req res) (wookie:send-response res :status 200 :headers '(:content-type "application/json" :cache-control "max-age=3600" :x-custom-header "custom-value") :body "{\"data\": [1, 2, 3]}")) ;; Redirect response (wookie:defroute (:get "/old-path") (req res) (wookie:send-response res :status 301 :headers '(:location "/new-path") :body "")) ``` ### Response #### Success Response (200) Returns the specified status code, headers, and body. #### Response Example For `/text`: ``` Plain text response ``` For `/api/data`: ```json { "data": [ 1, 2, 3 ] } ``` For `/old-path` (301 Redirect): Headers will include `Location: /new-path`. ``` -------------------------------- ### Multipart Form Data and File Uploads in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt Handles file uploads and multipart form data using `file-upload` and `form-var` in Lisp. Uploaded files are stored in temporary locations and their information (filename, temp file path, MIME type) is returned. The temporary file is automatically deleted after the response is sent. ```lisp (wookie:load-plugins) ;; Handle file upload ;; Form field: file (type=file), description (text field) (wookie:defroute (:post "/upload") (req res) (let ((file-info (wookie-plugin-export:file-upload req "file")) (description (wookie-plugin-export:form-var req "description"))) (if file-info ;; file-info is a plist: (:filename "photo.jpg" :tmp-file "/tmp/wookie123" :mime-type "image/jpeg") (let ((original-name (getf file-info :filename)) (tmp-path (getf file-info :tmp-file))) ;; Process the file (copy to permanent location, etc.) (format t "Uploaded: ~a to ~a~%" original-name tmp-path) ;; Note: tmp file is automatically deleted after response is sent (wookie:send-response res :headers '(:content-type "application/json") :body (format nil "{\"filename\": \"~a\", \"description\": \"~a\"}" original-name (or description ""))) (wookie:send-response res :status 400 :body "No file uploaded")))) ;; Multiple file uploads (wookie:defroute (:post "/upload-multiple") (req res) (let ((file1 (wookie-plugin-export:file-upload req "file1")) (file2 (wookie-plugin-export:file-upload req "file2"))) (wookie:send-response res :body (format nil "Files received: ~a, ~a" (when file1 (getf file1 :filename)) (when file2 (getf file2 :filename)))))) ``` -------------------------------- ### Sending HTTP Responses with send-response in Lisp Source: https://context7.com/orthecreedence/wookie/llms.txt The `send-response` function constructs and sends a complete HTTP response. It supports specifying status codes, headers, and the response body. This function is fundamental for handling client requests and returning appropriate data. ```lisp ;; Basic text response (wookie:defroute (:get "/text") (req res) (wookie:send-response res :body "Plain text response")) ;; JSON response with custom status and headers (wookie:defroute (:get "/api/data") (req res) (wookie:send-response res :status 200 :headers '(:content-type "application/json" :cache-control "max-age=3600" :x-custom-header "custom-value") :body "{\"data\": [1, 2, 3]}")) ;; Error response (wookie:defroute (:get "/error") (req res) (wookie:send-response res :status 500 :headers '(:content-type "text/plain") :body "Internal Server Error")) ;; Redirect response (wookie:defroute (:get "/old-path") (req res) (wookie:send-response res :status 301 :headers '(:location "/new-path") :body "")) ;; Force connection close after response (wookie:defroute (:get "/close-after") (req res) (wookie:send-response res :body "Goodbye" :close t)) ``` -------------------------------- ### Multipart Form Data and File Uploads API Source: https://context7.com/orthecreedence/wookie/llms.txt Handles multipart form data and file uploads, storing uploaded files in temporary locations. Provides APIs to access uploaded file information and form variables. ```APIDOC ## POST /upload ### Description Handles single file uploads and associated form data. Extracts file information (filename, temporary path, MIME type) and form variables. The temporary file is automatically deleted after the response is sent. ### Method POST ### Endpoint /upload ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **file** (file) - The file to be uploaded. - **description** (string) - Optional text description for the uploaded file. ### Request Example None (typically sent as multipart/form-data) ### Response #### Success Response (200) - **body** (string) - JSON string containing the filename and description of the uploaded file. #### Error Response (400) - **body** (string) - "No file uploaded" #### Response Example ```json {"filename": "photo.jpg", "description": "A picture of the beach"} ``` ## POST /upload-multiple ### Description Handles multiple file uploads within the same request. ### Method POST ### Endpoint /upload-multiple ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **file1** (file) - The first file to be uploaded. - **file2** (file) - The second file to be uploaded. ### Request Example None (typically sent as multipart/form-data) ### Response #### Success Response (200) - **body** (string) - A string indicating the filenames of the received files. #### Response Example ``` Files received: file1.jpg, document.pdf ``` ``` -------------------------------- ### POST /login - Accessing URL-encoded Form Data Source: https://context7.com/orthecreedence/wookie/llms.txt This endpoint handles POST requests with URL-encoded form data, extracting username and password. ```APIDOC ## POST /login ### Description This endpoint handles POST requests with URL-encoded form data, extracting username and password. ### Method POST ### Endpoint /login ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **username** (string) - The username for login. - **password** (string) - The password for login. ### Request Example ```json { "example": "username=john&password=secret" } ``` ### Response #### Success Response (200) - **body** (string) - JSON indicating successful authentication. #### Error Response (400) - **body** (string) - Error message indicating missing credentials. #### Response Example ```json { "example": "{\"user\": \"john\", \"authenticated\": true}" } ``` ``` -------------------------------- ### POST /api/users - Accessing JSON POST Body Source: https://context7.com/orthecreedence/wookie/llms.txt This endpoint processes POST requests with a JSON body, typically used for creating new resources. ```APIDOC ## POST /api/users ### Description This endpoint processes POST requests with a JSON body, typically used for creating new resources. ### Method POST ### Endpoint /api/users ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **name** (string) - The name of the user. - **email** (string) - The email address of the user. ### Request Example ```json { "name": "John", "email": "john@example.com" } ``` ### Response #### Success Response (201) - **body** (string) - JSON indicating successful resource creation. #### Response Example ```json { "created": true } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.