Flutter

[Flutter] Dio 패키지를 활용한 HTTP 통신 실습

연화 2025. 1. 15. 18:29

 

Flutter로 애플리케이션을 개발할 때, REST API를 활용한 데이터 통신은 매우 중요합니다.
이번 포스팅에서는 Flutter에서 인기 있는 HTTP 통신 패키지인 Dio를 사용하여 서버와 데이터를 주고받는 방법을 단계별로 살펴보겠습니다.

 

💡 학습 목표
1. Dio 패키지를 설치하고 기본 사용법 익히기
2. REST API로 데이터 가져오기
3. JSON 데이터를 Dart 객체로 변환하기

 

1. Dio 패키지 설치하기

 

dio install | Dart package

A powerful HTTP networking package, supports Interceptors, Aborting and canceling a request, Custom adapters, Transformers, etc.

pub.dev

Dio는 강력하고 유연한 HTTP 클라이언트 패키지로, Flutter에서 쉽게 설치하고 사용할 수 있습니다.
pub.dev 사이트에서 dio 패키지를 디펜던시 코드를 가져와서  pubspec.yaml 파일에 의존성을 추가하고 pub get을 실행하여 패키지를 설치했습니다.

dependencies:
  flutter:
    sdk: flutter
  dio: ^5.7.0

 

2. Dio로 간단한 GET 요청 보내기

Dio를 사용하여 서버에서 데이터를 가져오는 간단한 예제를 만들어봅니다.

전체 코드 구조

  • Dio 객체: HTTP 요청을 처리하는 클라이언트.
  • _fetchTodos 메서드: 서버에서 데이터를 가져오는 비동기 함수.
  • try-catch 문: 예외 처리를 통해 안정성을 높임.
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: SafeArea(
        child: Scaffold(
          body: HomePage(),
        ),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // 통신을 담당하는 클라언트 측 객체를 가져오자
  Dio _dio = Dio();

  @override
  void initState() {
    super.initState();
    // 객체 실행시 한번 호출 메서드
    _fetchTodos();
  }

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }

  // 통신을 담당하는 메서드를 만들어 보자.
  _fetchTodos() async {
    // https://jsonplaceholder.typicode.com/todos/1
    // 통신을 담당하는 코드를 기본적으로 예외처리을 꼭 넣자
    try {
      Response response =
          await _dio.get('https://jsonplaceholder.typicode.com/todos/1');

      print('HTTP status code : ${response.statusCode}');
      print('서버측 전달한 데이터 : ${response.data}');
      print(
          'json 통신 후 dart 에서는 어떤 타입으로 변경 되었을까? : ${response.data.runtimeType}');

      // Map 타입에 값을 출력하는 방법
      print('-----------------------------------------------');
      print('data-> title 값 확인 :  ${response.data['title']}');
      
    } catch (e) {
      print('실행 시점 예외가 발생 했어요');
      print(e.toString());
    }
  }
}

테스트 데이터는 아래의 링크에서 받아와 사용했습니다.

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake and reliable API for testing and prototyping. Powered by JSON Server + LowDB. Serving ~3 billion requests each month.

jsonplaceholder.typicode.com

 

3. JSON 데이터를 Dart 객체로 변환하기

서버에서 받은 JSON 데이터를 Dart 객체로 변환하여 사용하면 더 간편합니다. 이를 위해 모델 클래스를 생성합니다.

  • Todo 모델 클래스 만들기
class Todo {
  int? userId;
  int? id;
  String? title;
  bool? completed;

  Todo({
    required this.userId,
    required this.id,
    required this.title,
    required this.completed,
  });

  // JSON 데이터를 Dart 객체로 변환하는 생성자
  Todo.fromJson(Map<String, dynamic> json)
      : userId = json['userId'],
        id = json['id'],
        title = json['title'],
        completed = json['completed'];

  @override
  String toString() {
    return 'Todo{userId: $userId, id: $id, title: $title, completed: $completed}';
  }
}

 

  • JSON 데이터를 객체로 변환하기
  • _fetchTodos 메서드에서 가져온 데이터를 Todo 객체로 변환합니다.
Future<void> _fetchTodos() async {
  try {
    Response response =
        await _dio.get('https://jsonplaceholder.typicode.com/todos/1');

    print('HTTP 상태 코드: ${response.statusCode}');
    print('서버 데이터: ${response.data}');

    // JSON 데이터를 Dart 객체로 변환
    Todo todo = Todo.fromJson(response.data);
    print('변환된 Todo 객체: $todo');
  } catch (e) {
    print('에러 발생: $e');
  }
}

 

4. 예외 처리와 데이터 출력

Dio는 HTTP 요청 실패, 네트워크 연결 문제 등 다양한 예외를 처리할 수 있습니다.
try-catch 블록을 사용하여 안정적인 네트워크 통신을 구현했습니다.

try {
  Response response =
      await _dio.get('https://jsonplaceholder.typicode.com/todos/1');
  print('서버 데이터: ${response.data}');
} catch (e) {
  print('에러 발생: $e');
}

 

실행결과
HTTP 상태 코드: 200
서버 데이터: {userId: 1, id: 1, title: delectus aut autem, completed: false}
변환된 Todo 객체: Todo{userId: 1, id: 1, title: delectus aut autem, completed: false}
전체 코드
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: SafeArea(
        child: Scaffold(
          body: HomePage(),
        ),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // 통신을 담당하는 클라언트 측 객체를 가져오자
  Dio _dio = Dio();

  @override
  void initState() {
    super.initState();
    // 객체 실행시 한번 호출 메서드
    _fetchTodos();
  }

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }

  // 통신을 담당하는 메서드를 만들어 보자.
  _fetchTodos() async {
    // https://jsonplaceholder.typicode.com/todos/1
    // 통신을 담당하는 코드를 기본적으로 예외처리을 꼭 넣자
    try {
      Response response =
          await _dio.get('https://jsonplaceholder.typicode.com/todos/1');

      print('HTTP status code : ${response.statusCode}');
      print('서버측 전달한 데이터 : ${response.data}');
      print(
          'json 통신 후 dart 에서는 어떤 타입으로 변경 되었을까? : ${response.data.runtimeType}');

      // Map 타입에 값을 출력하는 방법
      print('-----------------------------------------------');
			
      Todo todo1 = Todo.fromJson(response.data);
      print("todo1 : ${todo1}");

      print('-----------------------------------------------');
      // Map 으로 들어온 데이터를 Todo 객체를 생성해서 상태 값을 담아 보시오
    } catch (e) {
      print('실행 시점 예외가 발생 했어요');
      print(e.toString());
    }
  }
}

// dart
class Todo {
  int? userId;
  int? id;
  String? title;
  bool? completed;

  Todo(
      {required this.userId,
      required this.id,
      required this.title,
      required this.completed});

  // dart 생성자 -> 명명된 생성자
  Todo.fromJson(Map<String, dynamic> json)
      : userId = json['userId'],
        id = json['id'],
        title = json['title'],
        completed = json['completed'];

  @override
  String toString() {
    return 'Todo{userId: $userId, id: $id, title: $title, completed: $completed}';
  }
}

 

이번 포스팅에서는 Flutter에서 Dio 패키지를 활용하여 REST API와 통신하는 방법을 배웠습니다.
Dio는 강력한 HTTP 클라이언트로, Flutter에서 효율적인 네트워크 요청을 처리할 수 있다고 합니다.
다음에도 Flutter 관련된 유용한 포스팅으로 돌아오도록 할게요~ 감사합니다.