Help us shape the future of Go! Take the 2026 Go Developer Survey

api

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Overview

Package api is `brevis-sql-api`: declared, read-only SQL served over HTTP.

THE FILE IS THE CONTRACT, as it is for the gateway: every endpoint, its parameters and its SQL, refused at load when any of it cannot be honoured. A server that starts on a file it half understood answers a readiness probe and then a caller's first request with something nobody declared.

Index

Constants

View Source
const (

	// EnvLocal is the value that leaves the API open. The engine's word.
	EnvLocal = "local"

	// LocalTenant is the tenant every request is, locally and without auth.
	LocalTenant = "local"
)
View Source
const DefaultMaxRows = 10000

DefaultMaxRows is the row ceiling when the file names none.

View Source
const ManifestVersion = 1

ManifestVersion is the shape `describe` prints. An engine that reads another refuses it by number.

Variables

This section is empty.

Functions

func Describe

func Describe(path string, cfg *Config, reg *connections.Registry) ([]byte, error)

Describe prints the manifest of a loaded file. It OPENS NOTHING: the targets come from the registry's declarations, which is why it runs where the API's credentials do not -- in a publish Job, beside the gateway's.

func KeyLine

func KeyLine(key, tenant string) (string, error)

KeyLine is the line a key list holds for one key: what `brevis-sql-api key hash` prints, so nobody hand-rolls the hash and gets the encoding wrong.

Types

type Auth

type Auth struct {
	// Type is `bearer`.
	Type string `yaml:"type"`

	// KeysFrom names the ENVIRONMENT VARIABLE holding the key list -- one
	// `<sha256 of the key, hex>=<tenant>` per line. The file is in git, and
	// the variable holds no key either: a hash is what lets an environment
	// dump, a CI log or a `kubectl describe` show this variable without
	// handing anybody a way in.
	KeysFrom string `yaml:"keys_from"`
}

Auth is who may read, and as which tenant.

THE GATEWAY'S RULE, AND ONE MORE. BREVIS_ENV=local leaves the API open and outside it the process refuses to start without a key list -- spelled the way the gateway and the engine spell it, so an operator learns one word. The addition is the TENANT: every key belongs to one, and that tenant is bound into every query as `{{ tenant }}`. A caller never says which tenant it is, so it can never say a different one.

type ByteSize

type ByteSize int64

ByteSize is a number of bytes, written `1GiB`, `512MiB` or a bare number.

func (ByteSize) String

func (b ByteSize) String() string

func (*ByteSize) UnmarshalYAML

func (b *ByteSize) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML reads binary units only. `1GB` is refused rather than read as either 10^9 or 2^30: a ceiling on money should not be off by 7% depending on which the reader assumed.

type CacheConfig

type CacheConfig struct {
	Type     string        `yaml:"type"`
	AddrFrom string        `yaml:"addr_from"`
	TTL      time.Duration `yaml:"ttl"`
	MaxEntry ByteSize      `yaml:"max_entry"`
}

CacheConfig is where answers are kept, and for how long at most.

type Config

