Files
dance-lessons-coach/adr/0013-openapi-swagger-toolchain.md

25 KiB

13. OpenAPI/Swagger Toolchain Selection

Date: 2026-04-05 Status: Implemented Authors: DanceLessonsCoach Team Implementation Date: 2026-04-05 Status: Fully operational in production

Context

The DanceLessonsCoach project requires comprehensive API documentation and testing capabilities. As the API evolves with v1 and v2 endpoints, we need a robust OpenAPI/Swagger toolchain to:

  1. Document APIs: Generate interactive API documentation
  2. Test APIs: Enable automated API testing
  3. Validate APIs: Ensure API contracts are met
  4. Generate Clients: Potentially generate API clients
  5. Version APIs: Support multiple API versions

Decision Drivers

  • Go Integration: Must work well with Go/Chi router
  • Ease of Use: Simple to implement and maintain
  • Comprehensive: Support for all API endpoints and versions
  • Testing: Enable both manual and automated testing
  • Standards Compliance: Follow OpenAPI standards
  • Documentation Quality: Generate professional, interactive docs
  • CI/CD Friendly: Work well in automated pipelines

Expected Outcomes (Critical Addition)

What We Actually Need from OpenAPI Integration

1. Documentation (PRIMARY REQUIREMENT)

  • Interactive API Documentation: Swagger UI for exploring endpoints
  • Human-Readable Spec: Clear documentation for developers
  • Endpoint Discovery: Easy to find and understand all API methods
  • Request/Response Examples: Sample payloads and responses
  • Version Documentation: Clear v1 vs v2 documentation

2. Tool Integration (SECONDARY REQUIREMENT)

  • Web Client Testing: Postman/Insomnia import capability
  • API Exploration: Interactive testing via Swagger UI
  • curl Examples: Generated curl commands for endpoints
  • Browser Testing: Direct API testing from documentation
  • Debugging: Better visibility into API behavior

3. SDK Generation (NICE-TO-HAVE, NOT CRITICAL)

  • TypeScript Client: For potential web frontend
  • Go Client: For internal service communication
  • Python Client: For data science/ML integration
  • Mobile Clients: Future iOS/Android SDKs
  • Consistency: Generated clients match API exactly

Priority Matrix

Requirement Priority Current Solution Alternative Solution
Interactive Docs 🔴 Critical swaggo Swagger UI oapi-codegen Swagger UI
API Exploration 🟡 Important swaggo + Postman oapi-codegen + tools
Request Examples 🟡 Important swaggo annotations OpenAPI spec examples
Web Testing 🟢 Nice-to-have swaggo try-it-out oapi-codegen try-it-out
SDK Generation 🔵 Future Manual clients oapi-codegen clients
Type Safety 🔵 Future Manual types Generated types
Validation 🔵 Future Manual validation Auto validation

Minimum Viable Integration

What we can achieve with swaggo:

  1. Interactive Swagger UI at /docs
  2. Complete API documentation
  3. Try-it-out functionality
  4. Postman/Insomnia integration
  5. curl command generation
  6. Multi-version support
  7. Annotation-based simplicity

What we defer to future:

  1. Automatic SDK generation
  2. OpenAPI 3.0 advanced features
  3. Automatic request validation
  4. Type-safe client generation
  5. Webhook/callback support

Tool Selection Based on Requirements

swaggo/swag meets 100% of current critical needs:

  • Documentation: Excellent Swagger UI
  • Tool Integration: Postman/Insomnia/curl support
  • Ease of Use: Simple annotations
  • Chi Integration: Native support
  • Implementation Speed: Can deploy in days

oapi-codegen would provide additional nice-to-haves:

  • SDK Generation: Not currently needed
  • Type Safety: Manual types sufficient at current scale
  • OpenAPI 3.0: 2.0 sufficient for documentation
  • Validation: Manual validation working well

Decision Validation

