seong

Riverpod 기본 세팅 및 테스트 코드 작성 본문

Flutter/Flutter

Riverpod 기본 세팅 및 테스트 코드 작성

hyeonseong 2022. 12. 7. 09:23

1. Rivepod 사용 위한 의존성 추가 

  flutter_riverpod: ^2.0.0-dev.9
  http: ^0.13.5
  http_parser: ^4.0.1

 

2. main에 ProviderScope, Key셋팅

navigatorKey는 해당 페이지의 정보를 찾기 위함.

 

3. DB와 API통신을 위한 HttpConnector 작성

비동기(async)로 실행한 이유
Flutter은 기본적으로 단일 스레드 이기 때문에 한가지의 작업만 수행이 가능하다. 
동기적 실행을 하게 되면 DB와 통신을 실행하면 응답을 받기 전까지 아무것도 수행을 하지 않기 때문에 
비동기로 실행한다. Future 타입으로 준다는 것은 일단 null 박스를 주고 나중에 응답이 완료되면 값을 돌려준다.
final httpConnector = Provider<HttpConnector>((ref) {
  return HttpConnector();
});

class HttpConnector {
// header에 content 타입 필요
  Map<String, String> headers = {
    "Content-Type": "application/json;charset=utf-8"
  }; 

  final host = "http://localhost:8000";
  final Client _client = Client();

  Future<Response> get(String path) async {
    Uri uri = Uri.parse("${host}${path}");
    Response response = await _client.get(uri);
    return response;
  }

  Future<Response> post(String path, String body) async {
    Uri uri = Uri.parse("${host}${path}");
    Response response = await _client.post(uri, body: body, headers: headers);
    return response;
  }

  Future<Response> delete(String path) async {
    Uri uri = Uri.parse("${host}${path}");
    Response response = await _client.delete(uri, headers: headers);
    return response;
  }

  Future<Response> put(String path, String body) async {
    Uri uri = Uri.parse("${host}${path}");
    Response response = await _client.put(uri, body: body, headers: headers);
    return response;
  }
}

 

4. Model Class 작성 

플러터는 자동으로 메세지 컨버팅기능을 해주지 않기 때문에 직접 Json으로 변경해준다.

그리고 카테고리는 Nested Structure 구조이다. category 부분은 json data에서 List타입이기 때문에

map으로 한번에 처리를 해주어야한다.

class UserReqDto {
  String username;
  String password;
  String email;
  String phoneNum;
  String role;
  List<Category> category;

  UserReqDto(
      {required this.username, required this.password, required this.email, required this.phoneNum, required this.role, required this.category});

  // json -> dynamic
  factory UserReqDto.fromJson(Map<String, dynamic> json) => UserReqDto(
      username: json["username"],
      password: json["password"],
      email: json["email"],
      phoneNum: json["phoneNum"],
      role: json["role"],
      category: json["category"]);

// dynamic -> json
  Map<String, dynamic> toJson() => {
        "username": username,
        "password": password,
        "email": email,
        "phoneNum": phoneNum,
        "role": role,
        "category": category.map((e) => e.toJson()).toList(), // list타입이기 때문에 한번에 처리
      };
}

 

요청 이후 응답을 확인할 데이터가 필요하다.

기본 규약인 http의 규약으로 받아도 되지만 서버에서서 결과값을 좀 더 내가 보기편하게 작성하기 위해서 생성

성공 실패 코드는 ResponseEntity로 200이 뜨면 성공으로 한다.(이 부분은 이후 if문으로 로직에서 처리)

class ResponseDto<T> {
  String msg;
  T data;

  ResponseDto({required this.msg, required this.data});

  factory ResponseDto.fromJson(Map<String, dynamic> json) => ResponseDto(
        msg: json["msg"],
        data: json["data"],
      );
  Map<String, dynamic> toJson() => {"msg": msg, "data": data};
}

 

5. DB와 직접적 통신을 담당할 Provider( Repository 역할)작성

final userHttpRepository = Provider<UserHttpRepository>((ref) {
  return UserHttpRepository(ref);
});

class UserHttpRepository {
  Ref _ref;
  UserHttpRepository(this._ref);

// 회원가입
  Future<ResponseDto> join(UserReqDto userReqDto) async {
    String body = jsonEncode(userReqDto.toJson()); // 값을 json으로 body에 담아서 전달
    Response resp = await _ref.read(httpConnector).post("/api/join", body);
    ResponseDto respDto = ResponseDto.fromJson(jsonDecode(resp.body));

    return respDto;
  }
}

 

6. pageStore의 상태 값을 확인 할 Provider( Controller 역할 ) 작성

/**
 * Controller은 비즈니스 로직을 담당
 * Page에서 컨트롤러 사용위한 싱글톤 Provider 사용
 * Page가 Controller만 리스닝함.
 */
final userController = Provider<UserController>((ref) {
  final userHttpRepositoryPS = ref.read(userHttpRepository); // 컨트롤러 + Repository
  return UserController(ref);
});

class UserController {
  final context = navigatorKey.currentContext!; // 모든 컨트롤러가 필요 왜? 어떤 페이지인지 알아야하기 때문
  final Ref _ref;
  UserController(this._ref);

  void join(UserReqDto userReqDto) async {
    ResponseDto respDto = await _ref.read(userHttpRepository).join(userReqDto);
  }
}

 

7. pageStore 작성

회원가입을 테스트해볼 예정


회원가입 테스트 

파싱하고 body값 확인하면 아래 처럼 category도 List로 제대로 나온다.