Repository라는 이름을 붙이는 이유는 데이터 접근 계층을 나타내기 위해서이다다.
주요 목적은?
Repository는 API, 데이터베이스, 로컬 파일, 캐시(데이터 소스) 등에서 데이터를 동일한 인터페이스를 통해 접근할 수 있도록 해준다. 즉, 특정 데이터 소스에 종속되지 않고 일관된 방식으로 데이터를 사용할 수 있게 설계할 수 있다.
의존성 역전 원칙(Dependency Inversion Principle)을 실현 - DIP
상위 레벨의 비즈니스 로직(서비스 계층)이 하위 레벨의 데이터 접근 세부사항(API, 데이터베이스 등)에 직접적으로 의존하지 않고 Repository 인터페이스에 의존하게 된다.
단일 책임 원칙(SRP)
Repository는 데이터를 가져오거나 저장하는 하나의 책임만 가집니다. 명확한 역할과 책임을 가짐.
repository/post_repository.dart
import '../models/post.dart';
abstract class PostRepository {
// 모든 게시글 목록을 가져온다.
Future<List<Post>> fetchPosts();
// 새로운 게시글을 생성한다.
Future<Post> createPost(Post post);
// 기본 게시글을 수정한다.
Future<Post> updatePost(Post post);
// 특정 게시글을 삭제한다. 게시글 PK
Future<void> deletePost(int id);
// 특정 게시글 하나를 요청한다. 게시글 PK
Future<Post> fetchPostById(int id);
// ...
}
repository/post_repository_impl.dart
import 'package:class_riverpod_mvvm/models/post.dart';
import 'package:class_riverpod_mvvm/repository/post_repository.dart';
import 'package:dio/dio.dart';
class PostRepositoryImpl implements PostRepository {
final Dio _dio;
// dio 을 가져올 때 우리가 사용할 수 있는 방법은
// 1. 생상자 주입을 통한 - 의존성을 수동으로 관리
// 2. 리버팟을 활용한 관리 - x
PostRepositoryImpl(this._dio);
@override
Future<Post> createPost(Post post) async {
// 통신 관련 코드는 무조건 예외 처리 코드 습관화
try {
final response = await _dio.post(
'/posts',
data: post.toJson(),
);
if (response.statusCode == 201 || response.statusCode == 200) {
return Post.fromJson(response.data);
} else {
throw Exception('게시글 생성 실패');
}
} catch (e) {
throw Exception('게시글 생성 중 오류 발생 : $e');
}
}
@override
Future<void> deletePost(int id) async {
try {
final response = await _dio.delete('/posts/${id}');
if (response.statusCode != 200) {
throw Exception('게시글 삭제 실패');
}
} catch (e) {
throw Exception('게시글 삭제 중 오류 발생 : $e');
}
}
@override
Future<Post> fetchPostById(int id) async {
try {
final response = await _dio.get('/posts/$id');
if(response.statusCode == 200) {
return Post.fromJson(response.data);
} else {
throw Exception('게시글 불러 오기 실패');
}
} catch(e) {
throw Exception('게시글 불러 오는 중 오류 발생 : $e');
}
}
@override
Future<List<Post>> fetchPosts() async {
try {
final response = await _dio.get('/posts');
if(response.statusCode == 200) {
// [ '{userId : 홍길동, id: 1 ...}' , '' , '' , '' ]
List<dynamic> data = response.data;
// [ 'Post(,,,)' , 'Post(,,,)' , 'Post(,,,)' , 'Post(,,,)' ]
return data.map((json) => Post.fromJson(json)).toList();
} else {
throw Exception('게시글 불러 오기 실패');
}
} catch(e) {
throw Exception('게시글 불러 오는 중 오류 발생 : $e');
}
}
@override
Future<Post> updatePost(Post post) async {
try {
final response = await _dio.put(
'/posts/${post.id}',
data: post.toJson(),
);
if (response.statusCode == 201 || response.statusCode == 200) {
return Post.fromJson(response.data);
} else {
throw Exception('게시글 수정 실패');
}
} catch (e) {
throw Exception('게시글 수정 중 오류 발생 : $e');
}
}
}
728x90
'Flutter' 카테고리의 다른 글
riverpod 과 MVVM 활용 - 화면의 데이터(상태)를 관리하는 PostListViewModel 을 먼저 만들어 보자(6) (0) | 2024.11.21 |
---|---|
riverpod 과 MVVM 활용 - PostRespository를 중앙에서(컨테이너) 관리하는 Provider 계열을 만들어 보자(5) (0) | 2024.11.20 |
riverpod 과 MVVM 활용 - API에서 사용할 데이터 구조를 정의하기 위해 Post 클래스를 만들어 보자.(모델링 작업)(3) (0) | 2024.11.19 |
riverpod 과 MVVM 활용 - Http 통신 클라이언트 Dio 객체를 만들어 보자(2) (0) | 2024.11.19 |
riverpod 과 MVVM 활용 - 플러터 프로젝트 생성(1) (0) | 2024.11.19 |