Building Web Apps with Hummingbird

Hummingbird is a lightweight, modern web framework for Swift that embraces async/await and structured concurrency.

Why Hummingbird?

Minimalism

Unlike Vapor, Hummingbird has a minimal core. You only add what you need:

import Hummingbird

@main
struct MyApp {
    static func main() async throws {
        let router = Router()
        router.get("/") { _, _ in
            return "Hello, World!"
        }

        let app = Application(
            router: router,
            configuration: .init(address: .hostname("0.0.0.0", port: 8080))
        )

        try await app.runService()
    }
}

Modern Swift

Built from the ground up with Swift Concurrency:

router.get("/users/:id") { request, context in
    guard let id = context.parameters.get("id") else {
        throw HTTPError(.badRequest)
    }

    let user = try await userService.fetchUser(id: id)
    return try JSONEncoder().encode(user)
}

Middleware

Composable middleware for cross-cutting concerns:

// Logging middleware
router.add(middleware: LogRequestsMiddleware())

// CORS middleware
router.add(middleware: CORSMiddleware())

// Authentication
router.group()
    .add(middleware: JWTAuthMiddleware())
    .get("/protected") { _, _ in
        return "Secret data"
    }

Template Rendering

Use HummingbirdMustache for server-side rendering:

import HummingbirdMustache

let mustache = MustacheLibrary("Templates/")

router.get("/users/:id") { request, context in
    let id = context.parameters.require("id")
    let user = try await userService.fetchUser(id: id)

    return mustache.render(
        "user",
        context: [
            "name": user.name,
            "email": user.email
        ]
    )
}

File Uploads

Handle file uploads with multipart parsing:

router.post("/upload") { request, context in
    guard let multipart = try? await request.decode(as: MultipartFormData.self) else {
        throw HTTPError(.badRequest)
    }

    for part in multipart.parts {
        if part.name == "file", let filename = part.filename {
            try await saveFile(data: part.body, filename: filename)
        }
    }

    return Response(status: .ok)
}

Conclusion

Hummingbird brings modern Swift to server-side development. Its minimal design and native async/await support make it a great choice for new projects.

Try it out for your next web service!