metadata

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 15, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package metadata extracts OpenAPI schema metadata from Go struct field tags.

This package provides parsers for various struct tags that control OpenAPI schema generation. It bridges the gap between Go struct tags and OpenAPI/JSON Schema properties by parsing tag values and converting them to appropriate metadata structures.

Supported Tags

The package supports three categories of tags:

1. OpenAPI Metadata (openapi tag):

  • Schema documentation: title, description, format, examples
  • Field modifiers: readOnly, writeOnly, deprecated, hidden, required
  • Extensions: x-* prefixed custom fields (field or struct level)
  • Struct-level only: additionalProperties, nullable (on _ field)

2. Validation Constraints (validate tag):

  • Numeric: min, max, gt, gte, lt, lte, multipleOf
  • String: pattern, email, url, uuid, etc.
  • General: required, enum (oneof)

3. Specialized Tags:

  • default: Default values for fields
  • requires: Fields that become required when this field is present

Tag Precedence Rules

When tags overlap, the following precedence applies:

1. Format: validate:"email" sets format, openapi:"format=custom" overrides it 2. Required: validate:"required" is source of truth, openapi:"required" can override for docs 3. Hidden: json:"-" hides from JSON, openapi:"hidden" hides from OpenAPI schema only

Best practices:

  • Use validate:"required" for actual validation
  • Use openapi:"required" only to override docs (e.g., mark optional field as required in docs)
  • Use validate:"email" for format, not openapi:"format=email" (unless overriding)

Complete Example

type User struct {
    _            struct{} `openapi:"additionalProperties=false,nullable=false"`
    ID           int      `json:"id" openapi:"readOnly,description=Unique identifier"`
    Email        string   `json:"email" validate:"required,email" openapi:"description=User email address,[email protected]"`
    Name         string   `json:"name" validate:"required,min=3" openapi:"description=Full name,examples=John Doe|Jane Smith"`
    Age          int      `json:"age" validate:"min=0,max=150" openapi:"description=User age,examples=25|30|35"`
    Status       string   `json:"status" validate:"oneof=active inactive" openapi:"description=Account status,examples=active|inactive"`
    CreditCard   string   `json:"credit_card,omitempty" requires:"billing_address,cvv"`
    BillingAddr  string   `json:"billing_address,omitempty"`
    CVV          string   `json:"cvv,omitempty" openapi:"writeOnly"`
    Internal     bool     `json:"-" openapi:"hidden"`
    LegacyField  string   `json:"legacy_field,omitempty" openapi:"deprecated"`
}

OpenAPI Tag

The openapi tag controls OpenAPI-specific schema properties:

// Boolean flags (no value needed)
openapi:"readOnly"              // Field is read-only (e.g., ID, created_at)
openapi:"writeOnly"             // Field is write-only (e.g., password, secret)
openapi:"deprecated"            // Field is deprecated
openapi:"hidden"                // Field excluded from OpenAPI schema (but in JSON)
openapi:"required"              // Override required status for docs only

// Documentation
openapi:"title=Field Title"
openapi:"description=Detailed description"
openapi:"format=date-time"      // OpenAPI format (date, date-time, email, uri, uuid, etc.)

// Examples (pipe-separated for multiple values)
openapi:"examples=value"        // Single example
openapi:"examples=val1|val2"    // Multiple examples

// Extensions (must start with x-, valid at both field and struct level)
openapi:"x-internal=true,x-category=admin"

// Struct-level options (on _ blank identifier field)
openapi:"additionalProperties=false"           // Disallow additional properties
openapi:"nullable=true"                        // Struct can be null
openapi:"additionalProperties=false,x-strict=true"  // Can combine with extensions

Validate Tag

The validate tag uses go-playground/validator format and maps to OpenAPI constraints:

validate:"required"             -> Required=true, used as source of truth
validate:"min=5,max=100"        -> Minimum=5, Maximum=100
validate:"gt=0,lt=100"          -> ExclusiveMinimum=0, ExclusiveMaximum=100
validate:"email"                -> Format="email" (can be overridden by openapi:"format=...")
validate:"url"                  -> Format="uri"
validate:"oneof=red green blue" -> Enum=["red","green","blue"]