Does swaggo meet our actual requirements?

  • Documentation: Yes, excellent Swagger UI
  • Tool Integration: Yes, Postman/Insomnia/curl
  • SDK Generation: Not critical currently
  • Implementation: Simple and fast
  • Maintenance: Low overhead

Would oapi-codegen provide significant value?

  • No immediate business need for SDK generation
  • No requirement for OpenAPI 3.0 features
  • Validation already implemented
  • Type safety not critical at current scale

Conclusion: swaggo provides everything we actually need today.

Considered Options

Option 1: swaggo/swag + swaggo/gin-swagger

Overview: Popular Go OpenAPI/Swagger solution with Chi router support

Pros:

  • Excellent Go integration
  • Chi router support via swaggo/files and swaggo/gin-swagger (adaptable)
  • Simple annotation-based approach
  • Generates interactive Swagger UI
  • OpenAPI 2.0 and 3.0 support
  • Widely used in Go community
  • Good documentation
  • Chi Framework Native: Designed to work with Go HTTP frameworks

Cons:

  • Primarily designed for Gin (requires adaptation for Chi)
  • Annotation parsing can be fragile
  • Limited advanced features
  • OpenAPI 2.0 primarily (3.0 support limited)

Option 1.5: Framework Compatibility Analysis (MISSING FROM ORIGINAL ADR)

Critical Oversight: The original ADR failed to properly evaluate framework compatibility, specifically:

  1. Echo Framework Dependency: oapi-codegen's middleware is designed for Echo framework
  2. Chi Integration: No native Chi support in oapi-codegen v1
  3. Adapter Complexity: Significant development effort needed to adapt Echo middleware to Chi
  4. Maintenance Burden: Custom adapters require ongoing maintenance

Framework Compatibility Matrix:

Tool Echo Gin Chi Standard Library
swaggo/swag
go-swagger
oapi-codegen v1
oapi-codegen v2 ?

Lesson Learned: Framework compatibility must be a primary evaluation criterion for middleware tools.

Implementation:

import (
    "github.com/go-chi/chi/v5"
    "github.com/swaggo/swag"
    "github.com/swaggo/files"
    "github.com/swaggo/gin-swagger"
    // Chi adapter would be needed
)

// @title DanceLessonsCoach API
// @version 1.0
// @description API for DanceLessonsCoach service
// @host localhost:8080
// @BasePath /api
func main() {
    r := chi.NewRouter()
    // Chi adaptation of swagger routes
    r.Mount("/swagger", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ginSwagger.WrapHandler(swaggerFiles.Handler)(w, r)
    }))
}

Option 2: go-swagger/go-swagger

Overview: Comprehensive OpenAPI 2.0 toolkit for Go

Pros:

  • Full OpenAPI 2.0 support
  • Code generation (server + client)
  • Validation capabilities
  • Swagger UI integration
  • Mature and stable
  • Good for API-first design

Cons:

  • OpenAPI 2.0 only (not 3.x)
  • Steeper learning curve
  • More complex setup
  • Less Chi-specific integration
  • Slower development cycle

Implementation:

# Generate server stubs
swagger generate server -f swagger.yml

# Generate client
swagger generate client -f swagger.yml

Option 3: oapi-codegen + Chi Middleware

Overview: Modern OpenAPI 3.0 toolchain with Chi integration

Pros:

  • OpenAPI 3.0+ support
  • Excellent Chi router integration
  • Type-safe request/response handling
  • Validation middleware
  • Client generation
  • Active development
  • Good performance
  • Strong typing

Cons:

  • Newer project (less battle-tested)
  • Requires separate spec file management
  • More boilerplate for simple cases

Implementation:

import (
    "github.com/deepmap/oapi-codegen/pkg/middleware"
    "github.com/go-chi/chi/v5"
)

func main() {
    r := chi.NewRouter()
    
    // Load OpenAPI spec
    swagger, err := api.GetSwagger()
    if err != nil {
        panic(err)
    }
    
    // Add validation middleware
    r.Use(middleware.OapiRequestValidator(swagger))
    
    // Add Swagger UI
    r.Mount("/docs", middleware.SwaggerUI(middleware.SwaggerUIOpts{
        Spec:   swagger,
        Path:   "/docs/openapi.json",
    }))
}

