Documentation
¶
Overview ¶
Package tapesoapi parses, aggregates, and compiles OpenAPI v3 documents.
It exists because tapes assembles its API description from two sources that nothing off the shelf treats alike: its own live Fiber routes, and the OpenAPI documents cassettes publish over HTTP for reverse-proxy mounting. Both are handled here as the same thing — a Fragment, a partial contribution tagged with where it came from — so one merge, validate, and render pipeline serves both instead of two that drift.
The shape of a use is always the same:
parser := tapesoapi.NewParser(tapesoapi.WithInfo(tapesoapi.Info{
Title: "tapes", Version: "v1",
}))
if err := parser.AddDocument(ctx, cassetteSpec,
tapesoapi.WithComponentNamespace("hello_world_")); err != nil {
return err
}
compiled, err := parser.Compile(ctx)
The Parser is a mutable accumulator guarded by a mutex; Compile is a pure function of the fragments it holds. Compiling the same fragments twice yields byte-identical output, which is what makes the generated contracts diffable in CI and cacheable behind an ETag.
All I/O happens at Add time. Compile never reads a file or opens a socket, so it is safe to call on a request path — which /openapi does.
Versions ¶
The internal model is version-neutral: it stores the union of 3.0 and 3.1 semantics, and the version decision happens once, at render time. Both V30 and V31 render. V30 is the default because the Rust client generator tapes publishes for reads only accepts 3.0.x; a 3.1-only construct reaching a 3.0 render is a documented loss, refused unless WithDowngradeLossy says to approximate it. See version.go.
Fiber ¶
The core has no web-framework dependency. The route-registration wrapper lives in the oasfiber subpackage, against the same Source interface any other adapter would implement.
Index ¶
- Constants
- Variables
- func Content(mediaType string, schema *Schema) map[string]*MediaType
- func JSON(schema *Schema) map[string]*MediaType
- func NormalizePath(path string) (string, error)
- func PathParams(path string) []string
- func SynthesizeOperationID(method, openAPIPath string) string
- func Text(schema *Schema) map[string]*MediaType
- type CompileOption
- type CompiledDoc
- func (d *CompiledDoc) ComponentSchema(name string) (*Schema, bool)
- func (d *CompiledDoc) ComponentSchemas() []string
- func (d *CompiledDoc) Fingerprint() string
- func (d *CompiledDoc) JSON() []byte
- func (d *CompiledDoc) MarshalJSON() ([]byte, error)
- func (d *CompiledDoc) Operations() map[string][]string
- func (d *CompiledDoc) Paths() []string
- func (d *CompiledDoc) Tree() map[string]any
- func (d *CompiledDoc) ValidateInstance(schemaName string, value any) error
- func (d *CompiledDoc) Version() Version
- func (d *CompiledDoc) Warnings() []string
- func (d *CompiledDoc) YAML() ([]byte, error)
- type Components
- type Conflict
- type ConflictError
- type ConflictPolicy
- type Contact
- type Discriminator
- type DocOption
- func WithAuthoritativeInfo() DocOption
- func WithComponentNamespace(namespace string) DocOption
- func WithOperationIDPrefix(prefix string) DocOption
- func WithPathPrefix(prefix string) DocOption
- func WithProvenance(provenance Provenance) DocOption
- func WithTagFilter(keep ...string) DocOption
- func WithoutInfo() DocOption
- func WithoutRootExtensions() DocOption
- func WithoutServers() DocOption
- type Document
- func (document *Document) Extension(key string) ([]byte, bool, error)
- func (document *Document) Fragment(provenance Provenance) (Fragment, error)
- func (document *Document) Marshal() ([]byte, error)
- func (document *Document) Paths() ([]string, error)
- func (document *Document) RewritePrefix(sourcePrefix, targetPrefix string) (*Document, error)
- func (document *Document) StandaloneRequestSchema(method, path, mediaType string) (map[string]any, error)
- func (document *Document) Version() (Version, error)
- type Encoding
- type ExternalDocs
- type Fragment
- type Header
- type Info
- type InstanceError
- type InstanceViolation
- type License
- type LintError
- type LintRule
- type LintTarget
- type MediaType
- type NoOrphanComponents
- type Operation
- type OperationBuilder
- func (b *OperationBuilder) Build() *Operation
- func (b *OperationBuilder) ContentResponse(status int, description, mediaType string, schema *Schema) *OperationBuilder
- func (b *OperationBuilder) CookieParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
- func (b *OperationBuilder) Deprecated() *OperationBuilder
- func (b *OperationBuilder) Description(text string) *OperationBuilder
- func (b *OperationBuilder) EmptyResponse(status int, description string) *OperationBuilder
- func (b *OperationBuilder) Extension(key string, value any) *OperationBuilder
- func (b *OperationBuilder) HeaderParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
- func (b *OperationBuilder) JSONBody(description string, schema *Schema) *OperationBuilder
- func (b *OperationBuilder) JSONResponse(status int, description string, schema *Schema) *OperationBuilder
- func (b *OperationBuilder) OptionalJSONBody(description string, schema *Schema) *OperationBuilder
- func (b *OperationBuilder) PathParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
- func (b *OperationBuilder) QueryParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
- func (b *OperationBuilder) RequestBody(description string, required bool, content map[string]*MediaType) *OperationBuilder
- func (b *OperationBuilder) Response(status int, response *Response) *OperationBuilder
- func (b *OperationBuilder) ResponseHeader(status int, name string, header *Header) *OperationBuilder
- func (b *OperationBuilder) ResponseKey(key string, response *Response) *OperationBuilder
- func (b *OperationBuilder) Security(requirement SecurityRequirement) *OperationBuilder
- func (b *OperationBuilder) Summary(text string) *OperationBuilder
- func (b *OperationBuilder) Tag(tags ...string) *OperationBuilder
- type OperationIDPresent
- type OperationIDUnique
- type Option
- type ParamOption
- type Parameter
- type ParameterIn
- type Parser
- func (p *Parser) AddComponentSchema(name string, schema *Schema, provenance Provenance) error
- func (p *Parser) AddDocument(ctx context.Context, data []byte, options ...DocOption) error
- func (p *Parser) AddDocumentFS(ctx context.Context, fsys fs.FS, path string, options ...DocOption) error
- func (p *Parser) AddDocumentFile(ctx context.Context, path string, options ...DocOption) error
- func (p *Parser) AddDocumentGlob(ctx context.Context, pattern string, options ...DocOption) error
- func (p *Parser) AddDocumentReader(ctx context.Context, reader io.Reader, options ...DocOption) error
- func (p *Parser) AddFragment(fragment Fragment) error
- func (p *Parser) AddOperation(method, path string, operation *Operation, provenance Provenance) error
- func (p *Parser) AddParsedDocument(document *Document, options ...DocOption) error
- func (p *Parser) AddSource(ctx context.Context, source Source) error
- func (p *Parser) Compile(ctx context.Context, options ...CompileOption) (*CompiledDoc, error)
- func (p *Parser) Fragments() []Fragment
- func (p *Parser) Freeze()
- func (p *Parser) Frozen() bool
- func (p *Parser) Reflector() Reflector
- func (p *Parser) Schema(value any) *Schema
- type PathItem
- type Provenance
- type Reflector
- type ReflectorOption
- type RequestBody
- type Response
- type ResponsesDeclared
- type Schema
- func AllOf(members ...*Schema) *Schema
- func AnyOf(alternatives ...*Schema) *Schema
- func AnyValue() *Schema
- func Array(items *Schema, opts ...SchemaOption) *Schema
- func Boolean(opts ...SchemaOption) *Schema
- func Integer(opts ...SchemaOption) *Schema
- func MapOf(value *Schema) *Schema
- func Number(opts ...SchemaOption) *Schema
- func Object(properties map[string]*Schema, opts ...SchemaOption) *Schema
- func OneOf(alternatives ...*Schema) *Schema
- func Ref(ref string) *Schema
- func SchemaRef(name string) *Schema
- func String(opts ...SchemaOption) *Schema
- type SchemaOption
- func AdditionalProperties(schema *Schema) SchemaOption
- func Default(value any) SchemaOption
- func Deprecated() SchemaOption
- func Description(text string) SchemaOption
- func Enum(values ...any) SchemaOption
- func Example(value any) SchemaOption
- func ExclusiveMaximum(v float64) SchemaOption
- func ExclusiveMinimum(v float64) SchemaOption
- func Extension(key string, value any) SchemaOption
- func Format(format string) SchemaOption
- func MaxItems(v uint64) SchemaOption
- func MaxLength(v uint64) SchemaOption
- func Maximum(v float64) SchemaOption
- func MinItems(v uint64) SchemaOption
- func MinLength(v uint64) SchemaOption
- func Minimum(v float64) SchemaOption
- func MultipleOf(v float64) SchemaOption
- func NoAdditionalProperties() SchemaOption
- func Nullable() SchemaOption
- func Pattern(expr string) SchemaOption
- func Property(name string, schema *Schema) SchemaOption
- func ReadOnly() SchemaOption
- func Required(names ...string) SchemaOption
- func Title(text string) SchemaOption
- func UniqueItems() SchemaOption
- func WriteOnly() SchemaOption
- type SchemaType
- type SecurityRequirement
- type SecurityScheme
- type Server
- type ServerVariable
- type Source
- type SourceFunc
- type Status
- type StructureError
- type Tag
- type TypeDocs
- type Version
Constants ¶
const ( KindDocument = "document" KindRoute = "route" KindManual = "manual" KindReflect = "reflect" )
Kind names where a fragment came from. It is a string rather than an enum so a caller implementing Source can name its own kind without patching this package.
Variables ¶
var ErrFrozen = errors.New("parser is frozen; no further contributions accepted")
ErrFrozen is returned by every Add method once the parser is frozen.
Functions ¶
func JSON ¶
JSON returns a single-entry application/json content map over schema. It is the shorthand almost every operation in a JSON API needs.
func NormalizePath ¶ added in v0.34.0
NormalizePath canonicalizes a path so two spellings of the same route cannot both appear in one document.
Trailing slashes are trimmed (except on the root) and the path must be absolute. Parameter names are left alone: `{id}` and `{userId}` are different paths to OpenAPI even when they route identically, and silently unifying them would publish an operation nobody wrote.
func PathParams ¶
PathParams returns the template parameter names in a path, in order.
func SynthesizeOperationID ¶
SynthesizeOperationID derives an operationId from a method and an OpenAPI path.
It is exported because two callers need to agree on the answer. The Fiber adapter names an undocumented route with it, and an aggregate names an ingested operation that arrived without an id with it — and if those two ever disagreed, the same route would be called one thing in core's own contract and another in the aggregate that republishes it.
Deterministic, so a compiled document does not churn between builds: same method and path, same id, always.
GET /v1/sessions/{id} → getV1SessionsId
Types ¶
type CompileOption ¶
type CompileOption func(*compileOptions)
CompileOption adjusts one compile.
func WithDowngradeLossy ¶
func WithDowngradeLossy() CompileOption
WithDowngradeLossy permits rendering 3.1-only constructs to a 3.0 target by approximating them, instead of failing. Without it, a downgrade that would drop meaning is an error naming the construct and the document it came from.
func WithLint ¶
func WithLint(rules ...LintRule) CompileOption
WithLint replaces the lint rules run after validation.
func WithTarget ¶
func WithTarget(version Version) CompileOption
WithTarget selects the version to render. The default is V30.
func WithoutValidation ¶
func WithoutValidation() CompileOption
WithoutValidation skips structural validation. It is an escape hatch for serving a known-imperfect upstream document rather than failing the request, not a way to land one in a generated contract.
type CompiledDoc ¶
type CompiledDoc struct {
// contains filtered or unexported fields
}
CompiledDoc is an immutable compiled OpenAPI document.
It is safe to share across goroutines and cheap to serve repeatedly: the rendered bytes and the fingerprint are computed once, at compile time.
func (*CompiledDoc) ComponentSchema ¶
func (d *CompiledDoc) ComponentSchema(name string) (*Schema, bool)
ComponentSchema returns a compiled component schema by bare name.
The returned schema is a copy, so a caller cannot reach into the compiled document through it.
func (*CompiledDoc) ComponentSchemas ¶
func (d *CompiledDoc) ComponentSchemas() []string
ComponentSchemas returns the names of every component schema, sorted.
func (*CompiledDoc) Fingerprint ¶
func (d *CompiledDoc) Fingerprint() string
Fingerprint is a content hash of the rendered document, for ETags and change detection.
func (*CompiledDoc) JSON ¶
func (d *CompiledDoc) JSON() []byte
JSON returns the rendered JSON bytes.
func (*CompiledDoc) MarshalJSON ¶
func (d *CompiledDoc) MarshalJSON() ([]byte, error)
MarshalJSON returns the document as indented JSON.
func (*CompiledDoc) Operations ¶
func (d *CompiledDoc) Operations() map[string][]string
Operations returns the methods this document describes per path, uppercased and sorted.
It is the accessor for the callers that need the served surface as a set rather than as a document: a coverage check comparing a router's route table against what got published. The alternative is walking CompiledDoc.Tree and re-deriving which keys under a path item are methods and which are metadata (`summary`, `parameters`, `$ref`), and a consumer that got that list wrong would report a phantom operation or miss a real one.
func (*CompiledDoc) Paths ¶
func (d *CompiledDoc) Paths() []string
Paths returns the document's paths in sorted order.
func (*CompiledDoc) Tree ¶
func (d *CompiledDoc) Tree() map[string]any
Tree returns the rendered document as a generic tree. It is the escape hatch for callers that need to post-process the output, and it returns a copy so they cannot mutate the compiled document.
func (*CompiledDoc) ValidateInstance ¶
func (d *CompiledDoc) ValidateInstance(schemaName string, value any) error
ValidateInstance checks a decoded JSON value against one of this document's component schemas.
value is what encoding/json produced — maps, slices, strings, bools, float64 or json.Number, nil. Both number representations are accepted because a caller that decoded with UseNumber did so to keep the digits it was given, and losing that here would defeat the point.
References inside the schema resolve against this document's components, so a composite response validates all the way down without the caller flattening anything first.
func (*CompiledDoc) Version ¶
func (d *CompiledDoc) Version() Version
Version reports which OpenAPI version this document was rendered to.
func (*CompiledDoc) Warnings ¶
func (d *CompiledDoc) Warnings() []string
Warnings reports non-fatal merge outcomes — the conflicts a first-wins or last-wins policy resolved by picking. Empty under the default policy, which fails instead of picking.
func (*CompiledDoc) YAML ¶
func (d *CompiledDoc) YAML() ([]byte, error)
YAML renders the document as YAML. Keys sort the same way as in JSON, so the two encodings describe the same document in the same order.
type Components ¶
type Components struct {
Schemas map[string]*Schema
Responses map[string]*Response
Parameters map[string]*Parameter
RequestBodies map[string]*RequestBody
Headers map[string]*Header
Examples map[string]any
SecuritySchemes map[string]*SecurityScheme
}
Components is the reusable-object section of a document.
func (*Components) IsEmpty ¶
func (c *Components) IsEmpty() bool
IsEmpty reports whether there is nothing to render.
type Conflict ¶
type Conflict struct {
// Kind is what collided: "path", "component", or "info".
Kind string
// Key names the collision — "GET /users/{id}", "schemas/User".
Key string
// Sources are every contributor, in merge order.
Sources []Provenance
}
Conflict is one key contributed by more than one fragment.
type ConflictError ¶
type ConflictError struct {
Conflicts []Conflict
}
ConflictError reports every collision at once.
Collect-all rather than fail-fast is deliberate. Someone aggregating a fleet of documents wants the whole list so they can fix it in one pass; failing on the first conflict turns that into one recompile per collision.
func (*ConflictError) Error ¶
func (e *ConflictError) Error() string
type ConflictPolicy ¶
type ConflictPolicy int
ConflictPolicy decides what happens when two fragments contribute the same key.
const ( // PolicyError collects every conflict and fails the compile. It is the // default: an aggregate whose contents depend on which document loaded // first is worse than one that refuses to build. PolicyError ConflictPolicy = iota // PolicyFirstWins keeps the earlier contribution in merge order. PolicyFirstWins // PolicyLastWins keeps the later contribution in merge order. PolicyLastWins )
The available conflict policies.
func (ConflictPolicy) String ¶
func (p ConflictPolicy) String() string
String names the policy for error messages.
type Discriminator ¶
Discriminator selects an implementing schema from a payload field.
type DocOption ¶
type DocOption func(*docOptions)
DocOption adjusts how one ingested document is decomposed.
func WithAuthoritativeInfo ¶
func WithAuthoritativeInfo() DocOption
WithAuthoritativeInfo marks this document's Info as the one that wins, rather than colliding with another document's.
func WithComponentNamespace ¶
WithComponentNamespace prefixes every component name, and rewrites every document-local reference to match.
Namespacing pre-empts collisions rather than resolving them. Two cassettes that each define a `Row` schema are not describing the same type, and merging them under one name would publish a schema neither of them wrote.
func WithOperationIDPrefix ¶
WithOperationIDPrefix prefixes every operationId in the document, giving one to any operation that arrived without one.
This is the operation-level counterpart to WithComponentNamespace, and it exists for the same reason: an operationId has to be unique across the whole document, and two independently authored inputs are perfectly free to have both named an operation `read`. Namespacing pre-empts that; the alternative is an aggregate that cannot be published as a valid contract.
It is a real edit to a document's contract, so it belongs to aggregation and not to republication. The document a client fetches for one input alone is served verbatim, ids untouched — see the per-cassette endpoint in api/cassetterunner. The prefixed ids exist only in the merged document, where the unprefixed ones could not have coexisted anyway.
func WithPathPrefix ¶
WithPathPrefix mounts every path in the document under a prefix.
This and WithComponentNamespace are the aggregation workhorses: together they are what lets three independently authored documents compose into one gateway description without colliding.
func WithProvenance ¶
func WithProvenance(provenance Provenance) DocOption
WithProvenance names the ingested document in conflict errors. Ingestion sets a sensible default (the file path or URL); this overrides it.
func WithTagFilter ¶
WithTagFilter ingests only the operations carrying one of the given tags.
func WithoutInfo ¶
func WithoutInfo() DocOption
WithoutInfo drops the document's Info, for merging a document into an aggregate that already has one.
func WithoutRootExtensions ¶
func WithoutRootExtensions() DocOption
WithoutRootExtensions drops the document's root `x-` keys. It is how an aggregate avoids inheriting a per-document extension — a cassette manifest, say — that describes only one of its inputs.
func WithoutServers ¶
func WithoutServers() DocOption
WithoutServers drops the document's servers.
A document being merged into an aggregate usually describes an origin the aggregate does not serve — a cassette's own listener, which clients reach only through core's proxy — and carrying that origin through would send them somewhere they cannot go.
type Document ¶
type Document struct {
// contains filtered or unexported fields
}
Document is a parsed OpenAPI document held as a generic tree.
It is deliberately *not* the IR. A document fetched from a cassette is republished to clients close to verbatim, and round-tripping it through a typed model would silently drop every field this package does not know about — including the parts of a future OpenAPI revision. The generic tree is what lets core rewrite exactly the paths it must and leave everything else alone.
Use Document.Fragment to move a document into the IR for merging.
func Parse ¶
Parse decodes exactly one JSON object, preserving JSON numbers.
Duplicate keys are rejected rather than last-one-wins. A document that declares the same path twice is ambiguous, and picking a winner would make core's published surface depend on Go's map iteration.
func ParseYAML ¶
ParseYAML decodes a YAML or JSON document. JSON is valid YAML, so this accepts both; Parse is the stricter reader used for documents arriving over the wire, where duplicate-key ambiguity is a security-relevant surprise rather than a typo in a checked-in file.
func (*Document) Fragment ¶
func (document *Document) Fragment(provenance Provenance) (Fragment, error)
Fragment decomposes the document into the version-neutral IR.
Decomposing at ingest — rather than holding loaded documents and merging them at the end — is deliberate: it forces every source through one normalization, and it means a malformed document fails at the Add call that supplied it, where the file name is still in hand, instead of at a Compile that cannot say which of its inputs was wrong.
func (*Document) RewritePrefix ¶
func (*Document) StandaloneRequestSchema ¶ added in v0.34.0
func (document *Document) StandaloneRequestSchema(method, path, mediaType string) (map[string]any, error)
StandaloneRequestSchema returns one operation request schema as JSON Schema 2020-12, with every reachable OpenAPI component bundled under $defs. The raw document tree is used so JSON Schema keywords that OpenAPI itself does not interpret are preserved for the standalone consumer.
type ExternalDocs ¶
ExternalDocs points at documentation outside the spec.
type Fragment ¶
type Fragment struct {
Provenance Provenance
// Version is the version the fragment was authored against, empty for
// fragments built programmatically (which are version-neutral by
// construction). It is what lets a compile refuse to silently downgrade a
// 3.1 document.
Version Version
Info *Info
Servers []Server
Tags []Tag
Security []SecurityRequirement
Paths map[string]*PathItem
Components *Components
// Webhooks are accepted from 3.1 documents and rendered only for 3.1
// targets. Holding them in the IR now means adding 3.1 output later does
// not change this type.
Webhooks map[string]*PathItem
// Authoritative marks this fragment's Info as the one that wins. Without
// it, two fragments both setting Info is a conflict rather than a
// last-one-loaded race.
Authoritative bool
Extensions map[string]any
}
Fragment is a partial OpenAPI contribution plus where it came from.
An external YAML file, a Fiber route registration, and a hand-built operation are all the same thing to the parser. Collapsing them into one type is what lets ingestion and live route registration share a single merge, validate, and render pipeline instead of two that drift.
type Info ¶
type Info struct {
Title string
Description string
TermsOfService string
Version string
Contact *Contact
License *License
Extensions map[string]any
}
Info describes the API as a whole.
type InstanceError ¶
type InstanceError struct {
// Schema names the schema the value was checked against.
Schema string
// Violations are the findings, in document order.
Violations []InstanceViolation
}
InstanceError reports every violation found in one value.
Collect-all, like the other errors here: someone checking a captured payload against a contract wants the whole disagreement, not its first line.
func (*InstanceError) Error ¶
func (e *InstanceError) Error() string
type InstanceViolation ¶
type InstanceViolation struct {
// Pointer is an RFC 6901 JSON Pointer to the offending value, so a finding
// in a nested array names the element rather than the document.
Pointer string
// Message says what was expected and what was there.
Message string
}
InstanceViolation is one place a value disagreed with its schema.
func (InstanceViolation) String ¶
func (v InstanceViolation) String() string
type License ¶
type License struct {
Name string
URL string
// Identifier is an SPDX expression. It is 3.1-only; rendering to 3.0 drops
// it in favour of Name, which 3.0 requires anyway.
Identifier string
}
License is the API's license.
type LintError ¶
type LintError struct {
Findings []string
}
LintError reports every lint finding at once.
type LintRule ¶
type LintRule interface {
// Name identifies the rule in error output.
Name() string
// Check returns one finding per problem, empty when the document passes.
Check(document *LintTarget) []string
}
LintRule is one check over a merged document. Rules run alongside structural validation, so they can assume the document is well formed and concern themselves with whether it is *good*.
func DefaultLintRules ¶
func DefaultLintRules() []LintRule
DefaultLintRules are the rules a compile runs unless WithLint replaces them.
They encode what the published tapes contracts actually need: every operation carries a unique operationId (progenitor panics without one, and a duplicate silently collapses two client methods into one), and every operation documents at least one outcome.
type LintTarget ¶
type LintTarget struct {
Info *Info
Paths map[string]*PathItem
Components *Components
}
LintTarget is the read-only view of a merged document that lint rules see. It is a distinct type from the internal merge state so adding a rule never requires reaching into compile internals.
type MediaType ¶
type MediaType struct {
Schema *Schema
Example any
Examples map[string]any
Encoding map[string]*Encoding
Extensions map[string]any
}
MediaType is one content-type entry of a body.
type NoOrphanComponents ¶
type NoOrphanComponents struct{}
NoOrphanComponents reports component schemas nothing references.
An orphan is usually the residue of a deleted operation, and left in place it makes a generated client carry a type no endpoint produces.
func (NoOrphanComponents) Check ¶
func (NoOrphanComponents) Check(document *LintTarget) []string
Check implements LintRule.
type Operation ¶
type Operation struct {
OperationID string
Summary string
Description string
Tags []string
Deprecated bool
Parameters []*Parameter
RequestBody *RequestBody
Responses map[string]*Response
Security []SecurityRequirement
Servers []Server
ExternalDocs *ExternalDocs
Extensions map[string]any
// contains filtered or unexported fields
}
Operation is one method on one path.
type OperationBuilder ¶
type OperationBuilder struct {
// contains filtered or unexported fields
}
OperationBuilder describes one operation fluently.
It exists because the alternative — writing struct literals four levels deep to say "this returns a User" — is what pushed the previous generation of Go OpenAPI tooling into doc comments. A builder keeps the description in Go, where the compiler checks the types being described.
op := tapesoapi.NewOperation("getUser").
Summary("Fetch a user by ID").
Tag("users").
PathParam("id", tapesoapi.String(tapesoapi.Format("uuid"))).
QueryParam("expand", tapesoapi.String()).
JSONResponse(200, "the user", userSchema)
func NewOperation ¶
func NewOperation(operationID string) *OperationBuilder
NewOperation starts an operation with the given operationId.
The id is required rather than optional because downstream generators need one — progenitor, which builds paper's Rust client from the compiled contract, hard-fails without it — and a synthesized id changes whenever the path does, silently renaming a client method.
func (*OperationBuilder) Build ¶
func (b *OperationBuilder) Build() *Operation
Build returns the described operation.
func (*OperationBuilder) ContentResponse ¶
func (b *OperationBuilder) ContentResponse(status int, description, mediaType string, schema *Schema) *OperationBuilder
ContentResponse records an outcome with an arbitrary media type.
func (*OperationBuilder) CookieParam ¶
func (b *OperationBuilder) CookieParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
CookieParam declares a cookie parameter.
func (*OperationBuilder) Deprecated ¶
func (b *OperationBuilder) Deprecated() *OperationBuilder
Deprecated marks the operation deprecated.
func (*OperationBuilder) Description ¶
func (b *OperationBuilder) Description(text string) *OperationBuilder
Description sets the long description.
func (*OperationBuilder) EmptyResponse ¶
func (b *OperationBuilder) EmptyResponse(status int, description string) *OperationBuilder
EmptyResponse records an outcome with no body, such as a 204.
func (*OperationBuilder) Extension ¶
func (b *OperationBuilder) Extension(key string, value any) *OperationBuilder
Extension sets a vendor extension on the operation.
func (*OperationBuilder) HeaderParam ¶
func (b *OperationBuilder) HeaderParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
HeaderParam declares a request-header parameter.
func (*OperationBuilder) JSONBody ¶
func (b *OperationBuilder) JSONBody(description string, schema *Schema) *OperationBuilder
JSONBody sets a required application/json request body.
func (*OperationBuilder) JSONResponse ¶
func (b *OperationBuilder) JSONResponse(status int, description string, schema *Schema) *OperationBuilder
JSONResponse records an application/json outcome.
func (*OperationBuilder) OptionalJSONBody ¶
func (b *OperationBuilder) OptionalJSONBody(description string, schema *Schema) *OperationBuilder
OptionalJSONBody sets an optional application/json request body.
func (*OperationBuilder) PathParam ¶
func (b *OperationBuilder) PathParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
PathParam declares a path template parameter.
func (*OperationBuilder) QueryParam ¶
func (b *OperationBuilder) QueryParam(name string, schema *Schema, opts ...ParamOption) *OperationBuilder
QueryParam declares a query-string parameter. Optional unless ParamRequired is passed.
func (*OperationBuilder) RequestBody ¶
func (b *OperationBuilder) RequestBody(description string, required bool, content map[string]*MediaType) *OperationBuilder
RequestBody sets the request body from a content map.
func (*OperationBuilder) Response ¶
func (b *OperationBuilder) Response(status int, response *Response) *OperationBuilder
Response records an outcome under a status key.
func (*OperationBuilder) ResponseHeader ¶
func (b *OperationBuilder) ResponseHeader(status int, name string, header *Header) *OperationBuilder
ResponseHeader attaches a header to an already-recorded response.
func (*OperationBuilder) ResponseKey ¶
func (b *OperationBuilder) ResponseKey(key string, response *Response) *OperationBuilder
ResponseKey records an outcome under an arbitrary key, for "default" and the `4XX` wildcard forms a numeric status cannot express.
func (*OperationBuilder) Security ¶
func (b *OperationBuilder) Security(requirement SecurityRequirement) *OperationBuilder
Security adds a security requirement. Repeated calls are alternatives: any one of them satisfies the operation, which is how OpenAPI reads a list.
func (*OperationBuilder) Summary ¶
func (b *OperationBuilder) Summary(text string) *OperationBuilder
Summary sets the short description.
func (*OperationBuilder) Tag ¶
func (b *OperationBuilder) Tag(tags ...string) *OperationBuilder
Tag adds one or more tags.
type OperationIDPresent ¶
type OperationIDPresent struct{}
OperationIDPresent requires an operationId on every operation.
func (OperationIDPresent) Check ¶
func (OperationIDPresent) Check(document *LintTarget) []string
Check implements LintRule.
type OperationIDUnique ¶
type OperationIDUnique struct{}
OperationIDUnique requires operationIds to be distinct.
func (OperationIDUnique) Check ¶
func (OperationIDUnique) Check(document *LintTarget) []string
Check implements LintRule.
type Option ¶
type Option func(*parserOptions)
Option configures a Parser.
func WithConflictPolicy ¶
func WithConflictPolicy(policy ConflictPolicy) Option
WithConflictPolicy sets how colliding contributions are resolved. The default is PolicyError, which reports every collision at once rather than picking a winner — an aggregate whose contents depend on load order is worse than one that refuses to build.
func WithInfo ¶
WithInfo sets the authoritative document Info. A parser given one is immune to Info conflicts between ingested documents: the aggregate is this API, and the documents merged into it describe parts of it.
func WithSchemaReflector ¶
WithSchemaReflector replaces the Go-type-to-schema reflector.
func WithServer ¶
WithServer appends a server to the compiled document.
type ParamOption ¶
type ParamOption func(*Parameter)
ParamOption adjusts a parameter after its schema is set.
func ParamDeprecated ¶
func ParamDeprecated() ParamOption
ParamDeprecated marks a parameter deprecated.
func ParamDescription ¶
func ParamDescription(text string) ParamOption
ParamDescription documents a parameter.
func ParamExample ¶
func ParamExample(value any) ParamOption
ParamExample sets an example value for a parameter.
func ParamRequired ¶
func ParamRequired() ParamOption
ParamRequired marks a parameter required. Path parameters are required implicitly; this is for the query and header ones that are not.
func ParamStyle ¶
func ParamStyle(style string, explode bool) ParamOption
ParamStyle sets the serialization style, for the array and object parameters where the default is ambiguous.
type Parameter ¶
type Parameter struct {
// Ref makes this a reference to a component parameter; the other fields
// are ignored when it is set.
Ref string
Name string
In ParameterIn
Description string
Required bool
Deprecated bool
Schema *Schema
Example any
Style string
Explode *bool
Extensions map[string]any
}
Parameter is one operation input.
type ParameterIn ¶
type ParameterIn string
ParameterIn is where a parameter is carried.
const ( InPath ParameterIn = "path" InQuery ParameterIn = "query" InHeader ParameterIn = "header" InCookie ParameterIn = "cookie" )
The parameter locations OpenAPI defines.
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser accumulates fragments from any number of sources.
The zero value is not usable; call NewParser. A Parser is safe for concurrent use, because the Fiber adapter contributes a fragment per route registration and nothing orders those against a concurrent Compile.
func (*Parser) AddComponentSchema ¶
func (p *Parser) AddComponentSchema(name string, schema *Schema, provenance Provenance) error
AddComponentSchema registers one reusable schema under a bare component name.
func (*Parser) AddDocument ¶
AddDocument ingests one OpenAPI document from bytes. JSON and YAML are both accepted.
func (*Parser) AddDocumentFS ¶
func (p *Parser) AddDocumentFS(ctx context.Context, fsys fs.FS, path string, options ...DocOption) error
AddDocumentFS ingests one OpenAPI document from an fs.FS, which is how an embedded contract is loaded without touching the filesystem at runtime.
func (*Parser) AddDocumentFile ¶
AddDocumentFile ingests one OpenAPI document from disk.
func (*Parser) AddDocumentGlob ¶
AddDocumentGlob ingests every document matching a shell pattern, in sorted order so a directory of specs compiles the same way on every machine.
func (*Parser) AddDocumentReader ¶
func (p *Parser) AddDocumentReader(ctx context.Context, reader io.Reader, options ...DocOption) error
AddDocumentReader ingests one OpenAPI document from a reader.
func (*Parser) AddFragment ¶
AddFragment records one contribution.
func (*Parser) AddOperation ¶
func (p *Parser) AddOperation(method, path string, operation *Operation, provenance Provenance) error
AddOperation records one programmatically described operation.
path is in OpenAPI form ("/users/{id}"); the Fiber adapter converts from framework syntax before calling this.
func (*Parser) AddParsedDocument ¶
AddParsedDocument ingests an already-parsed document, for callers that hold one for another reason — the cassette runner reads a manifest out of the same document it publishes, and re-parsing it would be a second chance to disagree.
func (*Parser) Compile ¶
func (p *Parser) Compile(ctx context.Context, options ...CompileOption) (*CompiledDoc, error)
Compile merges every fragment into one validated document.
The pipeline is snapshot, merge, resolve, render, validate, freeze — and it performs no I/O, so it is safe to call on a request path. Compiling the same fragments twice produces byte-identical output.
func (*Parser) Fragments ¶
Fragments returns a snapshot of what the parser holds, for inspection and tests. The returned fragments are copies.
func (*Parser) Freeze ¶
func (p *Parser) Freeze()
Freeze makes the parser read-only.
The intended lifecycle is register-everything-then-compile, and a route registered after startup silently changes a document already served. Freezing turns that into a loud error at the registration site.
func (*Parser) Reflector ¶
Reflector returns the parser's Go-type schema reflector, so an adapter can reflect a handler's types against the same registry the parser will compile.
func (*Parser) Schema ¶
Schema derives the schema for a Go value's type, registering named struct types as components of this parser's compiled document.
It is the shorthand a route declaration reaches for:
Response(200, "the session", parser.Schema(SessionDetailResponse{}))
A type that cannot be described — a channel, a func — yields a schema that carries the reason, so one bad field degrades that one property instead of failing a registration that has no way to report an error.
type PathItem ¶
type PathItem struct {
Ref string
Summary string
Description string
Servers []Server
// Parameters apply to every operation on this path.
Parameters []*Parameter
// Operations is keyed by uppercase HTTP method.
Operations map[string]*Operation
Extensions map[string]any
}
PathItem is every operation on one path, plus what they share.
type Provenance ¶
type Provenance struct {
// Kind is the class of contributor: KindDocument, KindRoute, KindManual, or
// a caller-defined kind.
Kind string
// Name identifies the contributor within its kind — a file path, a URL, or
// a route pattern such as "GET /users/:id".
Name string
// Detail is optional extra location information, typically a file:line.
Detail string
}
Provenance records where a contribution came from, precisely enough that a conflict error can point a reader at the two places to go look.
This is load-bearing rather than logging: aggregation only stays usable at scale if every error names its sources. "GET /users/{id} is defined twice" is a puzzle; "defined by both specs/users.yaml and route users.go:41" is a fix.
func (Provenance) String ¶
func (p Provenance) String() string
String renders a provenance for an error message.
type Reflector ¶
type Reflector interface {
// Reflect returns the schema for a value's type. Named struct types are
// registered as components and referenced, so a type used by ten operations
// is described once.
Reflect(value any) (*Schema, error)
// ReflectType is Reflect for a type with no value in hand.
ReflectType(t reflect.Type) (*Schema, error)
// Components returns every registered component schema, keyed by bare name.
Components() map[string]*Schema
}
Reflector turns Go types into schemas and accumulates the named ones as reusable components.
It is an interface so a caller with unusual types can substitute its own derivation without forking the package; NewReflector is the default.
func NewReflector ¶
func NewReflector(options ...ReflectorOption) Reflector
NewReflector returns the default Go-type-to-schema reflector.
type ReflectorOption ¶
type ReflectorOption func(*reflector)
ReflectorOption configures the default reflector.
func WithDocs ¶
func WithDocs(docs TypeDocs) ReflectorOption
WithDocs attaches doc comments to reflected schemas.
func WithPointersNullable ¶
func WithPointersNullable() ReflectorOption
WithPointersNullable marks pointer fields nullable.
Off by default. A Go pointer usually means "optional in the payload", which OpenAPI already expresses by leaving the field out of `required`; rendering every pointer as `nullable: true` would tell a client generator to wrap types in an option *and* admit an explicit null, which is not what most of these handlers do.
func WithTypeNamer ¶
func WithTypeNamer(namer func(reflect.Type) string) ReflectorOption
WithTypeNamer overrides how a Go type becomes a component name.
type RequestBody ¶
type RequestBody struct {
Ref string
Description string
Required bool
Content map[string]*MediaType
Extensions map[string]any
}
RequestBody is an operation's input payload.
type Response ¶
type Response struct {
Ref string
// Description is required by the spec for every response object. An empty
// one is filled in at compile time rather than failing, because a missing
// description is a documentation gap, not a structural defect.
Description string
Content map[string]*MediaType
Headers map[string]*Header
Extensions map[string]any
}
Response is one operation outcome.
type ResponsesDeclared ¶
type ResponsesDeclared struct{}
ResponsesDeclared requires at least one documented outcome per operation.
func (ResponsesDeclared) Check ¶
func (ResponsesDeclared) Check(document *LintTarget) []string
Check implements LintRule.
type Schema ¶
type Schema struct {
// Ref is a document-local reference such as "#/components/schemas/User".
Ref string
Type SchemaType
Format string
Title string
Description string
// Nullable widens the type to admit null. Held as a flag rather than as a
// type union so the IR does not have to commit to a version's spelling.
Nullable bool
Default any
Example any
Examples []any
Enum []any
// Const is 3.1-only. Compiling a document that uses it to V30 is an error
// unless the compile lowers it, which it does by emitting a single-member
// enum — the closest 3.0 equivalent.
Const any
HasConst bool
// Numeric constraints.
Minimum *float64
Maximum *float64
ExclusiveMinimum *float64
ExclusiveMaximum *float64
MultipleOf *float64
// String constraints.
MinLength *uint64
MaxLength *uint64
Pattern string
// Array constraints.
Items *Schema
MinItems *uint64
MaxItems *uint64
UniqueItems bool
// Object constraints.
Properties map[string]*Schema
Required []string
MinProperties *uint64
MaxProperties *uint64
// AdditionalProperties is the schema extra properties must satisfy.
AdditionalProperties *Schema
// AdditionalPropertiesAllowed is the boolean form of the same keyword. A
// nil value leaves the keyword unset, which is not the same as `true`:
// unset lets a consumer apply its own default, and false forbids extras.
AdditionalPropertiesAllowed *bool
// Composition.
OneOf []*Schema
AnyOf []*Schema
AllOf []*Schema
Not *Schema
Discriminator *Discriminator
ReadOnly bool
WriteOnly bool
Deprecated bool
// Extensions are `x-` vendor keys rendered verbatim.
Extensions map[string]any
}
Schema is the version-neutral schema IR.
It stores the union of 3.0 and 3.1 semantics and renders down to whichever version is targeted. Two fields carry the whole version story:
- Nullable renders as `nullable: true` in 3.0 and as a `"null"` member of the type union in 3.1.
- ExclusiveMinimum/ExclusiveMaximum are held in 3.1's numeric form, because it is the lossless one: 3.0's boolean form is derivable from it (emit the bound as `minimum` and the flag as `exclusiveMinimum`), while the reverse needs the sibling bound to reconstruct.
A Schema with Ref set is a reference and every other field is ignored, which mirrors how a `$ref` behaves in 3.0.
func AllOf ¶
AllOf returns a schema satisfied by all of the members, which is how this package expresses composition over a referenced component.
func AnyValue ¶
func AnyValue() *Schema
AnyValue returns a schema that constrains nothing — the "any JSON value" schema, rendered as an empty object.
func Array ¶
func Array(items *Schema, opts ...SchemaOption) *Schema
Array returns an array schema over items.
func MapOf ¶
MapOf returns an object schema whose values all satisfy value — the shape a Go map reflects to.
func Object ¶
func Object(properties map[string]*Schema, opts ...SchemaOption) *Schema
Object returns an object schema with the given properties.
type SchemaOption ¶
type SchemaOption func(*Schema)
SchemaOption mutates a schema under construction. It is the shared vocabulary of the primitive constructors, so `String(Format("uuid"))` and `Integer(Minimum(0))` read the same way.
func AdditionalProperties ¶
func AdditionalProperties(schema *Schema) SchemaOption
AdditionalProperties constrains extra properties to a schema, which is how a free-form map is described.
func Description ¶
func Description(text string) SchemaOption
Description sets the schema description.
func Enum ¶
func Enum(values ...any) SchemaOption
Enum restricts the schema to a fixed set of values.
func ExclusiveMaximum ¶
func ExclusiveMaximum(v float64) SchemaOption
ExclusiveMaximum sets an exclusive upper bound.
func ExclusiveMinimum ¶
func ExclusiveMinimum(v float64) SchemaOption
ExclusiveMinimum sets an exclusive lower bound.
func Extension ¶
func Extension(key string, value any) SchemaOption
Extension sets a vendor extension on the schema. The key is prefixed with `x-` if it is not already.
func MultipleOf ¶
func MultipleOf(v float64) SchemaOption
MultipleOf constrains the value to multiples of v.
func NoAdditionalProperties ¶
func NoAdditionalProperties() SchemaOption
NoAdditionalProperties forbids properties beyond those declared.
func Pattern ¶
func Pattern(expr string) SchemaOption
Pattern sets a regular expression the string must match.
func Property ¶
func Property(name string, schema *Schema) SchemaOption
Property adds one object property.
func Required ¶
func Required(names ...string) SchemaOption
Required marks object properties as required.
func UniqueItems ¶
func UniqueItems() SchemaOption
UniqueItems requires array members to be distinct.
type SchemaType ¶
type SchemaType string
SchemaType is a JSON Schema primitive type.
const ( TypeString SchemaType = "string" TypeNumber SchemaType = "number" TypeInteger SchemaType = "integer" TypeBoolean SchemaType = "boolean" TypeArray SchemaType = "array" TypeObject SchemaType = "object" TypeNull SchemaType = "null" )
The JSON Schema primitive types. Null is only nameable as a type of its own in 3.1; in 3.0 the IR's Nullable flag carries the same meaning.
type SecurityRequirement ¶
SecurityRequirement names schemes an operation requires, with their scopes. The map is a disjunction of conjunctions exactly as OpenAPI defines it.
type SecurityScheme ¶
type SecurityScheme struct {
Type string
Description string
Name string
In string
Scheme string
BearerFormat string
OpenIDConnectURL string
Flows map[string]any
Extensions map[string]any
}
SecurityScheme declares an authentication mechanism.
type Server ¶
type Server struct {
URL string
Description string
Variables map[string]*ServerVariable
}
Server is one base URL the API is served from.
type ServerVariable ¶
ServerVariable is a substitution in a server URL template.
type Source ¶
Source is anything that can contribute fragments.
Document ingestion and the Fiber adapter are both just implementations, and a caller can add its own — pulling specs from a service registry, say — without this package shipping support for it.
type SourceFunc ¶
SourceFunc adapts a function to Source.
type StructureError ¶
type StructureError struct {
// Version is the target the document was checked against, because some
// rules only apply to one of them.
Version Version
// Violations are the findings, sorted and deduplicated.
Violations []string
}
StructureError reports every structural violation at once, so one compile names the whole list rather than the first item on it.
func (*StructureError) Error ¶
func (e *StructureError) Error() string
type Tag ¶
type Tag struct {
Name string
Description string
ExternalDocs *ExternalDocs
}
Tag groups operations.
type TypeDocs ¶
type TypeDocs interface {
// TypeDoc returns the doc comment for a named type.
TypeDoc(pkgPath, typeName string) string
// FieldDoc returns the doc comment for one field of a named type.
FieldDoc(pkgPath, typeName, fieldName string) string
}
TypeDocs supplies prose that reflection cannot see.
Go's runtime carries no doc comments, so a purely reflective schema is structurally complete and completely undocumented. The generator reads the comments out of the source with [gosource.Load] and hands them here, which keeps documentation next to the field it describes rather than duplicated into a struct tag.
type Version ¶
type Version string
Version is an OpenAPI specification version this package can render.
The internal model is version-neutral: it stores the union of what 3.0 and 3.1 can express, and the version decision happens once, at render time. That is what keeps 3.1 support additive rather than a second parser.
func ParseVersion ¶
ParseVersion maps a document's `openapi` field onto a render target.
Patch releases of a minor version are all rendered the same way — 3.0.0 and 3.0.3 differ in wording, not in what a document may contain — so the whole 3.0.x line maps to V30 and the whole 3.1.x line to V31.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package gosource reads doc comments out of Go source so reflected schemas can carry prose.
|
Package gosource reads doc comments out of Go source so reflected schemas can carry prose. |
|
Package oasfiber populates a tapesoapi parser as Fiber routes are registered.
|
Package oasfiber populates a tapesoapi parser as Fiber routes are registered. |
|
Package v30 holds the OpenAPI 3.0 reference documents this module is tested against.
|
Package v30 holds the OpenAPI 3.0 reference documents this module is tested against. |
|
Package v31 holds the OpenAPI 3.1 reference documents this module is tested against.
|
Package v31 holds the OpenAPI 3.1 reference documents this module is tested against. |