type Config struct {
	Name       string `yaml:"name"`
	Connection string `yaml:"connection"`

	// ConnectionID is where the connection reaches, from the registry: part
	// of every cache key, so two deployments' answers never meet.
	ConnectionID string `yaml:"-"`

	// Timezone is the IANA zone `period` resolves in. UTC when absent.
	Timezone  string      `yaml:"timezone"`
	Listen    Listen      `yaml:"listen"`
	Endpoints []*Endpoint `yaml:"endpoints"`

	// Params are definitions an endpoint's parameter can name with `ref`.
	Params map[string]Param `yaml:"params"`

	// Limits bound every request; see Limits.
	Limits Limits `yaml:"limits"`

	// Cache keeps answers until a model they read is rebuilt. Absent, every
	// request reads the warehouse.
	Cache *CacheConfig `yaml:"cache"`

	// CacheKV is where the cache is kept; nil opens Cache.AddrFrom.
	CacheKV cache.KV `yaml:"-"`

	// Dialect and Open are the connection's, resolved from the registry at
	// load: a file naming a connection nobody declared is refused there,
	// not at the first request.
	Dialect dialect.Dialect                             `yaml:"-"`
	Open    func(context.Context) (dialect.Conn, error) `yaml:"-"`

	// MaxRows is the file-wide row ceiling.
	MaxRows int `yaml:"-"`

	// Metrics is where the Prometheus exposition listens.
	Metrics struct {
		Addr string `yaml:"addr"`
	} `yaml:"metrics"`

	// Audit receives one JSON line per request. Nil writes none.
	Audit io.Writer `yaml:"-"`

	// Env is BREVIS_ENV, read by the binary and never from the file: a file
	// that could declare itself local would be a file that turns off
	// authentication.
	Env string `yaml:"-"`
}

Config is one endpoint file, loaded and checked.

func Load

func Load(path string, reg *connections.Registry) (*Config, error)

Load reads an endpoint file and resolves its connection in the registry.

type Endpoint

type Endpoint struct {
	Name    string           `yaml:"name"`
	Path    string           `yaml:"path"`
	Params  map[string]Param `yaml:"params"`
	SQL     string           `yaml:"sql"`
	SQLFile string           `yaml:"sql_file"`

	// Limits are this endpoint's, each at most the file's.
	Limits *Limits `yaml:"limits"`

	// Tenant is `none` for an endpoint whose data is the same for every
	// tenant. Absent, the SQL must use `{{ tenant }}`.
	Tenant string `yaml:"tenant"`

	// MaxRows is this endpoint's ceiling; zero takes the file's.
	MaxRows int `yaml:"-"`

	Template *render.Template `yaml:"-"`
	// contains filtered or unexported fields
}

Endpoint is one declared GET path.

func (*Endpoint) Reads

func (e *Endpoint) Reads() []string

Reads are the models the endpoint's SQL can read, named as their generations are keyed.

type Limits

type Limits struct {
	Timeout        time.Duration `yaml:"timeout"`
	MaxRows        int           `yaml:"max_rows"`
	MaxBytesBilled ByteSize      `yaml:"max_bytes_billed"`

	// MaxResponseBytes bounds one answer's JSON. max_rows bounds how many
	// rows; this bounds how wide they are, which nothing did.
	MaxResponseBytes ByteSize `yaml:"max_response_bytes"`

	// MaxInFlight is how many requests the whole API may have waiting on
	// the warehouse at once -- each holds a connection. File-wide only.
	MaxInFlight int `yaml:"max_in_flight"`
}

Limits bound one request: how long, how many rows, how many bytes billed.

FILE-WIDE, AND AN ENDPOINT MAY ONLY LOWER THEM. The file's numbers are what whoever deploys the API agreed to; an endpoint that could raise its own would make the file's a suggestion.

type Listen

type Listen struct {
	Addr string `yaml:"addr"`
	Auth *Auth  `yaml:"auth"`
}

Listen is where the API answers.

type Manifest

type Manifest struct {
	Version    int                `json:"version"`
	Kind       string             `json:"kind"`
	Name       string             `json:"name"`
	Connection string             `json:"connection"`
	Dialect    string             `json:"dialect"`
	Cache      *ManifestCache     `json:"cache,omitempty"`
	Endpoints  []ManifestEndpoint `json:"endpoints"`
	Notes      map[string]string  `json:"notes,omitempty"`
}

Manifest is an API file as it runs, for the console: what each endpoint takes and reads, never how it reads it.

NO SQL TEXT. It is in the customer's repository, and what an operator acts on is which models an endpoint reads -- a model's page shows the endpoint beside its other consumers. NO VALUE OF ANY VARIABLE: a `*_from` is published as the name it holds. AND ONLY THE COMMENTS THEIR AUTHOR MARKED with `#:`, the gateway's rule: a comment is free text, and a secret ends up in one in ways no pattern recognises.

