Quick Start
This guide walks you through building a small pidgn application with routes, middleware, and JSON responses.
Hello World
Section titled “Hello World”-
Create a new project
Terminal window pidgn new hello_pidgncd hello_pidgn -
Open
src/main.zigand replace its contents with:const std = @import("std");const pidgn = @import("pidgn");fn index(ctx: *pidgn.Context) !void {ctx.text(.ok, "Hello from pidgn!");}const App = pidgn.Router.define(.{.middleware = &.{pidgn.logger},.routes = &.{pidgn.Router.get("/", index),},});pub fn main() !void {var gpa = std.heap.GeneralPurposeAllocator(.{}){};defer _ = gpa.deinit();var server = pidgn.Server.init(gpa.allocator(), .{.port = 4000,}, &App.handler);std.log.info("Listening on http://127.0.0.1:4000", .{});try server.listen(std.io.defaultIo());} -
Run it
Terminal window zig build runVisit
http://127.0.0.1:4000— you should see “Hello from pidgn!”.
Adding middleware
Section titled “Adding middleware”pidgn ships with 20 built-in middleware. Let’s add a few common ones:
const App = pidgn.Router.define(.{ .middleware = &.{ pidgn.errorHandler(.{ .show_details = true }), pidgn.logger, pidgn.requestId(.{}), pidgn.cors(.{ .allow_origins = &.{"*"} }), pidgn.bodyParser(.{}), pidgn.staticFiles(.{ .root = "public", .prefix = "/static" }), }, .routes = &.{ pidgn.Router.get("/", index), },});Middleware runs in the order listed — put error handling first so it catches everything downstream.
JSON routes
Section titled “JSON routes”Add a route that returns JSON:
fn getUser(ctx: *pidgn.Context) !void { const user = .{ .id = 1, .name = "Alice", .email = "alice@example.com", }; try ctx.json(.ok, user);}
fn createUser(ctx: *pidgn.Context) !void { const body = try ctx.parseBody(struct { name: []const u8, email: []const u8, }); // ... save to database ... try ctx.json(.created, body);}Wire them into your router:
.routes = &.{ pidgn.Router.get("/", index), pidgn.Router.get("/users/:id", getUser), pidgn.Router.post("/users", createUser),},RESTful resources
Section titled “RESTful resources”For standard CRUD, use Router.resource to generate all routes at once:
.routes = &.{ pidgn.Router.resource("/posts", .{ .index = listPosts, .show = showPost, .create = createPost, .update = updatePost, .delete_handler = deletePost, }),},This generates GET /posts, GET /posts/:id, POST /posts, PUT /posts/:id, and DELETE /posts/:id.
Scoped routes with auth
Section titled “Scoped routes with auth”Group routes under a prefix with shared middleware:
.routes = &.{ pidgn.Router.get("/", index),
pidgn.Router.scope("/api", .{ .middleware = &.{ pidgn.bearerAuth(.{ .validate = &myValidator }) }, }, &.{ pidgn.Router.get("/me", currentUser), pidgn.Router.resource("/posts", .{ .index = listPosts, .create = createPost, }), }),},Development tools
Section titled “Development tools”For a faster development cycle, use the pidgn server command to automatically rebuild on source changes, and enable live reload for instant browser refresh:
pidgn serverIf your project uses bundled assets, run pidgn assets watch in a separate terminal. See Asset Pipeline for setup details.
Next steps
Section titled “Next steps”You now have a working pidgn application with routing, middleware, and JSON. From here:
- Learn about Routing in depth
- Add a Database
- Set up Background Jobs
- Add WebSocket Channels
- Use the Template Engine for HTML views
- Set up the Frontend toolchain (assets, live reload, SSR)