schema

package module
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Nov 21, 2025 License: MIT Imports: 8 Imported by: 0

README

OpenAPI Schema Processor

A Go library for processing OpenAPI 3.x (3.0, 3.1, 3.2) schema definitions. Supports conversion to Protocol Buffer 3 (proto3), Go structs, JSON example generation, and schema validation.

Go Version CI Status Go Report Card

Overview

This library parses OpenAPI 3.x specifications (3.0, 3.1, and 3.2) and provides multiple processing capabilities: generating .proto files, Go struct types, JSON examples, and validating example data against schemas. It's designed for projects that need to work with OpenAPI schemas in various ways.

Installation

go get github.com/duh-rpc/openapi-schema.go

Usage

Basic Example
package main

import (
    "fmt"
    "os"

    schema "github.com/duh-rpc/openapi-schema.go"
)

func main() {
    // Read OpenAPI specification
    openapi, err := os.ReadFile("api.yaml")
    if err != nil {
        panic(err)
    }

    // Convert to proto3 and Go
    result, err := schema.Convert(openapi, schema.ConvertOptions{
        PackageName: "myapi",
        PackagePath: "github.com/example/proto/v1",
    })
    if err != nil {
        panic(err)
    }

    // Write proto file (if generated)
    if len(result.Protobuf) > 0 {
        err = os.WriteFile("api.proto", result.Protobuf, 0644)
        if err != nil {
            panic(err)
        }
    }

    // Write Go file (if generated - for types with unions)
    if len(result.Golang) > 0 {
        err = os.WriteFile("types.go", result.Golang, 0644)
        if err != nil {
            panic(err)
        }
    }
}
Go-Only Conversion

If you need Go struct types without Protocol Buffer definitions, use ConvertToStruct() to generate pure Go code:

package main

import (
    "fmt"
    "os"

    schema "github.com/duh-rpc/openapi-schema.go"
)

func main() {
    // Read OpenAPI specification
    openapi, err := os.ReadFile("api.yaml")
    if err != nil {
        panic(err)
    }

    // Convert ALL schemas to Go structs (no protobuf)
    result, err := schema.ConvertToStruct(openapi, schema.ConvertOptions{
        GoPackagePath: "github.com/example/types/v1",
    })
    if err != nil {
        panic(err)
    }

    // Write Go file
    err = os.WriteFile("types.go", result.Golang, 0644)
    if err != nil {
        panic(err)
    }

    // TypeMap shows all types as Go structs
    for typeName, info := range result.TypeMap {
        fmt.Printf("%s: %s (%s)\n", typeName, info.Location, info.Reason)
    }
}

Key Differences from Convert():

Feature Convert() ConvertToStruct()
Output Proto + Go (for unions) Go only
Type classification Transitive closure filtering All schemas become Go
Union handling Custom marshaling Custom marshaling
Regular types Proto messages Go structs with JSON tags
Use case Dual proto/Go interface Pure Go types

When to use ConvertToStruct():

  • You need Go types but not protobuf definitions
  • You want all schemas as Go structs for a consistent API
  • You're building a pure Go application without gRPC
  • You want simpler type management (everything in one Go file)
JSON Example Generation

Generate JSON examples from OpenAPI schemas for documentation, testing, or API design. The ConvertToExamples() function creates realistic examples that honor schema constraints like min/max values, string formats, enums, and required fields.

package main

import (
    "encoding/json"
    "fmt"
    "os"

    schema "github.com/duh-rpc/openapi-schema.go"
)

func main() {
    openapi := []byte(`openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        age:
          type: integer
          minimum: 18
          maximum: 120
        status:
          type: string
          enum: [active, inactive]
`)

    // Generate examples for all schemas
    result, err := schema.ConvertToExamples(openapi, schema.ExampleOptions{
        IncludeAll: true,
        MaxDepth:   5,
        Seed:       12345, // For deterministic generation
    })
    if err != nil {
        panic(err)
    }

    // Access generated examples
    userJSON := result.Examples["User"]
    fmt.Printf("User example: %s\n", string(userJSON))

    // Or unmarshal to validate structure
    var user map[string]interface{}
    json.Unmarshal(userJSON, &user)
    fmt.Printf("Email: %s, Age: %d\n", user["email"], int(user["age"].(float64)))
}

Example output:

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "email": "user@example.com",
  "age": 42,
  "status": "active"
}

