Files
Rogee 824861c27c feat: Refactor AST generation routes workflow
- Introduced a comprehensive data model for route definitions, parameters, and validation rules.
- Established component interfaces for route parsing, comment parsing, import resolution, route building, validation, and rendering.
- Developed a detailed implementation plan outlining execution flow, user requirements, and compliance with design principles.
- Created a quickstart guide to assist users in utilizing the refactored system effectively.
- Conducted thorough research on existing architecture, identifying key improvements and establishing a refactoring strategy.
- Specified functional requirements and user scenarios to ensure clarity and testability.
- Generated a task list for implementation, emphasizing test-driven development and parallel execution where applicable.
2025-09-22 11:33:13 +08:00

7.4 KiB

Phase 1: Quickstart Guide

Overview

This quickstart guide demonstrates how to use the refactored AST route generation system. It covers the basic workflow for defining routes and generating route handler code.

Prerequisites

  • Go 1.21 or higher
  • Existing atomctl project structure
  • Basic understanding of Go annotations

Basic Route Definition

1. Simple Route

Create a controller with basic route annotation:

// app/http/user_controller.go
package http

// @Router /users [get]
type UserController struct {}

Generate routes:

atomctl gen route

2. Route with Parameters

Add parameter bindings using @Bind annotations:

// app/http/user_controller.go
package http

// @Router /users/:id [get]
// @Bind id (path) model()
// @Bind limit (query) model(limit:int)
type UserController struct {}

Parameter Binding Types

Path Parameters

// @Bind id (path) model()
// @Bind name (path) model(name:string)

Query Parameters

// @Bind limit (query) model(limit:int)
// @Bind offset (query) model(offset:int)
// @Bind filter (query)

Body Parameters

// @Bind user (body) model(User)
// @Bind data (body) model(CreateUserRequest)

Header Parameters

// @Bind authorization (header)
// @Bind x-api-key (header) model(APIKey)

Generated Code Structure

The route generation will create a routes.gen.go file:

// app/http/routes.gen.go
package http

import (
    "context"
    "net/http"

    "go.ipao.vip/atom/contracts"
    "go.ipao.vip/atom/http"
    "go.ipao.vip/gen/model"
)

type RouteProvider struct {
    userController *UserController
}

func (p *RouteProvider) Provide(opts ...contracts.Option) error {
    // Route registration logic here
    p.userController = &UserController{}

    // Register /users route
    http.Handle("/users", p.userController.GetUsers)

    return nil
}

// UserController method stubs
func (c *UserController) GetUsers(ctx context.Context, w http.ResponseWriter, r *http.Request) {
    // Generated method implementation
}

Testing Your Routes

1. Unit Test

// app/http/user_controller_test.go
package http

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stretchr/testify/assert"
)

func TestUserController_GetUsers(t *testing.T) {
    controller := &UserController{}

    req := httptest.NewRequest("GET", "/users", nil)
    w := httptest.NewRecorder()

    controller.GetUsers(context.Background(), w, req)

    assert.Equal(t, http.StatusOK, w.Code)
}

2. Integration Test

// integration/user_routes_test.go
package integration

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stretchr/testify/assert"
)

func TestUserRoutes(t *testing.T) {
    // Setup router with generated routes
    router := setupRouter()

    tests := []struct {
        name       string
        path       string
        method     string
        wantStatus int
    }{
        {"Get Users", "/users", "GET", http.StatusOK},
        {"Get User by ID", "/users/123", "GET", http.StatusOK},
        {"Create User", "/users", "POST", http.StatusCreated},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            req := httptest.NewRequest(tt.method, tt.path, nil)
            w := httptest.NewRecorder()

            router.ServeHTTP(w, req)

            assert.Equal(t, tt.wantStatus, w.Code)
        })
    }
}

Advanced Features

1. Route Groups

// @Router /api/v1/users [get]
// @Router /api/v1/users/:id [get,put,delete]
type UserController struct {}

2. Middleware Integration

// @Router /admin [get]
// @Middleware auth,admin
type AdminController struct {}

3. Custom Return Types

// @Router /users [post]
// @ReturnType UserResponse
type UserController struct {}

Configuration Options

Parser Configuration

config := &route.RouteParserConfig{
    StrictMode:      true,
    ParseComments:   true,
    SourceLocations: true,
    EnableValidation: true,
}

Builder Configuration

config := &route.BuilderConfig{
    EnableValidation:          true,
    StrictMode:                true,
    DefaultParamPosition:      route.ParamPositionQuery,
    AutoGenerateReturnTypes:  true,
    ResolveImportDependencies: true,
}

Error Handling

1. Validation Errors

The refactored system provides detailed error messages:

$ atomctl gen route
Error: invalid route syntax in user_controller.go:15
  Expected: @Router /path [method]
  Found:    @Router /users
  Fix: Add HTTP methods in brackets

2. Parameter Binding Errors

$ atomctl gen route
Error: invalid parameter binding in user_controller.go:16
  Parameter 'id' has invalid position 'invalid'
  Valid positions: path, query, body, header, cookie, local, file

Migration from Legacy System

1. Existing Code Compatibility

The refactored system maintains full backward compatibility:

// This still works
// @Router /users [get]
// @Bind id (path) model()
type UserController struct {}

2. Gradual Migration

You can migrate files incrementally:

# Generate routes for specific files
atomctl gen route app/http/user_controller.go

# Or generate for entire directory
atomctl gen route app/http/

Performance Considerations

1. Caching

The refactored system includes caching for improved performance:

config := &route.RouteParserConfig{
    CacheEnabled: true,
}

2. Parallel Processing

Enable parallel processing for large projects:

config := &route.RouteParserConfig{
    ParallelProcessing: true,
}

Debugging and Diagnostics

1. Enable Detailed Logging

config := &route.RouteParserConfig{
    SourceLocations: true,
}

2. Access Diagnostics

parser := route.NewRouteParser()
routes, err := parser.ParseFile("controller.go")

// Get detailed diagnostics
diagnostics := parser.GetDiagnostics()
for _, diag := range diagnostics {
    fmt.Printf("%s: %s (%s:%d)\n", diag.Level, diag.Message, diag.File, diag.Location.Line)
}

Best Practices

1. Route Definition

  • Use descriptive route names
  • Group related routes together
  • Follow REST conventions where applicable

2. Parameter Binding

  • Use appropriate parameter positions
  • Provide clear parameter names
  • Add validation for complex parameters

3. Error Handling

  • Implement proper error handling in controllers
  • Use appropriate HTTP status codes
  • Provide meaningful error messages

4. Testing

  • Write comprehensive tests for all routes
  • Test both success and error scenarios
  • Use contract tests for consistency

Troubleshooting

Common Issues

  1. Routes not generated: Check file naming and location
  2. Parameters not parsed: Verify annotation syntax
  3. Import errors: Ensure all dependencies are available
  4. Compilation errors: Check generated code syntax

Getting Help

  • Review the contract tests in contracts/ directory
  • Check the diagnostic output for detailed error information
  • Run tests to verify implementation correctness

Next Steps

  1. Define your routes using @Router and @Bind annotations
  2. Run atomctl gen route to generate route code
  3. Implement the generated controller methods
  4. Write tests to verify functionality
  5. Configure options as needed for your project

The refactored system provides a solid foundation for route generation with improved maintainability, testability, and extensibility.