Chapter 3: Hello World Explained in Swift

In this chapter, we will take the Hello World example apart line by line. Understanding every piece now will make the rest of the tutorial much easier.

The Code

import Kungfu

let app = Kungfu()
app.get("/hello") { req, res in res.text("world") }
app.run(port: 3000)

Line by Line Breakdown

1. Importing Kungfu

The first line imports the Kungfu.js library. This gives you access to the Kungfu class, which is the main entry point for creating a web application.

Think of this like opening a toolbox. Until you open it, you cannot use any of the tools inside.

2. Creating the Application

The next line creates a new Kungfu application instance. This object holds your routes, middleware, and configuration. Everything you do with Kungfu.js starts here.

Behind the scenes, this initializes:

  • A trie-based router (for fast URL matching)
  • A middleware pipeline (for request processing)
  • A buffer pool (for memory-efficient request handling)
  • An OpenAPI spec generator (for auto-documentation)

3. Registering a Route

The .get("/hello", handler) line registers a route. It tells the router: "When a GET request comes in for the path /hello, call this handler function."

The handler function receives a request object and returns a response. In Swift, the response is an object with status and body properties.

4. Starting the Server

The .listen(3000) line starts the HTTP server on port 3000. This is a blocking call: the server will run forever, listening for connections, until you press Ctrl+C to stop it.

When a request arrives, here is the exact sequence of events:

  1. The Rust core accepts the TCP connection
  2. It reads the raw HTTP bytes from the socket
  3. It parses the HTTP request (method, path, headers, body)
  4. It looks up the path in the trie router
  5. It runs the middleware chain (security headers, CORS, rate limiter, logger)
  6. It calls your handler function
  7. Your function returns a response
  8. The middleware chain runs again in reverse (adding response headers)
  9. The Rust core formats the response as HTTP bytes
  10. It sends the bytes back to the client

All of this happens in microseconds. The Rust core is doing the heavy lifting; your Swift code only runs for step 6.

The Request Object

Your handler function receives a request object. Here is what it contains:

{
  "method": "GET",
  "path": "/hello",
  "query": {},           // parsed query string parameters
  "params": {},          // route parameters (we will cover in chapter 6)
  "headers": {           // all HTTP headers (lowercase keys)
    "host": "localhost:3000",
    "user-agent": "Mozilla/5.0..."
  },
  "body": "",            // request body (for POST/PUT)
  "remote_addr": "127.0.0.1:54321"
}

The Response Object

Your handler returns a response. The simplest response has two fields:

  • status: The HTTP status code (200 for OK, 404 for Not Found, etc.)
  • body: The response body as a string

You can also add custom headers:

return {
  status: 200,
  headers: { "x-custom-header": "hello" },
  body: "world"
};

Why is the Server So Fast?

The Rust core uses several techniques to achieve high throughput:

  • Zero-copy body handling: Request and response bodies use bytes::Bytes, which avoids copying memory. Cloning a Bytes object is just incrementing a counter.
  • Trie router: URL routing is O(path depth), not O(number of routes). Whether you have 10 routes or 10,000, lookup takes the same time.
  • Buffer pooling: Instead of allocating new memory for every request, the server reuses buffers from a pool. This reduces garbage collection pressure.
  • Single-syscall writes: The entire response (status line, headers, body) is built into one buffer and sent with a single write_all call.

What is Next?

In chapter 4, we will look at how to structure a real Kungfu.js project with multiple files, configuration, and best practices.