ExampleOptions:

  • IncludeAll: Generate examples for all schemas (takes precedence over SchemaNames)
  • SchemaNames: Specific schemas to generate examples for (used when IncludeAll is false)
  • MaxDepth: Maximum nesting depth for circular references (default: 5)
  • Seed: Random seed for deterministic generation (0 = time-based randomness)

Constraint Handling:

The example generator honors OpenAPI schema constraints:

Constraint Behavior
minimum / maximum Generates numbers within range
minLength / maxLength Generates strings within length limits
minItems / maxItems Generates arrays within item count limits
enum Picks first value for deterministic output
format Generates format-specific values (email, uuid, uri, date, date-time)
default Uses default value if specified
example Uses example value if specified (highest priority)

Field Heuristics:

The example generator applies smart heuristics based on field names to produce more realistic examples:

Cursor Fields - Fields named cursor, first, or after (case-insensitive) generate base64-looking strings:

openapi := []byte(`openapi: 3.0.0
components:
  schemas:
    PageInfo:
      type: object
      properties:
        cursor:
          type: string
        hasNext:
          type: boolean
`)

result, _ := schema.ConvertToExamples(openapi, schema.ExampleOptions{
    IncludeAll: true,
    Seed:       42,
})
// cursor: "dGhpc2lzYWN1cnNvcg" (16-32 character base64-like string)

Message Fields - Fields named error or message (case-insensitive) generate human-readable text:

openapi := []byte(`openapi: 3.0.0
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        code:
          type: integer
        error:
          type: string
        message:
          type: string
`)

result, _ := schema.ConvertToExamples(openapi, schema.ExampleOptions{
    IncludeAll: true,
})
// error: "An error occurred"
// message: "This is a message"

Non-Zero Defaults - Integers and numbers without constraints generate random values (1-100 for integers, 1.0-100.0 for numbers) instead of zero:

openapi := []byte(`openapi: 3.0.0
components:
  schemas:
    Product:
      type: object
      properties:
        quantity:
          type: integer
        price:
          type: number
`)

result, _ := schema.ConvertToExamples(openapi, schema.ExampleOptions{
    IncludeAll: true,
    Seed:       42,
})
// quantity: 42 (random 1-100)
// price: 67.3 (random 1.0-100.0)

Field Overrides:

Override specific field values across all schemas using FieldOverrides:

openapi := []byte(`openapi: 3.0.0
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        code:
          type: integer
        message:
          type: string
`)

result, _ := schema.ConvertToExamples(openapi, schema.ExampleOptions{
    FieldOverrides: map[string]interface{}{
        "code":    500,
        "message": "Internal server error",
    },
    IncludeAll: true,
})
// code: 500 (overridden)
// message: "Internal server error" (overridden)

Override Priority: example > default > FieldOverride > heuristics > generated value

Field overrides use case-sensitive matching and apply to any field with the matching name across all schemas.

Circular Reference Handling:

Circular references are automatically detected and broken to prevent infinite recursion:

// Schema with circular reference
openapi := []byte(`openapi: 3.0.0
components:
  schemas:
    User:
      type: object
      properties:
        name:
          type: string
        friends:
          type: array
          items:
            $ref: '#/components/schemas/User'
`)

result, err := schema.ConvertToExamples(openapi, schema.ExampleOptions{
    IncludeAll: true,
    MaxDepth:   3, // Limit nesting depth
})
// The 'friends' array will be generated but nested User objects
// will be omitted once the depth limit is reached

See docs/examples.md for detailed documentation.

Input: OpenAPI 3.x YAML
openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
paths: {}
components:
  schemas:
    User:
      type: object
      description: A user account
      properties:
        userId:
          type: string
          description: Unique user identifier
        email:
          type: string
        age:
          type: integer
        isActive:
          type: boolean
Output: Proto3
syntax = "proto3";

package myapi;

// A user account
message User {
  // Unique user identifier
  string userId = 1 [json_name = "userId"];
  string email = 2 [json_name = "email"];
  int32 age = 3 [json_name = "age"];
  bool isActive = 4 [json_name = "isActive"];
}

Union Support with OneOf

This library supports OpenAPI oneOf schemas with discriminators by generating Go structs with custom JSON marshaling instead of Protocol Buffer messages. This approach maintains complete JSON compatibility with the OpenAPI specification while avoiding protobuf's incompatible oneof format.

