Documentation

Request Lifecycle

Overview

Understanding how requests flow through the framework is crucial for both debugging and development. This document traces the complete lifecycle of HTTP requests from arrival to response.

Request Flow Architecture

HTTP Request
     ↓
Gin Router (Middleware Stack)
     ↓
Route Handler
     ↓
Controller Method
     ↓
Binder (Form/JSON extraction)
     ↓
Mae (Business Logic)
     ↓
Services (Fetchers, Handlers, etc.)
     ↓
Database Operations
     ↓
Response Formation (View/JSON)
     ↓
HTTP Response

Detailed Request Lifecycle

1. HTTP Request Arrival

// Gin receives the HTTP request
// Example: POST /gardens

2. Middleware Processing

// Middleware stack executes in order
router.Use(middleware.Recovery())
router.Use(middleware.Logger())
router.Use(middleware.CORS())
router.Use(middleware.Authentication())

3. Route Matching

// Route resolution based on method and path
gardens.POST("/", gardenController.Create)
gardens.GET("/:id", gardenController.Show)
gardens.PUT("/:id", gardenController.Update)

4. Controller Execution

func (this *GardenController) Create(c *gin.Context) {
    // Extract and bind form data
    form := &forms.CreateGardenForm{}
    if err := this.GardenBinder.BindCreateForm(c, form); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    // Execute business logic
    output, err := this.CreateGardenMae.Execute(c.Request.Context(), &maes.CreateGardenMaeInput{
        Form:   form,
        UserId: this.getCurrentUserId(c),
    })

    if err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    // Format response
    c.JSON(201, gin.H{
        "garden": output.Garden,
        "success": true,
    })
}

5. Mae Business Logic

func (this *CreateGardenMae) Execute(ctx context.Context, input *CreateGardenMaeInput) (*CreateGardenMaeOutput, error) {
    // Step 1: Validate
    if err := this.validateInput(input); err != nil {
        return nil, err
    }

    // Step 2: Transform
    garden := &mdl.Garden{}
    garden, _ = this.GardenMolder.ToEntity(input.Form, garden)

    // Step 3: Persist
    createdGarden, err := this.GardenHandler.Create(ctx, garden, nil)
    if err != nil {
        return nil, err
    }

    return &CreateGardenMaeOutput{Garden: createdGarden}, nil
}

6. Service Layer Operations

// Handler creates the entity
func (this *GardenHandler) Create(ctx context.Context, entity *mdl.Garden, mod *handler.HandlerMod) (*mdl.Garden, error) {
    // Set timestamps
    entity.CreatedAt = this.Time.Now()
    entity.UpdatedAt = this.Time.Now()

    // Use Table service for database operation
    values := this.GardenTable.EntityToValues(entity)
    id, _, err := this.Handler.Create(ctx, mod.Tx, this.GardenTable.TableName(), this.GardenTable.Columns(), values)
    if err != nil {
        return nil, err
    }

    entity.Id = id
    return entity, nil
}

7. Database Operations

// SQL execution through SqlDb abstraction
func (this *SqlDb) Create(ctx context.Context, tx *sql.Tx, table string, columns []string, values []interface{}) (string, int, error) {
    query := this.buildInsertQuery(table, columns)

    var result sql.Result
    var err error

    if tx != nil {
        result, err = tx.ExecContext(ctx, query, values...)
    } else {
        result, err = this.db.ExecContext(ctx, query, values...)
    }

    if err != nil {
        return "", 0, err
    }

    // Return generated ID
    id, _ := result.LastInsertId()
    return fmt.Sprintf("%d", id), 1, nil
}

8. Response Formation

// Controller formats final response
c.JSON(201, gin.H{
    "garden": output.Garden,
    "success": true,
})

// Or for HTML responses
c.HTML(200, "gardens/show.html", gin.H{
    "garden": garden,
    "title":  "Garden Details",
})

Request Types and Patterns

CRUD Operations

Create Request Flow

POST /gardens
├── GardenController.Create
├── CreateGardenMae.Execute
├── GardenHandler.Create
├── GardenTable.EntityToValues
└── SqlDb.Create → Database

Read Request Flow

GET /gardens/123
├── GardenController.Show
├── GardenFetcher.FindOneById
├── GardenTable.EsoToEntity
├── GardenHydrator.OneViaPreset (optional)
└── Response (JSON/HTML)

Update Request Flow

PUT /gardens/123
├── GardenController.Update
├── UpdateGardenMae.Execute
├── GardenMolder.ToEntity (change detection)
├── GardenHandler.UpdateFields
├── GardenTable.EntityToValues
└── SqlDb.Update → Database

Delete Request Flow

DELETE /gardens/123
├── GardenController.Delete
├── DeleteGardenMae.Execute
├── GardenFetcher.FindOneById (verify exists)
├── GardenHandler.Delete
└── SqlDb.Delete → Database

List/Search Operations

GET /gardens?search=tomato&page=2
├── GardenController.List
├── GardenBinder.BindListParams
├── GardenFetcher.FindPage (with filters)
├── GardenHydrator.ManyViaPreset
├── GardenSerializer.SetToJson
└── JSON Response with pagination

Context Propagation

Request Context Flow

