Skip to main content

What is the API Documentation System?

The API documentation system in pb-ext automatically generates OpenAPI 3.0.3 specifications from your Go source code using Abstract Syntax Tree (AST) parsing. This means you write normal Go handlers, and the system extracts:
  • Request and response schemas
  • Query, header, and path parameters
  • Authentication requirements
  • Endpoint descriptions and tags
All of this happens at startup by analyzing your handler functions, struct definitions, and PocketBase patterns.
The system operates in two modes: development (runtime AST parsing) and production (pre-generated specs loaded from disk).

Key Capabilities

Auto-Detection Without Annotations

The AST parser automatically detects:
WhatHow it’s detected
Request bodyc.BindBody(&req) or json.NewDecoder(c.Request.Body).Decode(&req)
Response schemac.JSON(status, data) — analyzes the second argument
Query parametersc.Request.URL.Query().Get("name")
Header parametersc.Request.Header.Get("name")
Path parametersc.Request.PathValue("id")
AuthenticationPocketBase auth middleware patterns (apis.RequireAuth())

Indirect Parameter Detection

If your handler calls a helper function like parseTimeParams(e *core.RequestEvent), the system follows that call and extracts the parameters the helper reads. This works for both:
  • Domain helpers — read specific params by name
  • Generic helpers — read params via function arguments (e.g., parseIntParam(e, "page", 0))
// Helper function reads params
func parseTimeParams(e *core.RequestEvent) timeParams {
    q := e.Request.URL.Query()
    return timeParams{
        Interval: q.Get("interval"),
        From:     q.Get("from"),
        To:       q.Get("to"),
    }
}

// Handler calls helper — params automatically detected
func getDataHandler(e *core.RequestEvent) error {
    params := parseTimeParams(e)
    // ...
}
The OpenAPI spec will include interval, from, and to as query parameters for getDataHandler.

Development vs Production Modes

Development Mode (Runtime AST)

  • Source files marked with // API_SOURCE are parsed on server startup
  • AST analysis runs every time the server starts
  • Full pipeline: struct extraction → helper analysis → handler parsing → OpenAPI generation
  • Best for rapid iteration and debugging

Production Mode (Embedded Specs)

  • OpenAPI specs are generated during pb-cli --production build
  • Specs are saved to dist/specs/ as JSON files
  • Server reads specs from disk on startup (no AST parsing)
  • Faster startup, deterministic output
Production builds use PB_EXT_OPENAPI_SPECS_DIR to locate the specs directory. If not set, the server looks for specs/ relative to the binary.

Accessing Documentation

Swagger UI (Interactive)

Each API version with PublicSwagger: true gets a Swagger UI interface:
GET /api/docs/v1/swagger
GET /api/docs/v2/swagger
The Swagger UI includes dark mode CSS (SwaggerDark by Amoenus, MIT licensed) for a better viewing experience.

OpenAPI Spec (JSON)

Public access to the OpenAPI spec (no auth required when PublicSwagger: true):
GET /api/docs/v1/spec
GET /api/docs/v2/spec
Authenticated access (superuser auth required):
GET /api/docs/v1
GET /api/docs/v2

Debug Endpoint (Full Pipeline Introspection)

For debugging the AST parsing pipeline:
GET /api/docs/debug/ast
Requires superuser authentication. Returns the complete internal state: all parsed structs, handlers, parameters, schemas, and the final OpenAPI output for each version.

What the Debug Endpoint Shows

  • Structs: All parsed struct definitions with their JSON schemas
  • Handlers: All detected handlers with request/response types and parameters
  • Endpoints: Per-version endpoint list with metadata
  • Component Schemas: All OpenAPI component schemas
  • OpenAPI Output: Complete OpenAPI 3.0.3 spec for each version
{
  "structs": {
    "TodoRequest": {
      "name": "TodoRequest",
      "fields": [...],
      "jsonSchema": {...}
    }
  },
  "handlers": {
    "getTodosHandler": {
      "name": "getTodosHandler",
      "description": "Get all todos with optional filtering",
      "tags": ["Todos"],
      "requestSchema": null,
      "responseSchema": {...},
      "parameters": [{"name": "completed", "source": "query"}, ...]
    }
  },
  "versions": {
    "v1": {
      "endpoints": [...],
      "componentSchemas": {...},
      "openapi": {...}
    }
  }
}

Source File Directives

Three directives control AST parsing:
DirectiveLocationPurpose
// API_SOURCETop of .go fileMarks file for AST parsing
// API_DESC <text>Before handler functionSets OpenAPI description
// API_TAGS <csv>Before handler functionComma-separated tags
// API_SOURCE
package main

import (
    "net/http"
    "github.com/pocketbase/pocketbase/core"
)

// API_DESC Get all todos with optional filtering
// API_TAGS Todos
func getTodosHandler(c *core.RequestEvent) error {
    // Handler implementation
    return c.JSON(http.StatusOK, map[string]any{"todos": []})
}

Next Steps

OpenAPI System Deep Dive

Learn how AST parsing detects schemas and parameters

Versioned Routing

Manage multiple API versions with isolated registries

Route Registration

Register routes manually or use CRUD helpers

Annotations Reference

Complete guide to source file directives

Build docs developers (and LLMs) love