--- name: kratos-mapper description: Generates bidirectional mapper functions (transformers/converters/adapters) between protobuf DTOs and business domain models for go-kratos services. Creates type-safe conversions with proper field mapping, handles timestamps, enums, optional fields, and pagination metadata transformations. Use when converting DTOs to domain models, transforming proto to biz models, mapping requests/responses, implementing type conversions, creating entity transformers, or handling DTO transformations between layers. tags: [kratos, mapper, dto, converter, transformer, proto, domain-model, type-conversion] keywords: [mapper, convert, transform, DTO, proto to domain, domain to proto, type conversion, request mapping, response mapping, transformer, converter, adapter] version: 2.0.0 last_updated: 2026-01-12 --- Generate mapper functions that convert between protobuf DTOs (requests/responses) and business domain models, ensuring type safety and proper field transformations. For an entity, create mappers in `internal/service/mapper.go`: ```go // Request → Business Model func {Entity}FromCreateRequest(req *pb.Create{Entity}Request) *domain.{Entity} { return &domain.{Entity}{ Name: req.Name, // Map fields... } } // Business Model → Proto Response func toProto{Entity}(e *domain.{Entity}) *pb.{Entity} { return &pb.{Entity}{ Id: e.ID, Name: e.Name, // Map fields... } } **Import**: `import "{service}/internal/biz/domain"` ``` ## Common Mapper Patterns **Request to Business Model**: ```go func {Entity}FromCreateRequest(req *pb.Create{Entity}Request) *domain.{Entity} func {Entity}FromUpdateRequest(req *pb.Update{Entity}Request, id uint64) *domain.{Entity} ``` **Business Model to Proto**: ```go func toProto{Entity}(e *domain.{Entity}) *pb.{Entity} func toProto{Entities}(list []*domain.{Entity}) []*pb.{Entity} ``` **List Options**: ```go func NewList{Entities}Options(req *pb.List{Entities}Request) *domain.List{Entities}Options { return &domain.List{Entities}Options{ Pagination: pagination.OffsetPaginationParams{ Offset: req.Offset, Limit: req.Limit, }, } } ``` **Pagination Meta**: ```go func toProtoPaginationMeta(meta *pagination.PaginationMeta) *pb.PaginationMeta { return &pb.PaginationMeta{ Total: meta.Total, Offset: meta.Offset, Limit: meta.Limit, } } ``` ## Naming Rules **Proto → Business**: `{Entity}From{Operation}Request` - Example: `SymbolFromCreateRequest`, `ProductFromUpdateRequest` **Business → Proto**: `toProto{Entity}` or `toProto{Entities}` - Example: `toProtoSymbol`, `toProtoSymbols` **Options**: `NewList{Entities}Options` **Helpers**: `toProto{Type}` for common types - Example: `toProtoPaginationMeta`, `toProtoTimestamp` ## Common Type Conversions **IDs**: `uint64` ↔ `uint64` (direct) **Strings**: `string` ↔ `string` (direct) **Timestamps**: `time.Time` ↔ `*timestamppb.Timestamp` ```go CreatedAt: timestamppb.New(e.CreatedAt) ``` **Optional Fields**: Use pointers ```go // Business has *string, proto has string Email: func() string { if e.Email != nil { return *e.Email } return "" }() ``` **Enums**: Map string to proto enum ```go Status: pb.Status(pb.Status_value[e.Status]) ``` ## Where to Put Mappers **Single entity**: `internal/service/mapper.go` (all mappers) **Multiple entities**: `internal/service/{entity}_mapper.go` (per entity) Keep mapper functions close to service handlers for easy reference. Mapper functions are correct when: - [ ] Naming follows conventions ({Entity}From* vs toProto*) - [ ] All proto fields mapped to business model fields - [ ] Type conversions handled (timestamps, optionals, enums) - [ ] Nil checks for optional/pointer fields - [ ] List mappers use range loops - [ ] Pagination helpers created if needed - [ ] Functions are pure (no side effects)