Note: validate tag is the source of truth for constraints. Use openapi tag only to add documentation metadata or override specific values for documentation purposes.

Default Tag

The default tag sets default values for fields:

default:"value"              // String default (no quotes needed)
default:"42"                 // Number default (parsed as JSON)
default:"true"               // Boolean default (parsed as JSON)
default:"[1,2,3]"           // Array default (parsed as JSON)
default:"{\"key\":\"value\"}" // Object default (parsed as JSON)

Requires Tag

The requires tag specifies fields that become required when this field is present (JSON Schema dependentRequired keyword):

type Payment struct {
    CreditCard     string `json:"credit_card" requires:"billing_address,cvv"`
    BillingAddress string `json:"billing_address"`
    CVV            string `json:"cvv"`
}

When credit_card is present, billing_address and cvv become required.

Hidden vs json:"-"

Two ways to hide fields, with different purposes:

json:"-"                 // Field not serialized to JSON AND hidden from OpenAPI
openapi:"hidden"         // Field serialized to JSON BUT hidden from OpenAPI schema

Use cases:

  • json:"-" → Completely internal fields (never in API responses or docs)
  • openapi:"hidden" → Runtime fields that appear in responses but not in documentation

Error Handling

All parsers return descriptive errors that include:

  • Field name where the error occurred
  • Tag name that failed to parse
  • Specific reason for the failure

Example error: "field Email: failed to parse validate tag: invalid email format"

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseDefaultTag

func ParseDefaultTag(field reflect.StructField, index int, tagValue string) (any, error)

ParseDefaultTag parses a default tag and returns DefaultMetadata. Tag format: default:"value".

Parses the default value based on the field type:

  • Strings: returned as-is (no quotes needed in tag)
  • Numbers, booleans, arrays, objects: parsed as JSON (e.g., default:"[1,2,3]" or default:"{\"key\":\"value\"}")

func ParseOpenAPITag

func ParseOpenAPITag(field reflect.StructField, index int, tagValue string) (any, error)

ParseOpenAPITag parses an openapi tag and returns OpenAPIMetadata. Tag format: openapi:"readOnly,writeOnly,deprecated,hidden,required,title=My Title,description=My description,examples=val1|val2|val3,x-custom=value"

This parser: 1. Parses tag format (comma-separated, key=value pairs or flags) 2. Converts string values to proper OpenAPI types (bool for readOnly/writeOnly/deprecated/hidden/required) 3. Converts empty string to true for boolean flags (e.g., "readOnly" -> ReadOnly=true) 4. Routes x-* prefixed keys to Extensions map (OpenAPI spec requirement) 5. Detects struct-level vs field-level based on field name (blank identifier _ = struct-level) 6. Supports pipe-separated examples values: examples=val1|val2|val3

Field-level options (for named fields):

  • readOnly -> ReadOnly=true
  • writeOnly -> WriteOnly=true
  • deprecated -> Deprecated=true
  • hidden -> Hidden=true (field excluded from schema properties)
  • required -> Required=true (overrides validate:"required" for docs only)
  • title=... -> Title="..."
  • description=... -> Description="..."
  • format=... -> Format="..." (e.g., "date", "date-time", "time", "email", "uri")
  • examples=val1|val2|val3 -> Examples=[val1, val2, val3] (pipe-separated values)

Struct-level options (for _ blank identifier field):

  • additionalProperties=true/false -> AdditionalProperties=bool
  • nullable=true/false -> Nullable=bool

OpenAPI extensions (valid at both field and struct level):

  • x-* -> Extensions["x-*"]="..." (MUST start with x-, minimum length 4)

func ParseRequiresTag

func ParseRequiresTag(field reflect.StructField, index int, tagValue string) (any, error)

ParseRequiresTag parses a requires tag and returns RequiresMetadata. Tag format: requires:"field1,field2,field3"

Parses comma-separated list of field names that become required when this field is present. Empty strings and whitespace are filtered out.

Example:

  • requires:"billing_address,cvv" -> Fields=["billing_address", "cvv"]
  • requires:"field1" -> Fields=["field1"]
  • requires:"" -> Fields=[] (empty, will be ignored)

