openapi

package
v0.0.105 Latest Latest
Warning

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

Go to latest
Published: Dec 11, 2025 License: MIT Imports: 9 Imported by: 0

README

OpenAPI Generator for ResolveSpec

This package provides automatic OpenAPI 3.0 specification generation for ResolveSpec, RestheadSpec, and FuncSpec API frameworks.

Features

  • Automatic Schema Generation: Generates OpenAPI schemas from Go struct models
  • Multiple Framework Support: Works with RestheadSpec, ResolveSpec, and FuncSpec
  • Dynamic Endpoint Discovery: Automatically discovers all registered models and generates paths
  • Query Parameter Access: Access spec via ?openapi on any endpoint or via /openapi
  • Comprehensive Documentation: Includes all request/response schemas, parameters, and security schemes

Quick Start

RestheadSpec Example
import (
    "github.com/bitechdev/ResolveSpec/pkg/openapi"
    "github.com/bitechdev/ResolveSpec/pkg/restheadspec"
    "github.com/gorilla/mux"
)

func main() {
    // 1. Create handler
    handler := restheadspec.NewHandlerWithGORM(db)

    // 2. Register models
    handler.registry.RegisterModel("public.users", User{})
    handler.registry.RegisterModel("public.products", Product{})

    // 3. Configure OpenAPI generator
    handler.SetOpenAPIGenerator(func() (string, error) {
        generator := openapi.NewGenerator(openapi.GeneratorConfig{
            Title:       "My API",
            Description: "API documentation",
            Version:     "1.0.0",
            BaseURL:     "http://localhost:8080",
            Registry:    handler.registry.(*modelregistry.DefaultModelRegistry),
            IncludeRestheadSpec: true,
            IncludeResolveSpec:  false,
            IncludeFuncSpec:     false,
        })
        return generator.GenerateJSON()
    })

    // 4. Setup routes (automatically includes /openapi endpoint)
    router := mux.NewRouter()
    restheadspec.SetupMuxRoutes(router, handler, nil)

    // Start server
    http.ListenAndServe(":8080", router)
}
ResolveSpec Example
func main() {
    // 1. Create handler
    handler := resolvespec.NewHandlerWithGORM(db)

    // 2. Register models
    handler.RegisterModel("public", "users", User{})
    handler.RegisterModel("public", "products", Product{})

    // 3. Configure OpenAPI generator
    handler.SetOpenAPIGenerator(func() (string, error) {
        generator := openapi.NewGenerator(openapi.GeneratorConfig{
            Title:       "My API",
            Version:     "1.0.0",
            Registry:    handler.registry.(*modelregistry.DefaultModelRegistry),
            IncludeResolveSpec: true,
        })
        return generator.GenerateJSON()
    })

    // 4. Setup routes
    router := mux.NewRouter()
    resolvespec.SetupMuxRoutes(router, handler, nil)

    http.ListenAndServe(":8080", router)
}

Accessing the OpenAPI Specification

Once configured, the OpenAPI spec is available in two ways:

1. Global /openapi Endpoint
curl http://localhost:8080/openapi

Returns the complete OpenAPI specification for all registered models.

2. Query Parameter on Any Endpoint
# RestheadSpec
curl http://localhost:8080/public/users?openapi

# ResolveSpec
curl http://localhost:8080/resolve/public/users?openapi

Returns the same OpenAPI specification as /openapi.

Generated Endpoints

RestheadSpec

For each registered model (e.g., public.users), the following paths are generated:

  • GET /public/users - List records with header-based filtering
  • POST /public/users - Create a new record
  • GET /public/users/{id} - Get a single record
  • PUT /public/users/{id} - Update a record
  • PATCH /public/users/{id} - Partially update a record
  • DELETE /public/users/{id} - Delete a record
  • GET /public/users/metadata - Get table metadata
  • OPTIONS /public/users - CORS preflight
ResolveSpec

