LogoSkills

openapi:mapper

Auto-generate OpenAPI Response to Domain Entity Mapper

항ëĒŠë‚´ėšŠ
Invoke/openapi:mapper
Aliases/mapper, /mapper:create
Categorygood-teacher-workflow
Complexitystandard

/openapi:mapper#

Context Framework Note: This behavioral instruction activates when Claude Code users type /openapi:mapper patterns.

Triggers#

  • When a Mapper to convert OpenAPI Response to Domain Entity is needed
  • When mapping logic for a new API endpoint is needed
  • When creating a Mapper before /feature:data

Context Trigger Pattern#

/openapi:mapper {feature_name} {response_type} {entity_type}

Parameters#

ParameterRequiredDescriptionExample
feature_name ✅ Feature module name (snake_case) classroom, student
response_type ✅ OpenAPI Response type name ClassResponse, StudentResponse
entity_type ✅ Domain Entity type name ClassroomClassInfo, StudentInfo

Behavioral Flow#

1. OpenAPI Response Analysis#

# Check Response type in OpenAPI package
find package/openapi -name  " *.dart "   | xargs grep -l  " {response_type} "

Analysis targets:

  • Response field list
  • Field types (nullable or not)
  • Nested object types

2. Domain Entity Analysis#

# Check Domain Entity
find feature -path  " */domain/entity/* "   -name  " *.dart "   | xargs grep -l  " {entity_type} "

Analysis targets:

  • Entity field list
  • Field types and defaults
  • Required/optional fields

3. Mapper Class Generation#

import 'package:core/core.dart';
import 'package:dependencies/dependencies.dart';
import 'package:openapi/api.dart';

/// Mapper that converts {Feature} API Response to Domain Entity
abstract final class {Feature}Mapper {
  /// Convert {Response}Response to {Entity}
  static {Entity} from{Response}Response({Response}Response response) {
    return {Entity}(
      // Required fields: null-safe conversion
      id: response.id?.toString() ?? '',
      name: response.name ?? '',

      // Date fields
      createdAt: response.createdAt ?? DateTime.now(),

      // Nested object fields
      teacher: response.teacher != null
          ? fromTeacherResponse(response.teacher!)
          : null,

      // List fields
      students: response.students
              ?.map(fromStudentResponse)
              .toList() ??
          [],

      // Enum fields
      status: _mapStatus(response.status),
    );
  }

  /// Convert {Response}Response list
  static List<{Entity}> from{Response}ResponseList(
    List<{Response}Response>? responses,
  ) {
    return responses?.map(from{Response}Response).toList() ?? [];
  }

  /// Convert nested object (TeacherResponse → TeacherInfo)
  static TeacherInfo fromTeacherResponse(TeacherResponse response) {
    return TeacherInfo(
      id: response.id?.toString() ?? '',
      name: response.name ?? '',
      // ...
    );
  }

  /// Enum conversion helper
  static {Entity}Status _mapStatus({Response}Status? status) {
    return switch (status) {
      {Response}Status.active => {Entity}Status.active,
      {Response}Status.inactive => {Entity}Status.inactive,
      _ => {Entity}Status.unknown,
    };
  }

  /// Convert API error to Failure
  static Failure mapException(Object error, StackTrace stackTrace) {
    Log.e('API Error: $error', stackTrace: stackTrace);
    if (error is DioException) {
      final statusCode = error.response?.statusCode;
      final message = error.message ?? 'Network error occurred';

      return switch (statusCode) {
        400 => ValidationFailure(message, error: error, stackTrace: stackTrace),
        401 => AuthFailure(message, error: error, stackTrace: stackTrace),
        403 => PermissionFailure(message, error: error, stackTrace: stackTrace),
        404 => NotFoundFailure(message, error: error, stackTrace: stackTrace),
        _ => NetworkFailure(message, error: error, stackTrace: stackTrace),
      };
    }
    return UnexpectedFailure(
      error.toString(),
      error: error is Exception ? error : null,
      stackTrace: stackTrace,
    );
  }
}

Output File#

feature/{location}/{feature_name}/lib/src/data/mappers/{feature}_mapper.dart

Mapping Rules#

Conversion Patterns by Field Type#

Response TypeEntity TypeConversion Pattern
int? String response.id?.toString() ?? ''
String?Stringresponse.name ?? ''
DateTime? DateTime response.createdAt ?? DateTime.now()
List<T>? List<T> responses?.map(fromT).toList() ?? []
Nested? Entity? response.nested != null ? fromNested(response.nested!) : null
Enum?Enum_mapEnum(response.status)

Null Safety Principles#

  1. Required fields: Provide default values

    id: response.id?.toString() ?? '',
    name: response.name ?? '',
    
  2. Optional fields: Keep nullable

    description: response.description,
    avatarUrl: response.avatarUrl,
    
  3. List fields: Default to empty list

    items: response.items?.map(fromItem).toList() ?? [],
    
  4. Date fields: Use current time or nullable

    createdAt: response.createdAt ?? DateTime.now(),
    updatedAt: response.updatedAt,  // When nullable allowed
    

Examples#

Classroom Mapper Generation#

/openapi:mapper classroom ClassResponse ClassroomClassInfo

Generated result:

abstract final class ClassroomMapper {
  static ClassroomClassInfo fromClassResponse(ClassResponse response) {
    return ClassroomClassInfo(
      classId: response.classId?.toString() ?? '',
      name: response.name ?? '',
      description: response.description ?? '',
      teacherId: response.teacherId?.toString() ?? '',
      joinCode: response.joinCode ?? '',
      memberCount: response.memberCount ?? 0,
      createdAt: response.createdAt ?? DateTime.now(),
    );
  }

  static Failure mapException(Object error, StackTrace stackTrace) { ... }
}

Student Mapper Generation#

/openapi:mapper student StudentResponse StudentInfo

Integration with /feature:data#

/openapi:mapper is used as a preprocessing step for /feature:data:

1. /openapi:mapper classroom ClassResponse ClassroomClassInfo
   → data/mappers/classroom_mapper.dart generated

2. /feature:data classroom ClassroomClassInfo
   → Repository, Mixin use ClassroomMapper

Checklist#

  • OpenAPI Response type analysis
  • Domain Entity type analysis
  • Field mapping table creation
  • Mapper class generation (abstract final class)
  • from{Response}Response() method implementation
  • from{Response}ResponseList() method implementation
  • Nested object conversion methods implementation
  • Enum conversion helper implementation
  • mapException() method implementation
  • Null-safe field mapping verification
  • Add export to data.dart

Reference Documents#

  • .claude/references/patterns/repository-patterns.md - Repository patterns
  • feature/application/classroom/lib/src/data/mappers/classroom_mapper.dart - Reference implementation