Why Go Code Generation?

OpenAPI's oneOf with discriminators produces flat JSON like {"petType": "dog", "bark": "woof"}, but protobuf's oneof wraps the variant: {"dog": {"petType": "dog", "bark": "woof"}}. These formats are incompatible. To maintain OpenAPI's JSON contract, union types are generated as Go code with custom marshaling. See discriminated-unions.md for details.

Basic Union Example

OpenAPI:

openapi: 3.0.0
info:
  title: Pet API
  version: 1.0.0
components:
  schemas:
    Pet:
      oneOf:
        - $ref: '#/components/schemas/Dog'
        - $ref: '#/components/schemas/Cat'
      discriminator:
        propertyName: petType

    Dog:
      type: object
      properties:
        petType:
          type: string
          enum: [dog]
        bark:
          type: string

    Cat:
      type: object
      properties:
        petType:
          type: string
          enum: [cat]
        meow:
          type: string

Generated Go Code:

package mypkg

import (
    "encoding/json"
    "fmt"
    "strings"
)

// Union wrapper with pointer fields to variants
type Pet struct {
    Dog *Dog
    Cat *Cat
}

// Custom marshaling to match flat OpenAPI JSON
func (u *Pet) MarshalJSON() ([]byte, error) {
    if u.Dog != nil {
        return json.Marshal(u.Dog)
    }
    if u.Cat != nil {
        return json.Marshal(u.Cat)
    }
    return nil, fmt.Errorf("Pet: no variant set")
}

func (u *Pet) UnmarshalJSON(data []byte) error {
    var discriminator struct {
        PetType string `json:"petType"`
    }
    if err := json.Unmarshal(data, &discriminator); err != nil {
        return err
    }

    // Case-insensitive discriminator matching
    switch strings.ToLower(discriminator.PetType) {
    case "dog":
        u.Dog = &Dog{}
        return json.Unmarshal(data, u.Dog)
    case "cat":
        u.Cat = &Cat{}
        return json.Unmarshal(data, u.Cat)
    default:
        return fmt.Errorf("unknown petType: %s", discriminator.PetType)
    }
}

type Dog struct {
    PetType string `json:"petType"`
    Bark    string `json:"bark"`
}

type Cat struct {
    PetType string `json:"petType"`
    Meow    string `json:"meow"`
}

JSON Format (matches OpenAPI spec exactly):

{"petType": "dog", "bark": "woof"}
Using ConvertResult and TypeMap

When schemas contain unions, Convert() returns a ConvertResult with separate proto and Go outputs. Similarly, ConvertToStruct() returns a StructResult with Go-only output:

result, err := schema.Convert(openapi, schema.ConvertOptions{
    PackageName:   "myapi",
    PackagePath:   "github.com/example/proto/v1",
    GoPackagePath: "github.com/example/types/v1",  // Optional, defaults to PackagePath
})
if err != nil {
    panic(err)
}

// TypeMap tells you where each type is generated
for typeName, info := range result.TypeMap {
    fmt.Printf("%s: %s (%s)\n", typeName, info.Location, info.Reason)
}
// Output:
// Pet: golang (contains oneOf)
// Dog: golang (variant of union type Pet)
// Cat: golang (variant of union type Pet)
// Owner: golang (references union type Pet)
// Address: proto ()

// Protobuf contains types that don't use unions
if len(result.Protobuf) > 0 {
    os.WriteFile("api.proto", result.Protobuf, 0644)
}

// Golang contains union types and anything that references them
if len(result.Golang) > 0 {
    os.WriteFile("types.go", result.Golang, 0644)
}
Transitive Closure for Union Types

When a schema contains or references a union, it becomes a Go type. This applies transitively:

  • Union types (Pet with oneOf) → Go
  • Union variants (Dog, Cat referenced in oneOf) → Go
  • Types referencing unions (Owner with pet: $ref Pet) → Go
  • Proto-only types (Address with no union connection) → Proto

The TypeMap provides complete visibility into why each type is generated where it is.

Union Requirements

For Phase 1 support, unions must meet these requirements:

  • Discriminator required: All oneOf schemas must have a discriminator.propertyName
  • Reference-based variants: All variants must use $ref (no inline schemas)
  • Discriminator in variants: Each variant schema must include the discriminator property
  • Case-insensitive matching: Discriminator values match schema names case-insensitively

