플러터 프로젝트

[3화] 공통 네트워크 통신 모듈 구축 및 명함 등록 API 연동하기

뱅우 2025. 4. 28. 17:11
반응형

 

안녕하세요!


오늘은 Flutter 프로젝트에서 공통 네트워크 통신 모듈을 구축하고,
이를 활용해서 명함 등록 API 연동까지 완료한 내용을 정리해보려고 합니다.

이번 작업을 통해 프로젝트의 통신 구조를 더 깔끔하고 일관성 있게 다듬을 수 있었어요. ✨

 

1. 공통 네트워크 통신 모듈 구축

네트워크 통신은 앱의 중요한 부분이기 때문에,
처음부터 공통 구조를 잘 잡아두는 게 정말 중요하다고 생각했습니다.

 

📌 구조

  • DioClient: Dio 기본 설정 + 인터셉터 등록
  • AuthInterceptor: 요청마다 자동으로 토큰 추가
  • LoggerInterceptor: 요청/응답 내용을 콘솔에 로깅
  • ApiConstants: API Base URL, 엔드포인트 관리

📂 파일 구성

lib/
 ├── core/
 │    └── network/
 │         ├── dio_client.dart
 │         ├── api_constants.dart
 │         └── interceptors/
 │              ├── auth_interceptor.dart
 │              └── logger_interceptor.dart

 

✅ 주요 포인트

  • DioClient를 싱글턴 패턴으로 구성해서 앱 전체에서 하나의 인스턴스만 사용
  • 모든 요청에 자동으로 토큰을 넣고, 로그도 깔끔하게 찍을 수 있도록 인터셉터 추가
  • 타임아웃, 기본 헤더 등도 중앙에서 관리

 

2. 명함 등록 API 연동

명함 등록을 위한 API 엔드포인트는 다음과 같습니다.

  • POST /전자명함앱/api/v1/cards/register

📝 보내야 할 데이터

필드설명
company 회사명
department 부서명
position 직급
name 이름
phoneNumber 전화번호
email 이메일

사용자는 간단한 폼에 정보를 입력하고,
그 데이터를 서버에 전송하는 방식으로 명함을 등록할 수 있습니다.

 

3. 전체 통신 흐름 구성

통신 흐름은 Service → ViewModel → UI 구조로 만들었습니다.

3.1 Service (API 호출 담당)

class CardApiService {
  final Dio _dio = DioClient().dio;

  Future<void> registerCard({
    required String company,
    required String department,
    required String position,
    required String name,
    required String phoneNumber,
    required String email,
  }) async {
    await _dio.post(
      '/cardtalk/api/v1/cards/register',
      data: {
        "company": company,
        "department": department,
        "position": position,
        "name": name,
        "phoneNumber": phoneNumber,
        "email": email,
      },
    );
  }
}

3.2 ViewModel (상태 관리)

class CardViewModel extends ChangeNotifier {
  final CardApiService _cardApiService = CardApiService();

  bool isLoading = false;
  String? errorMessage;

  Future<void> registerCard({
    required String company,
    required String department,
    required String position,
    required String name,
    required String phoneNumber,
    required String email,
  }) async {
    isLoading = true;
    errorMessage = null;
    notifyListeners();

    try {
      await _cardApiService.registerCard(
        company: company,
        department: department,
        position: position,
        name: name,
        phoneNumber: phoneNumber,
        email: email,
      );
    } catch (e) {
      errorMessage = e.toString();
    } finally {
      isLoading = false;
      notifyListeners();
    }
  }
}

3.3 UI (사용자 입력 + 요청 호출)

ElevatedButton(
  onPressed: viewModel.isLoading
      ? null
      : () {
          context.read<CardViewModel>().registerCard(
            company: _companyController.text,
            department: _departmentController.text,
            position: _positionController.text,
            name: _nameController.text,
            phoneNumber: _phoneController.text,
            email: _emailController.text,
          );
        },
  child: viewModel.isLoading
      ? const CircularProgressIndicator()
      : const Text('명함 등록'),
)

4. 작업을 하며 느낀 점

  • 통신 모듈을 공통으로 관리하니 새 API 추가할 때 훨씬 깔끔하고 빠르게 작업할 수 있었습니다.
  • Service → ViewModel → UI 흐름을 확실히 구분해두니, 테스트나 유지보수도 편해질 것 같습니다.
  • 다음에는 등록 완료 시 토스트 메시지화면 이동 처리까지 추가해서 UX를 조금 더 개선할 예정입니다.

✨ 마무리

이번 작업을 통해 플러터에서 네트워크 구조를 체계적으로 잡는 방법을 익혔고,
실제 API 연동까지 경험할 수 있어서 큰 도움이 되었습니다.

다음 글에서는, 명함 등록 후 성공 화면 이동 처리
API 통신 실패 시 에러 핸들링에 대해 더 자세히 다뤄보겠습니다.

읽어주셔서 감사합니다! 🙌

반응형