# Serializers Service Kind

## Overview

Serializers are entity-specific services responsible for converting domain model entities into JSON format for API responses. They provide standardized JSON serialization with proper field mapping, type conversion, and support for both individual entities and entity collections.

## Architecture

### Core Components

**JSON Utilities Library** (`src/lib/to_json/`)
- Field-specific JSON encoding functions for different data types
- Proper JSON key formatting and value marshaling
- Type-safe conversion utilities for common field types

**Entity-Specific Serializers** (`src/srv/serializers/`)
- Each domain model has its own dedicated serializer (e.g., `GardenSerializer`, `UserSerializer`)
- All serializers follow the same interface pattern and method conventions
- Manual field-by-field serialization for precise control over JSON output

### Key Components

#### Field Type Functions
The `to_json` library provides type-specific field encoding:
- `StringField(name, value)`: String field encoding
- `IntegerField(name, value)`: Integer field encoding
- `BooleanField(name, value)`: Boolean field encoding
- `TimeField(name, value)`: Time/date field encoding
- `DecimalField(name, value)`: Floating-point field encoding
- `JsonField(name, value)`: Raw JSON field embedding
- `StructField(name, value)`: Complex struct field encoding

## Standard Methods

Every entity serializer implements these standard methods:

### Single Entity Serialization
```go
OneToJson(entity) (json.RawMessage, error)
```
- Serialize individual entity to JSON format
- Returns `json.RawMessage` for efficient JSON handling
- Handles all entity fields with appropriate type conversion

### Collection Serialization
```go
SetToJson(entities) (json.RawMessage, error)
```
- Serialize array of entities to JSON array format
- Efficiently processes multiple entities
- Maintains proper JSON array structure

## Usage Examples

### Single Entity Serialization
```go
garden := &mdl.Garden{
    Id: "123",
    Name: "My Garden",
    Picture: "garden.jpg",
}

jsonData, err := gardenSerializer.OneToJson(garden)
if err != nil {
    return err
}
// Returns: {"id":"123","name":"My Garden","picture":"garden.jpg",...}
```

### Collection Serialization
```go
gardens := []*mdl.Garden{garden1, garden2, garden3}

jsonData, err := gardenSerializer.SetToJson(gardens)
if err != nil {
    return err
}
// Returns: [{"id":"123",...},{"id":"456",...},{"id":"789",...}]
```

### API Response Integration
```go
// In JSON view or API handler
gardens, err := fetcher.FindAll(ctx, nil)
if err != nil {
    return err
}

jsonResponse, err := gardenSerializer.SetToJson(gardens)
if err != nil {
    return err
}

// Send jsonResponse as HTTP response
```

## JSON Field Construction

Serializers manually construct JSON fields for precise control:

### Field Assembly Pattern
```go
func (this *GardenSerializer) OneToJson(garden *mdl.Garden) (json.RawMessage, error) {
    var fields []string
    var field string

    field, _ = to_json.StringField("id", garden.Id)
    fields = append(fields, field)

    field, _ = to_json.TimeField("created_at", garden.CreatedAt)
    fields = append(fields, field)

    field, _ = to_json.StringField("name", garden.Name)
    fields = append(fields, field)

    return json.RawMessage("{" + strings.Join(fields, ",") + "}"), nil
}
```

### Type-Specific Field Handling
- **String fields**: Direct string encoding with proper escaping
- **Time fields**: ISO 8601 timestamp formatting
- **Integer/Boolean fields**: Native JSON type conversion
- **Complex fields**: Struct serialization with nested JSON

## Collection Processing

Collection serialization efficiently handles entity arrays:

### Individual Processing
```go
func (this *GardenSerializer) SetToJson(gardens []*mdl.Garden) (json.RawMessage, error) {
    var jsonStrings []string

    for _, garden := range gardens {
        j, err := this.OneToJson(garden)
        if err != nil {
            return json.RawMessage(""), err
        }
        jsonStrings = append(jsonStrings, string(j))
    }

    return json.RawMessage("[" + strings.Join(jsonStrings, ",") + "]"), nil
}
```

## JSON Output Characteristics

### Field Naming
- Uses snake_case field names for JSON keys (`"created_at"`, `"updated_at"`)
- Matches REST API conventions and database column naming
- Consistent naming across all entity serializers

### Type Conversion
- **Time fields**: Serialized as ISO 8601 timestamps
- **String fields**: Proper JSON string escaping
- **Numeric fields**: Native JSON number representation
- **Boolean fields**: Native JSON boolean values

### Output Format
- **Single entity**: JSON object `{"field1":"value1","field2":"value2"}`
- **Entity collection**: JSON array `[{...},{...},{...}]`
- **Empty collection**: Empty JSON array `[]`

## Integration with Framework

### With JSON Views
```go
// In JSON view services
jsonData, err := serializer.SetToJson(entities)
return jsonData  // Direct HTTP response
```

### With API Handlers
```go
// In API endpoint handlers
entities, err := fetcher.FindPage(ctx, mod)
jsonResponse, err := serializer.SetToJson(entities)
// Return as API response
```

## Error Handling

- Field encoding errors are propagated up the call stack
- Failed individual entity serialization fails entire collection
- JSON marshaling errors are returned with empty `json.RawMessage`
- Type conversion errors handled by `to_json` utility functions

## Performance Considerations

- **Manual field assembly**: More control but potentially slower than reflection-based approaches
- **String building**: Efficient string concatenation for JSON construction
- **Memory efficiency**: Direct `json.RawMessage` usage avoids intermediate copies
- **Error short-circuiting**: Early return on first serialization error