Supported:

Pet:
  oneOf:
    - $ref: '#/components/schemas/Dog'
    - $ref: '#/components/schemas/Cat'
  discriminator:
    propertyName: petType

Not supported (will error):

# Missing discriminator
Pet:
  oneOf:
    - $ref: '#/components/schemas/Dog'
    - $ref: '#/components/schemas/Cat'

# Inline variant (not $ref)
Pet:
  oneOf:
    - type: object
      properties:
        bark: {type: string}
  discriminator:
    propertyName: petType

Supported Features

OpenAPI Features
  • ✅ Object schemas with properties
  • ✅ Scalar types (string, integer, number, boolean)
  • ✅ String enums (mapped to string fields with enum comments)
  • ✅ Integer enums (mapped to protobuf enum types)
  • ✅ Arrays (repeated fields)
  • ✅ Nested objects
  • ✅ Schema references ($ref)
  • ✅ Descriptions (converted to comments)
  • ✅ Multiple format specifiers (int32, int64, float, double, byte, binary, date, date-time)
Proto3 Features
  • ✅ Message definitions
  • ✅ Enum definitions with UNSPECIFIED values
  • ✅ Repeated fields
  • ✅ Nested messages
  • ✅ JSON name annotations
  • ✅ Field numbering (sequential based on YAML order)
  • ✅ Comments from descriptions

Unsupported Features