func ParseValidateTag

func ParseValidateTag(field reflect.StructField, index int, tagValue string) (any, error)

ParseValidateTag parses a validate tag in go-playground/validator format and returns ValidateMetadata. Tag format: validate:"required,email,min=5,max=100,pattern=^[a-z]+$"

This parser: 1. Parses go-playground/validator tag format (comma-separated, key=value pairs) 2. Maps validator tags to OpenAPI/JSON Schema constraints 3. Converts string values to proper OpenAPI types (int, float64, bool) 4. Returns error if value cannot be parsed to expected type

Validator tag -> OpenAPI mapping:

  • required -> Required=true
  • min=N -> Minimum=N (as float64)
  • max=N -> Maximum=N (as float64)
  • len=N -> Minimum=N, Maximum=N (as float64, sets both to same value)
  • email -> Format="email"
  • url -> Format="uri"
  • pattern=... -> Pattern="..."
  • oneof=... -> Enum="[...]"
  • etc.

Types

type DefaultMetadata

type DefaultMetadata struct {
	Value any // Parsed default value (JSON-compatible types: string, float64, bool, []any, map[string]any)
}

DefaultMetadata represents the default value extracted from the default tag. This is used for both runtime default application (via mapstructure) and OpenAPI schema generation.

type OpenAPIMetadata

type OpenAPIMetadata struct {
	// Field-level API contract metadata (not validation constraints)
	// OpenAPI v3.0: readOnly, writeOnly, deprecated are booleans
	ReadOnly    *bool  // field is read-only
	WriteOnly   *bool  // field is write-only
	Deprecated  *bool  // field is deprecated
	Hidden      *bool  // field is hidden from schema (not included in properties)
	Required    *bool  // field is required (override for validate:"required")
	Title       string // title for the schema
	Description string // description for the schema
	Format      string // format for the schema (e.g., "date", "date-time", "time", "email", "uri")
	Examples    []any  // parsed example values

	// Struct-level metadata (only valid when used on _ blank identifier field)
	AdditionalProperties *bool // allow additional properties (struct-level)
	Nullable             *bool // struct is nullable (struct-level)

	// Extensions are OpenAPI specification extensions (x-* fields).
	// Keys must start with "x-" per OpenAPI spec requirement.
	Extensions map[string]any
}

OpenAPIMetadata represents OpenAPI-specific schema metadata extracted from the openapi tag. Types match OpenAPI v3.0 specification for schema metadata. This metadata is used to generate OpenAPI schema properties that are not validation constraints but API contract metadata (e.g., readOnly, writeOnly, deprecated, title, description, examples).

When used on a field (not the _ blank identifier), it represents field-level metadata. When used on the _ blank identifier field, it represents struct-level metadata (additionalProperties, nullable).

type RequiresMetadata

type RequiresMetadata struct {
	Fields []string // List of field names that become required when this field is present
}

RequiresMetadata represents fields that become required when this field is present. Extracted from the requires tag for OpenAPI schema generation (JSON Schema dependentRequired keyword).

type ValidateMetadata

type ValidateMetadata struct {
	// Numeric validation constraints (for number/integer types)
	// OpenAPI v3.0: minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf are numbers
	Minimum          *float64 // inclusive minimum value
	ExclusiveMinimum *float64 // exclusive minimum value (value must be > exclusiveMinimum)
	Maximum          *float64 // inclusive maximum value
	ExclusiveMaximum *float64 // exclusive maximum value (value must be < exclusiveMaximum)
	MultipleOf       *float64 // value must be a multiple of this number

	// String validation constraints (for string types)
	Pattern string // regular expression pattern that string must match
	Format  string // predefined format for string validation (e.g., "email", "date-time", "uri")

	// General validation constraints
	Enum     []any // parsed enum values
	Required *bool // field must be present
}

ValidateMetadata represents validation constraints extracted from the validate tag. Types match OpenAPI v3.0 specification for schema validation constraints. This metadata is used to generate OpenAPI schema constraints by mapping go-playground/validator tags to OpenAPI/JSON Schema keywords.

Jump to

Keyboard shortcuts

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