// Context flows through entire request
func (this *GardenController) Create(c *gin.Context) {
    ctx := c.Request.Context()  // Extract request context

    // Pass to Mae
    output, err := this.CreateGardenMae.Execute(ctx, input)
}

func (this *CreateGardenMae) Execute(ctx context.Context, input *CreateGardenMaeInput) {
    // Pass to services
    garden, err := this.GardenHandler.Create(ctx, entity, nil)
}

func (this *GardenHandler) Create(ctx context.Context, entity *mdl.Garden, mod *handler.HandlerMod) {
    // Pass to database
    id, _, err := this.Handler.Create(ctx, mod.Tx, table, columns, values)
}

Context Values

// Adding values to context
func (this *AuthMiddleware) Authenticate(c *gin.Context) {
    user := this.validateToken(c.GetHeader("Authorization"))

    // Add user to context
    ctx := context.WithValue(c.Request.Context(), "user", user)
    c.Request = c.Request.WithContext(ctx)

    c.Next()
}

// Retrieving from context
func (this *GardenController) getCurrentUser(c *gin.Context) *mdl.User {
    user, _ := c.Request.Context().Value("user").(*mdl.User)
    return user
}

Error Handling Through Lifecycle

Error Propagation

// Errors bubble up through layers
Database Error
     
Service Error (with context)
     
Mae Error (with business context)
     
Controller Error Handling
     
HTTP Error Response

Error Response Formation

func (this *GardenController) Create(c *gin.Context) {
    output, err := this.CreateGardenMae.Execute(c.Request.Context(), input)
    if err != nil {
        // Determine error type and appropriate response
        switch e := err.(type) {
        case *ValidationError:
            c.JSON(400, gin.H{
                "error": e.Message,
                "field": e.Field,
            })
        case *BusinessRuleError:
            c.JSON(422, gin.H{
                "error": e.Message,
                "code":  e.Code,
            })
        default:
            c.JSON(500, gin.H{
                "error": "Internal server error",
            })
        }
        return
    }

    c.JSON(201, gin.H{"garden": output.Garden})
}

Transaction Lifecycle

Transaction Boundaries

func (this *ComplexGardenMae) Execute(ctx context.Context, input *ComplexGardenMaeInput) (*ComplexGardenMaeOutput, error) {
    // Begin transaction
    tx, err := this.SqlDb.Begin(ctx)
    if err != nil {
        return nil, err
    }
    defer tx.Rollback() // Auto-rollback if not committed

    // All operations use the same transaction
    handlerMod := &handler.HandlerMod{Tx: tx}

    // Create garden
    garden, err := this.GardenHandler.Create(ctx, gardenEntity, handlerMod)
    if err != nil {
        return nil, err
    }

    // Create related plants
    for _, plant := range input.Plants {
        plant.GardenId = garden.Id
        _, err := this.PlantHandler.Create(ctx, plant, handlerMod)
        if err != nil {
            return nil, err
        }
    }

    // Commit transaction
    if err := tx.Commit(); err != nil {
        return nil, err
    }

    return &ComplexGardenMaeOutput{Garden: garden}, nil
}

Performance Monitoring Points

Request Timing

func (this *GardenController) Create(c *gin.Context) {
    start := time.Now()
    defer func() {
        duration := time.Since(start)
        this.Metrics.RecordRequestDuration("POST", "/gardens", duration)
    }()

    // ... request processing
}

Service Operation Timing

func (this *GardenHandler) Create(ctx context.Context, entity *mdl.Garden, mod *handler.HandlerMod) (*mdl.Garden, error) {
    this.Spy.LogOperation(ctx, "GardenHandler.Create", map[string]interface{}{
        "garden_name": entity.Name,
        "user_id":     entity.UserId,
    })

    // ... implementation
}

Request Lifecycle Debugging

Tracing Requests

// Add request ID to context
func (this *TracingMiddleware) AddRequestID(c *gin.Context) {
    requestId := uuid.New().String()
    ctx := context.WithValue(c.Request.Context(), "request_id", requestId)
    c.Request = c.Request.WithContext(ctx)
    c.Header("X-Request-ID", requestId)
    c.Next()
}

// Log with request ID
func (this *Logger) LogWithContext(ctx context.Context, level, message string, fields ...interface{}) {
    requestId, _ := ctx.Value("request_id").(string)
    this.Log(level, message, append(fields, "request_id", requestId)...)
}

Request State Inspection

// Middleware for request state logging
func (this *DebugMiddleware) LogRequestState(c *gin.Context) {
    if this.Config.Environment == "dev" {
        this.Logger.Debug("Request received",
            "method", c.Request.Method,
            "path", c.Request.URL.Path,
            "headers", c.Request.Header,
        )
    }

    c.Next()

    if this.Config.Environment == "dev" {
        this.Logger.Debug("Response sent",
            "status", c.Writer.Status(),
            "size", c.Writer.Size(),
        )
    }
}

LLM Request Lifecycle Notes

When debugging or developing: 1. Request Context - Always propagate context through all layers 2. Error Handling - Handle errors at appropriate levels with context 3. Transaction Management - Use transactions for multi-entity operations 4. Performance Monitoring - Add timing and logging at key points 5. Debugging - Use middleware for request tracing and state inspection 6. Service Integration - Understand the flow through Mae → Services → Database 7. Response Formation - Handle both success and error cases consistently