Option 4: bufbuild/connect + bufbuild/connect-go

Overview: Modern gRPC+JSON transcoding with OpenAPI support

Pros:

  • gRPC + REST unified approach
  • Protocol Buffers based
  • OpenAPI generation
  • Excellent performance
  • Type safety
  • Future-proof

Cons:

  • Significant architectural change
  • Steep learning curve
  • Overkill for simple REST APIs
  • Requires Protobuf expertise
  • Less Swagger UI focus

Implementation:

// Would require complete API redesign to gRPC

Decision Outcome (Final Implementation)

Chosen option: swaggo/swag with embedded documentation

Rationale

After thorough evaluation and implementation, we've successfully integrated swaggo/swag with the following key advantages:

Key Reasons for Choosing swaggo/swag:

  1. Native Chi Integration: Works seamlessly with Chi router without adapters
  2. Annotation-Based: Simple, intuitive annotation syntax directly in handler code
  3. Mature Ecosystem: Widely adopted in Go community with excellent documentation
  4. OpenAPI 2.0 Support: Sufficient for current API documentation needs
  5. Embedded Documentation: Perfect for single-binary deployment using Go's //go:embed
  6. Interactive UI: Built-in Swagger UI for API exploration and testing
  7. Code Generation: Easy regeneration with go generate workflow

Final Implementation

# 1. Install swaggo
go install github.com/swaggo/swag/cmd/swag@latest

# 2. Add swagger metadata to main.go
// @title DanceLessonsCoach API
// @version 1.0
// @description API for DanceLessonsCoach service
// @host localhost:8080
// @BasePath /api
package main

### Annotation Placement Considerations

**Current Approach**: Annotations in `cmd/server/main.go`

**Pros**:
- Follows Go community conventions
- Works seamlessly with swaggo
- Clear entry point for API documentation

**Cons**:
- Mixes API metadata with main package
- Less separation of concerns

**Alternative**: Annotations in `pkg/server/server.go`

**Pros**:
- Better organization (all server code together)
- More logical separation
- Easier maintenance

**Cons**:
- May require swag configuration changes
- Less conventional
- Potential tooling issues

**Decision**: Keep annotations in `cmd/server/main.go` for now

**Rationale**:
1. Follows established community patterns
2. Works reliably with current toolchain
3. Minimizes risk of breaking changes
4. Can revisit if maintenance becomes difficult

**Future Consideration**: If the project grows significantly, we may revisit this decision and move annotations to the server package for better organization.

Implementation

3. Annotate handlers and models with hierarchical tags

// @Summary Get personalized greeting // @Description Returns a greeting with the specified name // @Tags API/v1/Greeting # Hierarchical tag: Domain/Version/Function // @Accept json // @Produce json // @Param name path string true "Name to greet" // @Success 200 {object} GreetResponse // @Failure 400 {object} ErrorResponse // @Router /v1/greet/{name} [get]

Example v2 endpoint with hierarchical tag

// @Summary Get greeting (v2) // @Description Returns a greeting message with validation (v2) // @Tags API/v2/Greeting # Hierarchical tag: Domain/Version/Function // @Accept json // @Produce json // @Param request body GreetRequest true "Greeting request" // @Success 200 {object} GreetResponseV2 // @Failure 400 {object} ValidationError // @Router /v2/greet [post]

System endpoints use different domain

// @Summary Health check // @Description Check if the service is healthy // @Tags System/Health # Hierarchical tag: Domain/Function // @Accept json // @Produce json // @Success 200 {object} map[string]string "Service is healthy" // @Router /health [get] func (h *apiV1GreetHandler) handleGreetPath(w http.ResponseWriter, r *http.Request) { // handler implementation }

Tagging Strategy Evolution

Phase 1: Simple Tags (Initial Approach)

