Files
dance-lessons-coach/adr/0013-openapi-swagger-toolchain.md
Gabriel Radureau 52065c9cf3
Some checks failed
CI/CD Pipeline / Build Docker Cache (push) Successful in 10s
CI/CD Pipeline / CI Pipeline (push) Failing after 13s
refactor: convert all DanceLessonsCoach mentions to kebab-case
2026-04-07 19:11:39 +02:00

32 KiB

13. OpenAPI/Swagger Toolchain Selection

Date: 2026-04-05 Status: Partially Implemented (Documentation only) Authors: Arcodange Team Implementation Date: 2026-04-05 Last Updated: 2026-04-05 Status: OpenAPI documentation operational, SDK generation deferred

Context

The dance-lessons-coach 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 dance-lessons-coach API
// @version 1.0
// @description API for dance-lessons-coach 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

Implementation Reality vs Original Plan

Original Decision: oapi-codegen + Chi Middleware Actual Implementation: swaggo/swag with embedded documentation

Why We Changed

  1. Framework Compatibility: swaggo works natively with Chi
  2. Implementation Speed: Days vs weeks of development
  3. Lower Risk: Proven, battle-tested solution
  4. Current Needs: Documentation without SDK generation
  5. Team Capacity: Limited resources for complex integration

What We Actually Need

Documentation: Interactive Swagger UI for API exploration Tool Integration: Postman/Insomnia/curl support API Exploration: Try-it-out functionality Multi-Version Support: Clear v1 vs v2 documentation

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

Final Implementation

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

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

Swag Formatting Integration

To ensure consistent swagger comment formatting, we've integrated swag fmt into our workflow:

Git Hooks

Added to .git/hooks/pre-commit:

# Run swag fmt to format swagger comments
echo "Running swag fmt..."
if command -v swag >/dev/null 2>&1; then
    swag fmt
    if [ $? -ne 0 ]; then
        echo "ERROR: swag fmt failed"
        exit 1
    fi
else
    echo "swag not installed, skipping swag fmt"
fi

CI/CD Integration

Added to .gitea/workflows/go-ci-cd.yaml lint-format job:

- name: Install swag
  run: go install github.com/swaggo/swag/cmd/swag@latest

- name: Run swag fmt
  run: swag fmt

Benefits

  • Consistent Formatting: Automatic formatting of swagger comments
  • Pre-Commit Validation: Catches issues before commit
  • CI/CD Enforcement: Ensures formatting in all pull requests
  • Team Consistency: Everyone follows the same rules
  • Automatic Fixes: Issues are fixed automatically

Usage

# Format swagger comments manually
swag fmt

# Format is automatically run in:
# - pre-commit hook
# - CI/CD lint-format job

=======

Final Implementation

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

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

Swag Formatting Integration

To ensure consistent swagger comment formatting, we've integrated swag fmt into our workflow:

Git Hooks

Added to .git/hooks/pre-commit:

# Run swag fmt to format swagger comments
echo "Running swag fmt..."
if command -v swag >/dev/null 2>&1; then
    swag fmt
    if [ $? -ne 0 ]; then
        echo "ERROR: swag fmt failed"
        exit 1
    fi
else
    echo "swag not installed, skipping swag fmt"
fi

CI/CD Integration

Added to .gitea/workflows/go-ci-cd.yaml lint-format job:

- name: Install swag
  run: go install github.com/swaggo/swag/cmd/swag@latest

- name: Run swag fmt
  run: swag fmt

Benefits

  • Consistent Formatting: Automatic formatting of swagger comments
  • Pre-Commit Validation: Catches issues before commit
  • CI/CD Enforcement: Ensures formatting in all pull requests
  • Team Consistency: Everyone follows the same rules
  • Automatic Fixes: Issues are fixed automatically

Usage

# Format swagger comments manually
swag fmt

# Format is automatically run in:
# - pre-commit hook
# - CI/CD lint-format job

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.

What We Actually Implemented

# 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]

# 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)

What We Did NOT Implement (From Original Plan)

# NOT IMPLEMENTED: oapi-codegen approach
# 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: dance-lessons-coach API
#   version: 1.0.0

# 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))

### 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)
```go
// @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: dance-lessons-coach API
  version: 1.0.0
description: API for dance-lessons-coach 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

What We Actually Implemented

OpenAPI Documentation: Comprehensive API documentation with swaggo/swag Interactive Swagger UI: Available at /swagger/ for API exploration Embedded Specification: Single-binary deployment with embedded OpenAPI spec Hierarchical Tagging: Clear organization with Domain/Version/Function tags Production Ready: Fully tested and operational

What We Did NOT Implement (From Original Plan)

oapi-codegen: Using swaggo instead due to Chi compatibility SDK Generation: No generated Go/TypeScript/Python clients OpenAPI 3.0: Using OpenAPI 2.0 (sufficient for current needs) Auto Validation: Manual validation working well Type Safety: Manual types sufficient at current scale

Why This is the Right Approach

  1. Framework Compatibility: swaggo works natively with Chi router
  2. Implementation Speed: Days vs weeks of development
  3. Lower Risk: Proven, battle-tested solution
  4. Current Needs: Documentation without SDK generation
  5. Team Capacity: Limited resources for complex integration

Future Migration Path

If we need SDK generation in the future:

  1. Add oapi-codegen alongside swaggo (not instead of)
  2. Generate SDKs from OpenAPI spec
  3. Add SDK-based testing
  4. Implement request validation middleware
  5. Migrate to OpenAPI 3.0 if needed

Current Status: Partially Implemented (Documentation only) Implementation: swaggo/swag with embedded documentation Documentation: http://localhost:8080/swagger/ OpenAPI Spec: http://localhost:8080/swagger/doc.json Swagger UI: http://localhost:8080/swagger/index.html

Proposed by: Arcodange Team Implemented by: 2026-04-05 Last Updated: 2026-04-05 Status: Production Ready for Current Documentation Needs

Note: This ADR has been updated to reflect the actual implementation (swaggo/swag) rather than the originally proposed approach (oapi-codegen). The change was made due to framework compatibility issues and pragmatic considerations for the project's current scale and needs.