Skip to content

5. API docs

The app has served Swagger UI at /docs since chapter 1. The spec comes from the code: each route's path, its params, query and body types, and the type a handler returns. .docs on a route adds a summary and the responses it can give.

Authorize with the key

Two settings make Swagger UI's Authorize button send the key: bearer_auth on the plugin adds the scheme, and .bearer_auth = true in a route's docs marks it as needing it (the three writes in the controller).

In production too

The scaffold serves the docs only in development (disable_in_prod = true). This API is meant to be used by others, so it keeps them: the spec only describes the API, and the writes still need the key.

src/main.zig
const std = @import("std");
const kzig = @import("kzig");
const Config = @import("config.zig").Config;
const modules = @import("modules.zig").modules;
const DbAdapter = @import("adapters/db.adapter.zig").DbAdapter;

pub const App = kzig.App(.{
    .modules = modules,
    .config = Config,
    .adapters = &.{DbAdapter},
    .middleware = .{
        kzig.middleware.requestId(),
        kzig.middleware.requestLogger(.{ .skip = &.{"/health"} }),
        kzig.middleware.helmet(.{}),
    },
    // /openapi.json, /docs (Swagger UI), /redoc — in production too: the
    // spec only describes the API, and writes still need the key.
    .plugins = &.{kzig.swagger.Plugin(.{
        .info = .{ .title = "Bookmarks API", .version = "0.1.0", .description = "Save links; writes take `Authorization: Bearer <API_KEY>`." },
        .bearer_auth = true,
    })},
});

pub fn main(init: std.process.Init) !void {
    var app: App = undefined;
    try app.init(init.io, init.gpa, init.environ_map);
    defer app.deinit();
    // Until SIGINT/SIGTERM, then drains in-flight requests.
    const config = app.get(Config);
    try kzig.runtime.std.serve(App, &app, init.io, init.gpa, .{ .host = config.host, .port = config.port });
}

test {
    _ = @import("modules/hello/hello.test.zig");
    _ = @import("modules/bookmarks/bookmark.test.zig");
    // kzig:tests
}
Path What
/docs Swagger UI: try each route; Authorize with the API key first for the writes
/redoc ReDoc, for reading
/openapi.json The OpenAPI 3.0 spec, for clients and code generators
$ curl -s localhost:3000/openapi.json | head -c 120
{"openapi":"3.0.3","info":{"title":"Bookmarks API","version":"0.1.0","description":"Save links; writes take `Authorization: …

Next, tests.