type ManifestCache

type ManifestCache struct {
	Type     string `json:"type"`
	AddrFrom string `json:"addr_from"`
	TTL      string `json:"ttl"`
	MaxEntry int64  `json:"max_entry"`
}

ManifestCache is the cache's shape, by the variable's name.

type ManifestEndpoint

type ManifestEndpoint struct {
	Name   string            `json:"name"`
	Path   string            `json:"path"`
	Tenant string            `json:"tenant"`
	Params []ManifestParam   `json:"params"`
	Limits ManifestLimits    `json:"limits"`
	Reads  []string          `json:"reads"`
	Notes  map[string]string `json:"notes,omitempty"`
}

ManifestEndpoint is one endpoint, its parameters resolved.

type ManifestLimits

type ManifestLimits struct {
	Timeout        string `json:"timeout"`
	MaxRows        int    `json:"max_rows"`
	MaxBytesBilled int64  `json:"max_bytes_billed"`
}

ManifestLimits are an endpoint's effective limits.

type ManifestParam

type ManifestParam struct {
	Name     string   `json:"name"`
	Type     string   `json:"type"`
	Default  *string  `json:"default,omitempty"`
	Required bool     `json:"required,omitempty"`
	Values   []string `json:"values,omitempty"`
	Min      *int64   `json:"min,omitempty"`
	Max      *int64   `json:"max,omitempty"`
	MaxLen   int      `json:"max_len,omitempty"`
}

ManifestParam is one parameter as a caller sees it.

type Param

type Param struct {
	Type string `yaml:"type"`

	// MaxLen bounds a string, in characters. Required for one.
	MaxLen int `yaml:"max_len"`

	// Min and Max bound an int.
	Min *int64 `yaml:"min"`
	Max *int64 `yaml:"max"`

	// Values are an enum's, each an identifier: an enum is the one value
	// written into the SQL text, and an identifier is what makes that safe.
	Values []string `yaml:"values"`

	// Default stands in for an omitted value, and is parsed exactly as a
	// sent one is -- so a default its own type cannot hold is refused at
	// load.
	Default *string `yaml:"default"`

	// Required refuses a request that omits the parameter.
	Required bool `yaml:"required"`

	// Ref names a definition in the file's `params:`, and takes nothing
	// else.
	Ref string `yaml:"ref"`
}

Param is one query-string parameter an endpoint takes.

FIVE TYPES AND EACH ONE NARROW. A parameter is a filter somebody outside sends, and every type is the smallest set of strings that can mean what it says: an int is base-10 digits, a date is YYYY-MM-DD and nothing an instant-parser would also accept, a bool is `true` or `false`, an enum is one of the values the file lists. Anything looser is a second way to spell a value, and the cache key, the audit line and the author all read the first.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server answers the endpoints of one file.

func New

func New(cfg *Config) (*Server, error)

New builds the handler, or refuses a configuration it cannot serve.

func (*Server) Keys

func (s *Server) Keys() (keys, tenants int)

Keys is how many keys and tenants the API accepts; zero and zero means it is open, which only BREVIS_ENV=local allows.

func (*Server) Metrics

func (s *Server) Metrics() http.Handler

Metrics is the Prometheus exposition, for its own port: never the API's, which is public by design, and a /metrics on it would publish every endpoint's traffic.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

Directories

Path Synopsis
Package cache holds an endpoint's answers, compressed, until a model they read is rebuilt.
Package cache holds an endpoint's answers, compressed, until a model they read is rebuilt.
Package render turns an endpoint's SQL template into a statement and its arguments, and never writes a caller's value into the statement.
Package render turns an endpoint's SQL template into a statement and its arguments, and never writes a caller's value into the statement.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL