DTO (Data Transfer Object)

ssh·2023년 12월 17일
0

dart

목록 보기
20/22

DTO

  • Json 데이터를 모델 클래스까지 전달하는 중간 단계 역할을 하는 객체다.
  • 프로세스 간 데이터를 전송하기 위해 생성되는 객체다.

사용이유

  • 메서드 호출을 줄이는 것이 주 목적이다.
  • Model Class 는 non-nullable 한 값만 가지고 있는 것이 좋다.
  • Json 데이터는 문서에 명시되어 있지 않더라도 null 값을 포함할 수 있다.
  • Map -> Model Class 변환시 null 값 등의 예외를 사전에 걸러내기 용이하다.
  • 불완전한 코드가 포함될 것 같다면 Dto를 도입한다.
  • Json 값에 예외가 없다면 반드시 Dto를 도입할 필요는 없다.
  • 중요한 정보를 노출시키지 않고 두 시스템(api와 서버 등) 간 통신을 원할하게 할 수 있다.
  • Dto는 json to dart 플러그인을 활용하여 nullable을 담도록 만든다.
  • Model class는 꼭 필요한 내용만 직접 JsonSerialization등의 라이브러리를 사용하여 만든다.
  • Dto to 모델 클래스가 되는 메서드를 작성하여 활용한다.
  • extension 등을 활용한다. (https://dart.dev/language/extension-methods)

사용방법

  • DTO에는 비즈니스 로직이 아닌 데이터만 저장해야 한다.
  • 또한 용량이 작은 단순한 환경으로, 한 가지 작업만 수행하는 것이어야 한다.
  • 효과적인 DTO는 다음과 같다.
    • 상용구 코드를 최소화한다.
      • 코드를 일일이 새로 작성하기 때문이다.
    • 작성이 용이하다.
      • DTO는 작성이 어려울 정도로 복잡해서는 안 된다.
        • 다만, 이러한 코드는 깨지기도 쉽다.
    • 읽을 수 있어야 한다.
      • 누구든지 코드 구문을 분석할 수 있어야 한다.

dto 적용단계

  1. Dto 작성 - json to dart 라이브러리로 변환
  2. 모델 클래스 작성 - jsonSerialization 등의 코드 제네레이션 라이브러리로 필요한 모델만 작성
  3. Mapper 작성 - extension을 활용하여 변환 메서드 작성

추천 폴더 구조

dto 코드

  • 코드

    import 'movie_dates.dart';
    import 'movie_result.dart';
    
    class MovieData {
      Dates dates;
      int page;
      List<MovieResult> results;
      int totalPages;
      int totalResults;
    
      MovieData({
        required this.dates,
        required this.page,
        required this.results,
        required this.totalPages,
        required this.totalResults,
      });
    
      factory MovieData.fromJson(Map<String, dynamic> json) {
        return MovieData(
          dates: Dates.fromJson(json['dates'] ?? {}),
          page: json['page'] ?? 0,
          results: (json['results'] != null
              ? List<MovieResult>.from(
                  json['results'].map((result) => MovieResult.fromJson(result)))
              : []),
          totalPages: json['total_pages'] ?? 0,
          totalResults: json['total_results'] ?? 0,
        );
      }
    
      Map<String, dynamic> toJson() {
        return {
          'dates': dates.toJson(),
          'page': page,
          'results': results.map((result) => result.toJson()).toList(),
          'total_pages': totalPages,
          'total_results': totalResults,
        };
      }
    }
    

api 코드

  • 통신 후 dto를 반환
    • 코드
      import 'dart:convert';
      import '../dto/movie_data.dart';
      import 'package:http/http.dart' as http;
      
      class MovieApi {
        Future<MovieData> fetchMovies({required String upcoming}) async {
          final response = await http.get(Uri.parse(upcoming));
      
          Map<String, dynamic> jsonData = jsonDecode(utf8.decode(response.bodyBytes));
          MovieData movieData = MovieData.fromJson(jsonData);
          return movieData;
        }
      }

model 코드

  • 필요한 내용만 간단히 구성
    • 코드
      class Movie {
        final int id;
        final String title;
        final String originalTitle;
        final String posterPath;
        final String overview;
        final String releaseDate;
        final double voteAverage;
      
        Movie({
          required this.id,
          required this.originalTitle,
          required this.overview,
          required this.posterPath,
          required this.releaseDate,
          required this.title,
          required this.voteAverage,
        });
      
        factory Movie.fromJson(Map<String, dynamic> json) {
          return Movie(
            id: json['id'],
            originalTitle: json['original_title'],
            overview: json['overview'],
            posterPath: json['poster_path'],
            releaseDate: json['release_date'],
            title: json['title'],
            voteAverage: json['vote_average'].toDouble(),
          );
        }
      
        Map<String, dynamic> toJson() {
          return {
            'id': id,
            'title': title,
            'originalTitle': originalTitle,
            'posterPath': posterPath,
            'overview': overview,
            'releaseDate': releaseDate,
            'voteAverage': voteAverage,
          };
        }
      
        factory Movie.fromMap(Map<String, dynamic> json) {
          return Movie(
            id: json['id'] as int,
            title: json['title'] as String,
            originalTitle: json['originalTitle'] as String,
            posterPath: json['posterPath'] as String,
            overview: json['overview'] as String,
            releaseDate: json['releaseDate'] as String,
            voteAverage: json['voteAverage'] as double,
          );
        }
      
        
        String toString() {
          return 'Movie{id: $id, title: $title, originalTitle: $originalTitle, posterPath: $posterPath, overview: $overview, releaseDate: $releaseDate, voteAverage: $voteAverage}';
        }
      }

Mapper 코드

  • dto를 model로 변환하는 유틸 메소드
  • Nullable을 non-Nullable로 변환이 핵심
  • 전체 반환이 아니라 필요한 부분만 반환
    • 코드
      import 'package:basic/23_12_15/dto/movie_result.dart';
      import '../model/movie.dart';
      
      extension ToMovie on MovieResult {
        Movie toMovie() {
          return Movie(
            id: id,
            originalTitle: originalTitle,
            overview: overview,
            posterPath: posterPath,
            releaseDate: releaseDate,
            title: title,
            voteAverage: voteAverage,
          );
        }
      }

main

  • 코드
    import 'dart:convert';
    
    import 'package:basic/23_12_15/data_source/movie_api.dart';
    import 'package:basic/23_12_15/dto/movie_data.dart';
    import 'package:basic/23_12_15/mapper/movie_mapper.dart';
    import 'model/movie.dart';
    
    void main() async {
      // api 통신
      final api = MovieApi();
    
      String url =
          'https://api.themoviedb.org/3/movie/upcoming?api_key=a64533e7ece6c72731da47c9c8bc691f&language=ko-KR&page=1';
    
      // json을 dto로
      final MovieData dto = await api.fetchMovies(upcoming: url);
      // print(dto);
      // print(jsonEncode(dto.toJson()));
      // dto에서 필요한 내용을 mapper를 통해 모델 클래스로 변환
      final List<Movie> movies = dto.results.map((e) => e.toMovie()).toList();
    
      print(movies.toString());
    }

0개의 댓글

관련 채용 정보