For each registered model (e.g., public.users), the following paths are generated:

  • POST /resolve/public/users - Execute operations (read, create, meta)
  • POST /resolve/public/users/{id} - Execute operations (update, delete)
  • GET /resolve/public/users - Get metadata
  • OPTIONS /resolve/public/users - CORS preflight

Schema Generation

The generator automatically extracts information from your Go struct tags:

type User struct {
    ID        int       `json:"id" gorm:"primaryKey" description:"User ID"`
    Name      string    `json:"name" gorm:"not null" description:"User's full name"`
    Email     string    `json:"email" gorm:"unique" description:"Email address"`
    CreatedAt time.Time `json:"created_at" description:"Creation timestamp"`
    Roles     []string  `json:"roles" description:"User roles"`
}

This generates an OpenAPI schema with:

  • Property names from json tags
  • Required fields from gorm:"not null" and non-pointer types
  • Descriptions from description tags
  • Proper type mappings (int → integer, time.Time → string with format: date-time, etc.)

RestheadSpec Headers

The generator documents all RestheadSpec HTTP headers:

  • X-Filters - JSON array of filter conditions
  • X-Columns - Comma-separated columns to select
  • X-Sort - JSON array of sort specifications
  • X-Limit - Maximum records to return
  • X-Offset - Records to skip
  • X-Preload - Relations to eager load
  • X-Expand - Relations to expand (LEFT JOIN)
  • X-Distinct - Enable DISTINCT queries
  • X-Response-Format - Response format (detail, simple, syncfusion)
  • X-Clean-JSON - Remove null/empty fields
  • X-Custom-SQL-Where - Custom WHERE clause (AND)
  • X-Custom-SQL-Or - Custom WHERE clause (OR)

ResolveSpec Request Body

The generator documents the ResolveSpec request body structure:

{
  "operation": "read",
  "data": {},
  "id": 123,
  "options": {
    "limit": 10,
    "offset": 0,
    "filters": [
      {"column": "status", "operator": "eq", "value": "active"}
    ],
    "sort": [
      {"column": "created_at", "direction": "desc"}
    ]
  }
}

Security Schemes

The generator automatically includes common security schemes:

  • BearerAuth: JWT Bearer token authentication
  • SessionToken: Session token in Authorization header
  • CookieAuth: Cookie-based session authentication
  • HeaderAuth: Header-based user authentication (X-User-ID)

FuncSpec Custom Endpoints

For FuncSpec, you can manually register custom SQL endpoints:

funcSpecEndpoints := map[string]openapi.FuncSpecEndpoint{
    "/api/reports/sales": {
        Path:        "/api/reports/sales",
        Method:      "GET",
        Summary:     "Get sales report",
        Description: "Returns sales data for specified date range",
        SQLQuery:    "SELECT * FROM sales WHERE date BETWEEN [start_date] AND [end_date]",
        Parameters:  []string{"start_date", "end_date"},
    },
}

generator := openapi.NewGenerator(openapi.GeneratorConfig{
    // ... other config
    IncludeFuncSpec:   true,
    FuncSpecEndpoints: funcSpecEndpoints,
})

Combining Multiple Frameworks

You can generate a unified OpenAPI spec that includes multiple frameworks:

generator := openapi.NewGenerator(openapi.GeneratorConfig{
    Title:       "Unified API",
    Version:     "1.0.0",
    Registry:    sharedRegistry,
    IncludeRestheadSpec: true,
    IncludeResolveSpec:  true,
    IncludeFuncSpec:     true,
    FuncSpecEndpoints:   funcSpecEndpoints,
})

This will generate a complete spec with all endpoints from all frameworks.

Advanced Customization

You can customize the generated spec further:

handler.SetOpenAPIGenerator(func() (string, error) {
    generator := openapi.NewGenerator(config)

    // Generate initial spec
    spec, err := generator.Generate()
    if err != nil {
        return "", err
    }

    // Add contact information
    spec.Info.Contact = &openapi.Contact{
        Name:  "API Support",
        Email: "support@example.com",
        URL:   "https://example.com/support",
    }

    // Add additional servers
    spec.Servers = append(spec.Servers, openapi.Server{
        URL:         "https://staging.example.com",
        Description: "Staging Server",
    })

    // Convert back to JSON
    data, _ := json.MarshalIndent(spec, "", "  ")
    return string(data), nil
})

Using with Swagger UI

You can serve the generated OpenAPI spec with Swagger UI:

  1. Get the spec from /openapi
  2. Load it in Swagger UI at https://petstore.swagger.io/
  3. Or self-host Swagger UI and point it to your /openapi endpoint

Example with self-hosted Swagger UI:

// Serve Swagger UI static files
router.PathPrefix("/swagger/").Handler(
    http.StripPrefix("/swagger/", http.FileServer(http.Dir("./swagger-ui"))),
)

// Configure Swagger UI to use /openapi

Testing

You can test the OpenAPI endpoint:

# Get the full spec
curl http://localhost:8080/openapi | jq

# Validate with openapi-generator
openapi-generator validate -i http://localhost:8080/openapi

# Generate client SDKs
openapi-generator generate -i http://localhost:8080/openapi -g typescript-fetch -o ./client

Complete Example

See example.go in this package for complete, runnable examples including:

  • Basic RestheadSpec setup
  • Basic ResolveSpec setup
  • Combining both frameworks
  • Adding FuncSpec endpoints
  • Advanced customization

License

Part of the ResolveSpec project.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExampleBothSpecs

func ExampleBothSpecs(db *gorm.DB)

ExampleBothSpecs shows how to combine both RestheadSpec and ResolveSpec

func ExampleCustomization

func ExampleCustomization()

ExampleCustomization shows advanced customization options

func ExampleResolveSpec

func ExampleResolveSpec(db *gorm.DB)

ExampleResolveSpec shows how to configure OpenAPI generation for ResolveSpec

func ExampleRestheadSpec

func ExampleRestheadSpec(db *gorm.DB)

ExampleRestheadSpec shows how to configure OpenAPI generation for RestheadSpec

func ExampleWithFuncSpec

func ExampleWithFuncSpec()

ExampleWithFuncSpec shows how to add FuncSpec endpoints to OpenAPI

Types

type Components

type Components struct {
	Schemas         map[string]Schema         `json:"schemas,omitempty"`
	SecuritySchemes map[string]SecurityScheme `json:"securitySchemes,omitempty"`
}

type Contact

type Contact struct {
	Name  string `json:"name,omitempty"`
	URL   string `json:"url,omitempty"`
	Email string `json:"email,omitempty"`
}

type FuncSpecEndpoint

type FuncSpecEndpoint struct {
	Path        string
	Method      string
	Summary     string
	Description string
	SQLQuery    string
	Parameters  []string // Parameter names extracted from SQL
}

FuncSpecEndpoint represents a FuncSpec endpoint for OpenAPI generation

type Generator

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

Generator creates OpenAPI specifications

func NewGenerator

func NewGenerator(config GeneratorConfig) *Generator

NewGenerator creates a new OpenAPI generator

func (*Generator) Generate

func (g *Generator) Generate() (*OpenAPISpec, error)

Generate creates the complete OpenAPI specification

func (*Generator) GenerateJSON

func (g *Generator) GenerateJSON() (string, error)

GenerateJSON generates OpenAPI spec as JSON string

type GeneratorConfig

type GeneratorConfig struct {
	Title               string
	Description         string
	Version             string
	BaseURL             string
	Registry            *modelregistry.DefaultModelRegistry
	IncludeRestheadSpec bool
	IncludeResolveSpec  bool
	IncludeFuncSpec     bool
	FuncSpecEndpoints   map[string]FuncSpecEndpoint // path -> endpoint info
}

