Skip to main content

Getting Started with the API

How to configure and run the Go API server locally.

Prerequisites​

  • Go 1.25 or later
  • Infrastructure running (docker compose up -d)
  • Monorepo dependencies installed (pnpm install)

Configuration​

The API loads configuration from environment variables. Each component defines its own config struct and parses only the variables it needs at startup.

Setting up your .env​

Copy the example file:

cp apps/api/.env.example apps/api/.env

Edit apps/api/.env with your local values. The .env file is gitignored and loaded automatically on startup — real environment variables always take precedence.

Environment variables​

Common​

These are shared across all components via config.Base:

VariableDefaultDescription
APP_ENVdevelopmentEnvironment name (development, production)
LOG_LEVELinfoLog level (debug, info, warn, error)

Server​

VariableDefaultRequiredDescription
SERVER_PORT4000NoHTTP listen port
SERVER_READ_TIMEOUT5sNoMax duration for reading request
SERVER_WRITE_TIMEOUT10sNoMax duration for writing response
SERVER_IDLE_TIMEOUT120sNoMax duration for idle connections
SERVER_SHUTDOWN_TIMEOUT30sNoGraceful shutdown deadline
SERVER_CORS_ORIGINS—YesComma-separated allowed CORS origins

Authentication​

JWT validation against the Identity service:

VariableDefaultRequiredDescription
AUTH_JWKS_URL—YesIdentity service JWKS endpoint (e.g. https://main-identity.chompardo.dev/api/auth/jwks)
AUTH_ISSUER—YesExpected token issuer (Identity service base URL)
AUTH_AUDIENCE—YesExpected token audience (API service URL)

Database​

VariableDefaultRequiredDescription
DB_HOSTlocalhostNoPostgreSQL host
DB_PORT5432NoPostgreSQL port
DB_NAME—YesDatabase name
DB_USER—YesDatabase role
DB_PASSWORD—YesDatabase password
DB_SSLMODEdisableNoSSL mode (disable, require, verify-full)
DB_MAX_CONNS10NoMax pool connections
DB_MIN_CONNS2NoMin idle connections
DB_MAX_CONN_LIFETIME1hNoMax connection lifetime
DB_MAX_CONN_IDLE_TIME30mNoMax idle time before connection is closed
DB_AUTO_MIGRATEfalseNoRun migrations on startup (use true for local dev)

Authorization (OpenFGA)​

VariableDefaultRequiredDescription
FGA_API_URLhttp://localhost:5080NoOpenFGA HTTP API URL
FGA_STORE_ID—NoOpenFGA store ID (ULID). Noop client if unset

See the Authorization Guide for setup and usage details.

How it works​

Configuration uses caarlos0/env to parse environment variables into Go structs with struct tags:

type ServerConfig struct {
config.Base
Port int `env:"SERVER_PORT" envDefault:"4000"`
CORSOrigins []string `env:"SERVER_CORS_ORIGINS,required"`
}

At startup, config.LoadDotEnv() loads the .env file (if present), then each component calls config.MustParse[T]() to parse its own config. Missing required variables cause a panic with a clear error message.

Adding config to a module​

When a module needs configuration, add a config.go in the module root:

// internal/modules/recipe/config.go
package recipe

import "github.com/marcuslindfeldt/chompardo/apps/api/internal/config"

type Config struct {
config.Base
MaxResults int `env:"RECIPE_MAX_RESULTS" envDefault:"50"`
}

Parse it in the module's Register() or initialization function:

func Register(r chi.Router) {
cfg := config.MustParse[Config]()
// use cfg...
}

Database Migrations​

Before running the API for the first time (or after pulling new migration files), run migrations:

cd apps/api && make migrate

Alternatively, set DB_AUTO_MIGRATE=true in your .env to run migrations automatically on startup. This is convenient for local development but should be disabled in production — use the standalone cmd/migrate binary instead to avoid race conditions when multiple instances start simultaneously.

See the Database Guide for more details on writing migrations and queries.

Running the API​

pnpm dev --filter=api

Or directly with Go:

cd apps/api
go run ./cmd/api

The server starts on http://127.0.0.1:4000 (or https://main-api.chompardo.dev via Traefik).

Verify it's running​

curl http://localhost:4000/healthz
# ok

curl http://localhost:4000/openapi.yaml
# full OpenAPI spec

Code generation​

The API uses an OpenAPI-first workflow. After changing any openapi.yaml spec:

pnpm generate --filter=api

This bundles all module specs and regenerates Go server code. See Add an Endpoint and Add a Module for details.