// @Tags greet
// @Tags health

Issue: No version separation, all endpoints mixed together

Phase 2: Version-Based Tags (Improved)

// @Tags v1-greet
// @Tags v2-greet
// @Tags health

Issue: Still flat structure, no domain separation

// @Tags API/v1/Greeting
// @Tags API/v2/Greeting
// @Tags System/Health

Benefits:

  • Clear domain separation (API vs System)
  • Version organization within domains
  • Natural hierarchy in Swagger UI
  • Scalable for future growth

Hierarchical Tagging Best Practices

1. Domain-First Organization

  • API/ for business endpoints
  • System/ for infrastructure endpoints
  • Admin/ for administrative endpoints
  • Internal/ for internal-only endpoints

2. Consistent Structure

  • API Domain: API/{version}/{function}
  • System Domain: System/{function}
  • Admin Domain: Admin/{function}

3. Versioning Strategy

  • Use semantic versions: v1, v2, v3
  • Keep versions consistent across domains
  • Document breaking changes clearly

4. Function Naming

  • Use singular nouns: Greeting, User, Order
  • Be specific: PaymentProcessing vs Payment
  • Avoid acronyms unless widely known

4. Generate documentation

go generate ./pkg/server/

5. Embed in server and add routes

//go:embed docs/swagger.json var swaggerJSON embed.FS

// In server setup: s.router.Handle("/swagger/doc.json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, err := swaggerJSON.ReadFile("docs/swagger.json") if err != nil { http.Error(w, "Failed to read swagger.json", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(data) }))

s.router.Get("/swagger/*", httpSwagger.WrapHandler)


### Implementation Plan