OpenAPI Features Not Supported
  • oneOf with discriminators (generates Go code with custom marshaling)
  • ✅ Nullable type arrays (OpenAPI 3.1+ type: [string, null] syntax)
  • ❌ Schema composition: allOf, anyOf, not
  • oneOf without discriminators
  • ❌ Inline oneOf variants (must use $ref)
  • ❌ External file references (only internal #/components/schemas refs)
  • ❌ Nested arrays (e.g., array of array)
  • ❌ Truly multi-type properties (e.g., type: [string, integer]) - only nullable variants allowed
  • ❌ Map types via additionalProperties
  • ❌ Validation constraints (min, max, pattern, etc. are ignored)
  • ❌ OpenAPI 2.0 (Swagger) - only 3.x supported
Proto3 Features Not Generated
  • ❌ Service definitions
  • ❌ Multiple output files (single file only)
  • ❌ Import statements
  • ❌ Proto options beyond json_name
  • ❌ Map types
  • optional keyword (all fields follow proto3 default semantics)
  • ❌ Wrapper types for nullable fields
Nullable Field Handling

The library supports nullable types in both OpenAPI 3.0 and 3.1+ syntax:

OpenAPI 3.0 nullable syntax:

properties:
  name:
    type: string
    nullable: true

OpenAPI 3.1+ type array syntax:

properties:
  name:
    type: [string, null]

Both are converted to the same proto3 field:

string name = 1 [json_name = "name"];

Important: Proto3 doesn't have a nullable concept - it uses zero values to indicate "not set" (empty string for strings, 0 for numbers, false for booleans, null for messages). The nullable keyword and null type are processed but don't change the proto3 output, since proto3 fields are inherently nullable through zero values.

Ignored OpenAPI Directives
  • The required array is ignored (proto3 has no required keyword)
  • The nullable field is ignored (proto3 uses zero values for optional semantics)

Type Mapping

OpenAPI Type OpenAPI Format Proto3 Type Notes
string (none) string
string byte bytes
string binary bytes
string date string
string date-time string
string + enum (none) string Enum values in comments
integer (none) int32
integer int32 int32
integer int64 int64
integer + enum (none) enum Protobuf enum type
number (none) double
number float float
number double double
boolean (any) bool
object (any) message
array (any) repeated

Naming Conventions

Field Names: Preservation

The library preserves original OpenAPI field names when they're valid proto3 syntax:

  • HTTPStatusHTTPStatus (preserved)
  • userIduserId (preserved)
  • user_iduser_id (preserved)

Invalid characters are replaced with underscores:

  • status-codestatus_code (hyphen → underscore)
  • user.nameuser_name (dot → underscore)
  • first namefirst_name (space → underscore)

All fields include a json_name annotation to explicitly map to the original OpenAPI field name.

Proto3 Field Name Requirements

Field names must:

  • Start with an ASCII letter (A-Z or a-z) - non-ASCII letters like ñ are not allowed
  • Contain only ASCII letters, digits (0-9), and underscores (_)
  • Field names starting with digits or underscores will cause errors
  • Field names that are proto3 reserved keywords (like message, enum, package) will cause protoc compilation errors - the library does not detect or prevent these

Note on Reserved Keywords: Proto3 has reserved keywords like message, enum, service, package, import, option, etc. If your OpenAPI schema has field names that match these keywords, the generated proto file will fail to compile with protoc. This is intentional - the library lets protoc handle keyword validation rather than maintaining a keyword list that might change across proto versions.

Best Practices

While proto3 syntax allows mixed-case field names, the Protocol Buffers style guide recommends snake_case for consistency across languages. If you control your OpenAPI schema, consider using snake_case field names to align with proto3 conventions.

BREAKING CHANGE Notice

This represents a breaking change from previous library behavior.

Previous behavior:

  • Field names were converted to snake_case: HTTPStatush_t_t_p_status
  • Simple letter-by-letter conversion with no acronym detection

New behavior:

  • Field names are preserved when valid: HTTPStatusHTTPStatus
  • Only invalid characters are replaced: status-codestatus_code

Migration: If you have existing code that references generated proto field names, you will need to update those references. For example:

  • Proto references: message.h_t_t_p_statusmessage.HTTPStatus
  • Any tooling parsing .proto files needs adjustment for new field names

Rationale: Preserving original names provides more intuitive mapping between OpenAPI and proto, respects your naming choices, and avoids surprising transformations like HTTPStatush_t_t_p_status.

Message Names: PascalCase

Schema names and nested message names are converted to PascalCase:

  • user_accountUserAccount
  • shippingAddressShippingAddress
Enum Values: UPPERCASE_SNAKE_CASE (Integer Enums Only)

Integer enum values are prefixed with the enum name and converted to uppercase:

  • Enum Code with value 200CODE_200
  • Enum Code with value 404CODE_404

All integer enums automatically include an UNSPECIFIED value at position 0 following proto3 conventions.

String enums do not generate protobuf enum types - they become string fields with enum values documented in comments.

Plural Name Validation

When using inline objects or enums in arrays, property names must be singular:

# ✅ GOOD - singular property name
properties:
  contact:
    type: array
    items:
      type: object
      properties:
        name:
          type: string

# ❌ BAD - plural property name
properties:
  contacts:  # Will cause error
    type: array
    items:
      type: object

Why? The library derives message names from property names. A plural property name like contacts would generate a message named Contacts, which is confusing. Instead:

  • Use singular names: contactContact message
  • Or use $ref to reference a named schema

Examples

Enums

The library handles string enums and integer enums differently to preserve JSON wire format compatibility.

String Enums

String enums map to string fields with enum value annotations in comments:

OpenAPI:

components:
  schemas:
    Order:
      type: object
      properties:
        status:
          type: string
          description: Status of the order
          enum:
            - pending
            - confirmed
            - shipped

Proto3:

message Order {
  // Status of the order
  // enum: [pending, confirmed, shipped]
  string status = 1 [json_name = "status"];
}

String enums preserve JSON wire format exactly - the JSON will contain "pending" not 1 or "ORDER_STATUS_PENDING".

Integer Enums

Integer enums map to protobuf enum types:

OpenAPI:

components:
  schemas:
    Code:
      type: integer
      enum:
        - 200
        - 400
        - 404
        - 500

Proto3:

enum Code {
  CODE_UNSPECIFIED = 0;
  CODE_200 = 1;
  CODE_400 = 2;
  CODE_404 = 3;
  CODE_500 = 4;
}
Nested Objects

OpenAPI:

components:
  schemas:
    User:
      type: object
      properties:
        name:
          type: string
        address:
          type: object
          properties:
            street:
              type: string
            city:
              type: string

Proto3:

message User {
  message Address {
    string street = 1 [json_name = "street"];
    string city = 2 [json_name = "city"];
  }

  string name = 1 [json_name = "name"];
  Address address = 2 [json_name = "address"];
}
Arrays with References

OpenAPI:

components:
  schemas:
    Address:
      type: object
      properties:
        street:
          type: string
        city:
          type: string

    User:
      type: object
      properties:
        name:
          type: string
        address:
          type: array
          items:
            $ref: '#/components/schemas/Address'

Proto3:

message Address {
  string street = 1 [json_name = "street"];
  string city = 2 [json_name = "city"];
}

message User {
  string name = 1 [json_name = "name"];
  repeated Address address = 2 [json_name = "address"];
}
Name Conflict Resolution

When multiple schemas have the same name, numeric suffixes are automatically added:

OpenAPI:

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string

    User:  # Duplicate name
      type: object
      properties:
        name:
          type: string

Proto3:

message User {
  string id = 1 [json_name = "id"];
}

message User_2 {
  string name = 1 [json_name = "name"];
}

Best Practices

  1. Use singular property names for arrays with inline objects/enums, or use $ref to reference named schemas
  2. Consider snake_case field names in your OpenAPI schema to align with proto3 style guide conventions
  3. Use descriptions liberally - they become useful comments in the generated proto
  4. Order schemas intentionally in your OpenAPI YAML - the output order will match
  5. Test with protoc after generation to catch any proto3 reserved keywords

Development

Running Tests
make test
Test Coverage
make coverage
Linting
make lint
Detailed Documentation

See the following links for more details:

  • Enums - How string enums are converted and their limitations
  • Scalar Types - Type mapping between OpenAPI and proto3
  • Objects - Message generation and nested objects
  • Discriminated Unions - How oneOf with discriminators generates Go code

License

MIT License - see LICENSE file for details

Acknowledgments

This library uses the excellent libopenapi for OpenAPI parsing, which provides support for OpenAPI 3.0 and 3.1 specifications.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConvertOptions

type ConvertOptions struct {
	// PackageName is the name of the generated proto3 package (e.g. "api")
	PackageName string
	// PackagePath is the path of the generated proto3 package (e.g. "github.com/myorg/proto/v1/api")
	PackagePath string
	// GoPackagePath is the path for generated Go code (defaults to PackagePath if empty)
	GoPackagePath string
}

ConvertOptions configures the conversion from OpenAPI to Protocol Buffers

type ConvertResult

type ConvertResult struct {
	Protobuf []byte
	Golang   []byte
	TypeMap  map[string]*TypeInfo
}

ConvertResult contains the outputs from converting OpenAPI to proto3 and Go code.

When schemas contain oneOf with discriminators, a hybrid approach is used:

  • Protobuf contains types that don't use unions (may be empty if all types use unions)
  • Golang contains union types, their variants, and any types that reference them
  • TypeMap provides metadata about where each type was generated and why

Output field behavior:

  • Protobuf is empty when all schemas are union-related (use unions or reference union types)
  • Golang is empty when no schemas contain or reference oneOf unions
  • Both may contain content when schemas are mixed (some use unions, some don't)

func Convert

func Convert(openapi []byte, opts ConvertOptions) (*ConvertResult, error)

Convert converts OpenAPI 3.x schemas (3.0, 3.1, 3.2) to Protocol Buffer 3 format. It takes OpenAPI specification bytes (YAML or JSON) and conversion options, and returns a ConvertResult containing proto3 output, Go output, and type metadata.

Field names are preserved from the OpenAPI schema when they meet proto3 syntax requirements. Invalid characters (hyphens, dots, spaces) are replaced with underscores. All fields include json_name annotations for correct JSON mapping.

Examples:

  • HTTPStatus → HTTPStatus [json_name = "HTTPStatus"]
  • userId → userId [json_name = "userId"]
  • status-code → status_code [json_name = "status-code"]

The function validates inputs, parses the OpenAPI document, extracts schemas, and generates corresponding proto3 message definitions.

Returns an error if:

  • openapi is empty
  • opts.PackageName is empty
  • opts.PackagePath is empty
  • the OpenAPI document is invalid or not version 3.x
  • any schema contains unsupported features

type ExampleOptions

type ExampleOptions struct {
	SchemaNames []string // Specific schemas to generate (ignored if IncludeAll is true)
	MaxDepth    int      // Maximum nesting depth (default 5)
	IncludeAll  bool     // If true, generate examples for all schemas (takes precedence over SchemaNames)
	Seed        int64    // Random seed for deterministic generation (0 = use time-based seed)
	// FieldOverrides allows overriding generated values for specific field names (e.g., {"code": 400, "status": "error"}).
	// - Applies to any field with matching name (case-sensitive) across all schemas
	// - Takes precedence over heuristics and generated values
	// - Does NOT override schema.Example or schema.Default (those have higher precedence)
	// - Type must match schema type or error is returned
	FieldOverrides map[string]interface{}
}

ExampleOptions configures JSON example generation

type ExampleResult

type ExampleResult struct {
	Examples map[string]json.RawMessage // schema name → JSON example
}

ExampleResult contains generated JSON examples for schemas

func ConvertToExamples

func ConvertToExamples(openapi []byte, opts ExampleOptions) (*ExampleResult, error)

ConvertToExamples generates JSON examples from OpenAPI schemas

type IssueSeverity

type IssueSeverity string

IssueSeverity indicates whether an issue is an error or warning

const (
	IssueSeverityError   IssueSeverity = "error"
	IssueSeverityWarning IssueSeverity = "warning"
)

type SchemaValidationResult

type SchemaValidationResult struct {
	SchemaPath  string
	HasExamples bool
	Valid       bool
	Issues      []ValidationIssue
}

SchemaValidationResult contains validation details for a single schema

type StructResult

type StructResult struct {
	Golang  []byte
	TypeMap map[string]*TypeInfo
}

StructResult contains the output from converting OpenAPI to Go structs only.

This is the result type for ConvertToStruct(), which generates Go structs for all schemas without producing Protocol Buffer definitions.

Field behavior:

  • Golang contains Go source code with all schema types as structs
  • TypeMap provides metadata about each type (all marked as TypeLocationGolang)
  • Union types include custom MarshalJSON/UnmarshalJSON methods
  • Regular types are simple structs with JSON tags

func ConvertToStruct

func ConvertToStruct(openapi []byte, opts ConvertOptions) (*StructResult, error)

ConvertToStruct converts all OpenAPI schemas to Go structs only, without generating Protocol Buffer definitions. This provides a pure Go struct generation path for users who need Go types but not protobuf.

Unlike Convert(), this function generates Go structs for ALL schemas:

  • Union types (oneOf with discriminator) get custom MarshalJSON/UnmarshalJSON
  • Regular types become simple structs with JSON tags
  • All types appear in TypeMap with Location=TypeLocationGolang

Field names follow the same conversion rules as Convert():

  • Invalid proto characters (hyphens, dots, spaces) are replaced with underscores
  • JSON tags preserve original field names from OpenAPI schema

Parameters:

  • openapi: OpenAPI specification bytes (YAML or JSON)
  • opts: Conversion options (only GoPackagePath is required, PackageName defaults to "main")

Returns:

  • StructResult containing Go source code and type metadata

Returns an error if:

  • openapi is empty
  • opts.GoPackagePath is empty
  • the OpenAPI document is invalid or not version 3.x
  • any schema contains unsupported features

type TypeInfo

type TypeInfo struct {
	Location TypeLocation
	Reason   string
}

TypeInfo contains metadata about where a type is generated and why

type TypeLocation

type TypeLocation string

TypeLocation indicates whether a type is generated as proto or golang

const (
	TypeLocationProto  TypeLocation = "proto"
	TypeLocationGolang TypeLocation = "golang"
)

type ValidateOptions

type ValidateOptions struct {
	SchemaNames []string // Specific schemas to validate (ignored if IncludeAll is true)
	IncludeAll  bool     // If true, validate all schemas (takes precedence over SchemaNames)
}

ValidateOptions configures example validation

type ValidationIssue

type ValidationIssue struct {
	Severity     IssueSeverity
	ExampleField string
	Message      string
	Line         int
}

ValidationIssue represents a single validation error or warning

type ValidationResult

type ValidationResult struct {
	Schemas map[string]*SchemaValidationResult
}

ValidationResult contains the validation status for all examples in an OpenAPI spec

func ValidateExamples

func ValidateExamples(openapi []byte, opts ValidateOptions) (*ValidationResult, error)

ValidateExamples validates examples in OpenAPI spec against schemas. It validates the 'example' and 'examples' fields in Schema Objects under components/schemas.

For schemas with the 'examples' map, all entries are validated. If both 'example' and 'examples' exist on the same schema, both are validated.

Parameters:

  • openapi: OpenAPI specification bytes (YAML or JSON)
  • opts: Validation options (SchemaNames to filter specific schemas, or IncludeAll to validate all)

Returns:

  • ValidationResult containing per-schema validation results with errors and warnings

Returns an error if:

  • openapi is empty
  • opts.IncludeAll is false and opts.SchemaNames is empty
  • the OpenAPI document is invalid or not version 3.x

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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