GeneratorConfig holds configuration for OpenAPI spec generation

type Info

type Info struct {
	Title       string   `json:"title"`
	Description string   `json:"description,omitempty"`
	Version     string   `json:"version"`
	Contact     *Contact `json:"contact,omitempty"`
}

type MediaType

type MediaType struct {
	Schema  *Schema     `json:"schema,omitempty"`
	Example interface{} `json:"example,omitempty"`
}

type OpenAPISpec

type OpenAPISpec struct {
	OpenAPI    string                `json:"openapi"`
	Info       Info                  `json:"info"`
	Servers    []Server              `json:"servers,omitempty"`
	Paths      map[string]PathItem   `json:"paths"`
	Components Components            `json:"components"`
	Security   []map[string][]string `json:"security,omitempty"`
}

OpenAPISpec represents the OpenAPI 3.0 specification structure

type Operation

type Operation struct {
	Summary     string                `json:"summary,omitempty"`
	Description string                `json:"description,omitempty"`
	OperationID string                `json:"operationId,omitempty"`
	Tags        []string              `json:"tags,omitempty"`
	Parameters  []Parameter           `json:"parameters,omitempty"`
	RequestBody *RequestBody          `json:"requestBody,omitempty"`
	Responses   map[string]Response   `json:"responses"`
	Security    []map[string][]string `json:"security,omitempty"`
}

type Parameter

type Parameter struct {
	Name        string      `json:"name"`
	In          string      `json:"in"` // "query", "header", "path", "cookie"
	Description string      `json:"description,omitempty"`
	Required    bool        `json:"required,omitempty"`
	Schema      *Schema     `json:"schema,omitempty"`
	Example     interface{} `json:"example,omitempty"`
}

type PathItem

type PathItem struct {
	Get     *Operation `json:"get,omitempty"`
	Post    *Operation `json:"post,omitempty"`
	Put     *Operation `json:"put,omitempty"`
	Patch   *Operation `json:"patch,omitempty"`
	Delete  *Operation `json:"delete,omitempty"`
	Options *Operation `json:"options,omitempty"`
}

type RequestBody

type RequestBody struct {
	Description string               `json:"description,omitempty"`
	Required    bool                 `json:"required,omitempty"`
	Content     map[string]MediaType `json:"content"`
}

type Response

type Response struct {
	Description string               `json:"description"`
	Content     map[string]MediaType `json:"content,omitempty"`
}

type Schema

type Schema struct {
	Type                 string             `json:"type,omitempty"`
	Format               string             `json:"format,omitempty"`
	Description          string             `json:"description,omitempty"`
	Properties           map[string]*Schema `json:"properties,omitempty"`
	Items                *Schema            `json:"items,omitempty"`
	Required             []string           `json:"required,omitempty"`
	Ref                  string             `json:"$ref,omitempty"`
	Enum                 []interface{}      `json:"enum,omitempty"`
	Example              interface{}        `json:"example,omitempty"`
	AdditionalProperties interface{}        `json:"additionalProperties,omitempty"`
	OneOf                []*Schema          `json:"oneOf,omitempty"`
	AnyOf                []*Schema          `json:"anyOf,omitempty"`
}

type SecurityScheme

type SecurityScheme struct {
	Type         string `json:"type"` // "apiKey", "http", "oauth2", "openIdConnect"
	Description  string `json:"description,omitempty"`
	Name         string `json:"name,omitempty"`         // For apiKey
	In           string `json:"in,omitempty"`           // For apiKey: "query", "header", "cookie"
	Scheme       string `json:"scheme,omitempty"`       // For http: "basic", "bearer"
	BearerFormat string `json:"bearerFormat,omitempty"` // For http bearer
}

type Server

type Server struct {
	URL         string `json:"url"`
	Description string `json:"description,omitempty"`
}

Jump to

Keyboard shortcuts

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