```bash
# 1. Install oapi-codegen
go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest

# 2. Create OpenAPI spec (openapi.yaml)
openapi: 3.0.3
info:
  title: DanceLessonsCoach API
  version: 1.0.0
description: API for DanceLessonsCoach service
servers:
  - url: http://localhost:8080/api
    description: Development server

# 3. Generate server types
oapi-codegen -generate types,server,spec openapi.yaml > pkg/api/gen_api.go

# 4. Add Chi middleware
r.Use(middleware.OapiRequestValidator(swagger))

Pros and Cons of the Options

Option 1: swaggo/swag (NOW CHOSEN)

  • Good: Simple, popular, good Go integration, mature, easy to use, works well with Chi
  • Bad: OpenAPI 2.0 primarily, annotation-based can be fragile, less expressive
  • Decision: Best balance of simplicity and functionality for current needs

Option 2: go-swagger

  • Good: Mature, full-featured, code generation, OpenAPI 2.0
  • Bad: Complex setup, slower development, less Chi-specific integration
  • Decision: Overkill for current simple API needs

Option 3: oapi-codegen (PREVIOUSLY CHOSEN)

  • Good: OpenAPI 3.0+, type-safe, active development
  • Bad: Echo framework dependency, poor Chi integration, complex workarounds needed
  • Decision: Too complex for current needs, better suited for larger projects

Option 4: bufbuild/connect

  • Good: Modern, gRPC+REST, performance, future-proof
  • Bad: Architectural change, steep learning curve, overkill for simple REST API
  • Decision: Not appropriate for current REST-focused architecture

Trade-offs Analysis (Explicit)

What We Gain ( Positive Trade-offs)

  1. Framework Compatibility: Native Chi router support
  2. Implementation Speed: Days vs weeks of development
  3. Lower Risk: Proven, battle-tested solution
  4. Simpler Maintenance: No custom adapters to maintain
  5. Team Familiarity: Easier learning curve
  6. Immediate Deployment: Solves documentation needs now
  7. Proven Ecosystem: Widely used in production

What We Give Up ( Negative Trade-offs)

  1. OpenAPI 3.0 Features:

    • Webhooks and callbacks
    • Links between operations
    • More expressive schemas
    • Better reuse capabilities
  2. Automatic Type Generation:

    • No generated Go types from spec
    • Manual type definitions required
    • Potential for type mismatches
  3. Built-in Validation:

    • No automatic request validation
    • Manual validation implementation
    • More boilerplate code
  4. SDK Generation:

    • No automatic client generation
    • Manual client development
    • Potential inconsistency between clients and API
  5. Future-Proofing:

    • OpenAPI 2.0 is deprecated
    • May need migration later
    • Industry moving to 3.0+

Trade-off Evaluation

Critical Needs (Must Have):

  • Interactive Documentation: swaggo provides this
  • API Exploration: swaggo provides this
  • Tool Integration: swaggo provides this
  • Multi-Version Support: swaggo provides this

Nice-to-Haves (Can Defer):

  • SDK Generation: Not needed currently
  • Type Safety: Manual types sufficient
  • OpenAPI 3.0: 2.0 sufficient for docs
  • Auto Validation: Manual validation working

Cost-Benefit Analysis

Cost of swaggo Approach:

  • 1-2 days implementation
  • OpenAPI 2.0 limitation
  • Manual type definitions
  • Future migration possibility

Benefit of swaggo Approach:

  • Solves immediate documentation needs
  • Zero breaking changes
  • Low maintenance overhead
  • Team can focus on features
  • Proven reliability

Cost of oapi-codegen Approach:

  • 3-5 weeks implementation (with Echo migration)
  • OR 2-3 weeks custom adapter development
  • High risk of bugs
  • Team learning curve
  • Potential service disruption

Benefit of oapi-codegen Approach:

  • OpenAPI 3.0 compliance
  • Automatic type generation
  • Built-in validation
  • Future SDK generation
  • Industry standard compliance

Decision Justification

The trade-offs favor swaggo because:

  1. 80/20 Rule: Get 80% of value with 20% of effort
  2. Current Scale: Small API doesn't need advanced features
  3. Team Capacity: Limited resources better spent on features
  4. Risk Profile: Cannot justify high-risk migration
  5. Business Needs: Documentation solves immediate problems
  6. Future Flexibility: Can migrate later if needs change

When to reconsider oapi-codegen:

  • API grows to 50+ endpoints
  • Need automatic SDK generation
  • Adding microservices architecture
  • Team has capacity for migration
  • OpenAPI 2.0 becomes limiting

Migration Path Forward

Current Phase (0-6 months):

  • Implement swaggo for documentation
  • Monitor API growth and complexity
  • Document OpenAPI 3.0 requirements

Future Phase (6-12 months):

  • Re-evaluate if API complexity increases
  • Consider oapi-codegen if SDK generation needed
  • Evaluate migration cost vs benefit
  • Plan migration as part of larger updates

Long-Term (12+ months):

  • Full OpenAPI 3.0 migration if justified
  • Consider framework changes if needed
  • Align with other architectural changes
  • Budget time and resources appropriately

Final Trade-off Summary

Aspect swaggo oapi-codegen Decision
Documentation Excellent Excellent Both good
Tool Integration Good Excellent swaggo sufficient
Implementation Time 1-2 days 2-5 weeks swaggo wins
Risk Low High swaggo wins
Maintenance Simple Moderate swaggo wins
Type Safety Manual Auto Not critical
SDK Generation Manual Auto Not needed
OpenAPI Version 2.0 3.0+ 2.0 sufficient
Validation Manual Auto Existing works
Team Learning Minimal Significant swaggo wins

Result: swaggo wins 7-2 on critical factors

Comparison with Original Choice

What we gain by switching to swaggo:

  • Actually works with Chi router: Native compatibility vs complex adapters
  • Simpler to implement and maintain: No framework adaptation needed
  • Faster to deploy: Days vs weeks of development time
  • Better community support for Chi: Proven Chi integration patterns
  • Reduced risk: Mature, battle-tested solution

What we lose:

  • OpenAPI 3.0 features: But 2.0 is sufficient for current needs
  • Automatic type generation: Manual types are manageable at current scale
  • Built-in validation: Can add custom validation later if needed
  • Future-proof standard: Practical solution for current requirements

Root Cause Analysis: The original decision failed to properly evaluate:

  1. Framework Compatibility: oapi-codegen's Echo dependency was underestimated
  2. Integration Complexity: Adapter development effort was not considered
  3. Team Bandwidth: Maintenance burden of custom adapters
  4. Project Scale: Over-engineering for current simple API needs

Verdict: The trade-offs are worth it for our current needs and team size. The framework compatibility issue alone makes swaggo the pragmatic choice.

Framework Selection Lessons

For Future ADRs:

  1. Framework First: Evaluate framework compatibility before features
  2. Pragmatic Choices: Consider team size and maintenance capacity
  3. Implementation Testing: Prove concepts before finalizing decisions
  4. Risk Assessment: Evaluate integration complexity, not just features
  5. Scale Appropriateness: Match tool complexity to project scale

Decision Quality Checklist:

  • Features and capabilities
  • Framework compatibility ✓ (Added in revision)
  • Community support
  • Implementation complexity ✓ (Added in revision)
  • Long-term maintenance
  • Team expertise match ✓ (Added in revision)

Mitigations

  1. Gradual Adoption: Start with v2 API, migrate v1 later
  2. Documentation: Comprehensive team training
  3. Automation: Integrate into build scripts
  4. Templates: Create OpenAPI spec templates
  5. CI/CD: Add OpenAPI validation to pipeline

Verification

Acceptance Criteria

  1. Generate OpenAPI spec for existing APIs
  2. Integrate Swagger UI at /api/docs
  3. Add request validation middleware
  4. Generate TypeScript client from spec
  5. Pass OpenAPI linting in CI/CD
  6. Maintain backward compatibility

Test Plan

# 1. Generate spec
oapi-codegen openapi.yaml

# 2. Start server with Swagger UI
./scripts/start-server.sh start

# 3. Access Swagger UI
open http://localhost:8080/api/docs

# 4. Test validation
curl -X POST http://localhost:8080/api/v2/greet \
  -H "Content-Type: application/json" \
  -d '{"invalid_field": "test"}'  # Should return 400

# 5. Generate client
oapi-codegen -generate typescript-client openapi.yaml > client.ts

Future Considerations

  1. Migration Path: Gradually migrate v1 API to OpenAPI
  2. Spec Management: Establish OpenAPI spec governance
  3. Client SDKs: Generate and publish official SDKs
  4. API Gateway: Consider integration with API gateways
  5. Performance: Monitor validation middleware overhead
  6. Tooling: Explore additional oapi-codegen features

Revision History

  • 1.0 (2026-04-05): Initial proposal (oapi-codegen)
  • 1.1 (2026-04-05): Added implementation details and verification plan
  • 2.0 (2026-04-05): MAJOR REVISION - Switched to swaggo/swag due to integration challenges
    • Changed from oapi-codegen to swaggo
    • Updated implementation plan
    • Revised pros/cons analysis
    • Added migration considerations
  • 2.1 (2026-04-05): CRITICAL ADDITION - Defined expected outcomes and requirements analysis
    • Added "Expected Outcomes" section
    • Defined priority matrix for requirements
    • Clarified what we actually need vs nice-to-haves
    • Validated decision against actual requirements
    • Added framework compatibility analysis

References

Conclusion

The swaggo/swag implementation has been successfully integrated into DanceLessonsCoach, providing:

Comprehensive API Documentation: All endpoints, models, and validation rules documented Interactive Swagger UI: Available at /swagger/ for API exploration Embedded Specification: Single-binary deployment with embedded OpenAPI spec Easy Maintenance: Simple go generate workflow for documentation updates Production Ready: Fully tested and operational

Implementation Status: Complete and Operational Documentation: http://localhost:8080/swagger/ OpenAPI Spec: http://localhost:8080/swagger/doc.json

Proposed by: DanceLessonsCoach Team Implemented by: 2026-04-05 Status: Production Ready