flutter Dio

Pyo·2023년 9월 18일
0
post-thumbnail

기존에는 Http 라이브러리를 이용하여 api서버와 네트워크 통신을 하였다. 하지만 최근 인프런에서 강의를 몇개 듣고있는데 모두 Dio를 이용하여 네트워크 통신을 하였다. 그래서 이번에는 Dio에 대해 정리 해보려고 한다.

Dio

앱 개발에서 네트워크 통신은 중요한 부분이다. Dio는 이를 위한 탁월한 도구로, HTTP 통신을 쉽고 효과적으로 처리할 수 있도록 도와준다. 이 라이브러리는 HTTP와 유사한 방식으로 동작하지만, 더 간편한 사용법과 다양한 고급 기능을 제공하여 개발자들에게 큰 편의를 제공한다. Dio를 통해 플러터 앱에서 네트워크 작업을 보다 효율적으로 관리하고 제어할 수 있다.

의존성 추가

dependencies:
	dio: ^replace-with-latest-version

우선 Dio를 사용하기 위해서는 pubspec.yaml에 dio를 추가해야 한다.

Http VS Dio

우선 기존 사용하던 Http방식과 Dio방식의 차이점을 알아보겠다.

import 'package:flutter/material.dart';

import 'package:dio/dio.dart';
import 'package:http/http.dart' as http;

import 'package:flutter_practice/src/default_layout_widget.dart';

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

  @override
  Widget build(BuildContext context) {
    final dio = Dio();

    return DefaultLayoutWidget(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () async {
              final resp = await dio.get(
                'https://reqres.in/api/users?page=1',
                queryParameters: {'page': 1},
              );

              print(resp.data);
            },
            child: const Text('Dio Get'),
          ),
          const SizedBox(
            width: 100,
          ),
          ElevatedButton(
            onPressed: () async {
              final resp = await http.get(
                Uri.parse(
                  'https://reqres.in/api/users?page=1',
                ),
              );
              
              print(resp.data);
			  print(
            
            },
            child: const Text('Http Get'),
          ),
        ],
      ),
    );
  }
}

왼쪽 버튼은 Dio방식으로 네트워크 통신을 하여 데이터를 받아오고 , 오른쪽 버튼은 Http방식으로 네트워크 통신을 하여 데이터를 받아온다.

Dio : {page: 1, per_page: 6, total: 12, total_pages: 2, data: [{id: 1, email: george.bluth@reqres.in, first_name: George, last_name: Bluth, avatar: https://reqres.in/img/faces/1-image.jpg}, {id: 2, email: janet.weaver@reqres.in, first_name: Janet, last_name: Weaver, avatar: https://reqres.in/img/faces/2-image.jpg}, {id: 3, email: emma.wong@reqres.in, first_name: Emma, last_name: Wong, avatar: https://reqres.in/img/faces/3-image.jpg}, {id: 4, email: eve.holt@reqres.in, first_name: Eve, last_name: Holt, avatar: https://reqres.in/img/faces/4-image.jpg}, {id: 5, email: charles.morris@reqres.in, first_name: Charles, last_name: Morris, avatar: https://reqres.in/img/faces/5-image.jpg}, {id: 6, email: tracey.ramos@reqres.in, first_name: Tracey, last_name: Ramos, avatar: https://reqres.in/img/faces/6-image.jpg}], support: {url: https://reqres.in/#support-heading, text: To keep ReqRes free, contributions towards server costs are appreciated!}}

Http : {"page":1,"per_page":6,"total":12,"total_pages":2,"data":[{"id":1,"email":"george.bluth@reqres.in","first_name":"George","last_name":"Bluth","avatar":"https://reqres.in/img/faces/1-image.jpg"},{"id":2,"email":"janet.weaver@reqres.in","first_name":"Janet","last_name":"Weaver","avatar":"https://reqres.in/img/faces/2-image.jpg"},{"id":3,"email":"emma.wong@reqres.in","first_name":"Emma","last_name":"Wong","avatar":"https://reqres.in/img/faces/3-image.jpg"},{"id":4,"email":"eve.holt@reqres.in","first_name":"Eve","last_name":"Holt","avatar":"https://reqres.in/img/faces/4-image.jpg"},{"id":5,"email":"charles.morris@reqres.in","first_name":"Charles","last_name":"Morris","avatar":"https://reqres.in/img/faces/5-image.jpg"},{"id":6,"email":"tracey.ramos@reqres.in","first_name":"Tracey","last_name":"Ramos","avatar":"https://reqres.in/img/faces/6-image.jpg"}],"support":{"url":"https://reqres.in/#support-heading","text":"To keep ReqRes free, contributions towards server costs are appreciated!"}}

Http Decode : {page: 1, per_page: 6, total: 12, total_pages: 2, data: [{id: 1, email: george.bluth@reqres.in, first_name: George, last_name: Bluth, avatar: https://reqres.in/img/faces/1-image.jpg}, {id: 2, email: janet.weaver@reqres.in, first_name: Janet, last_name: Weaver, avatar: https://reqres.in/img/faces/2-image.jpg}, {id: 3, email: emma.wong@reqres.in, first_name: Emma, last_name: Wong, avatar: https://reqres.in/img/faces/3-image.jpg}, {id: 4, email: eve.holt@reqres.in, first_name: Eve, last_name: Holt, avatar: https://reqres.in/img/faces/4-image.jpg}, {id: 5, email: charles.morris@reqres.in, first_name: Charles, last_name: Morris, avatar: https://reqres.in/img/faces/5-image.jpg}, {id: 6, email: tracey.ramos@reqres.in, first_name: Tracey, last_name: Ramos, avatar: https://reqres.in/img/faces/6-image.jpg}], support: {url: https://reqres.in/#support-heading, text: To keep ReqRes free, contributions towards server costs are appreciated!}}

결과를 보면 Http를 통해 받아온 데이터를 decode한 결과값이 Dio를 통해 받아온 결과값이다. 따라서 Dio를 통해 받아오게 되면 decode과정없이 바로 Map으로 데이터를 바꿔줄수 있다.

기능 및 사용법

그럼 Dio의 기능들을 간단한 코드로 알아보겠다.

HTTP 요청 처리

Dio에서는 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 지원하며, Dio 인스턴스를 생성하여 서버에 요청을 보낼 수 있다. Options객체를 통해 header등 여러가지 옵션 설정이 가능하고 , request()를 이용할경우 HTTP 메서드를 설정 할수 있다.

var dio = Dio();

// get
final reps1 = await dio.get('https://example.com/api/searchBooks',
	queryParameters: {'query': 'flutter', 'page': 5},);	

// post
final reps2 = await dio.post('https://example.com/api/endpoint',
	options: Options(headers: {'Authorization': 'Bearer token'},),
	data: {'username': 'pyo', 'password': 'test'},);

// reqeust
final reps3 = await dio.request('https://example.com/api/endpoint',
	data: {'query': 'flutter', 'page': 5},
    options: Options(method: 'POST'),);

default Options & BaseOptions

Dio를 이용할경우 options로 Default값을 설정하거나,Dio 객체를 생성할 때 생성자의 매개변수로 BaseOptions 객체를 지정하여 다양하게 설정할 수 있다. header설정도 가능하며,connectTimeout,receiveTimeout 타임 아웃을 설정할 수 있으며 baseUrl로 서버 URL의 공통 부분을 명시해 놓으면 이후 실제 서버에 요청할 때는 path 부분만 지정할 수 있다.

var dio1 = Dio(); 
dio.options.baseUrl = 'https://example.com/api/endpoint';
dio.options.connectTimeout = 3000; 
dio.options.receiveTimeout = 3000;

var dio2 = Dio(
	BaseOptions(
    baseUrl: "https://example.com/api/endpoint",
    connectTimeout: 3000,
    receiveTimeout: 3000,
    headers: {
        HttpHeaders.contentTypeHeader: 'application/json',
        HttpHeaders.acceptHeader: 'application/json'
    },
));

Interceptor

Interceptor는 Dio에서 네트워크 요청과 응답을 가로채고 처리하는 중요한 기능이다. 이를 통해 에러 핸들링, 헤더 수정, 로깅, 공통 작업 처리 등을 수행할 수 있다.

다음은 기본적인 Interceptor를 Dio에 추가하는 방법이다. 이렇게 추가한 Interceptor는 모든 요청과 응답에 적용된다.

dio.interceptors.add(InterceptorsWrapper(
  onRequest:(options, handler){
     return handler.next(options); //continue
    },
    onResponse:(response,handler) {
     return handler.next(response); // continue
   },
    onError: (DioError e, handler) {
     return  handler.next(e);//continue
    }
));

Interceptor를 상속받는 CustomInterceptors 클래스를 만들어서 더 세밀한 제어를 할 수 있다.

import 'package:dio/dio.dart';
class CustomInterceptors extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    print('REQUEST[${options.method}] => PATH: ${options.path}');
    return super.onRequest(options, handler);
  }
  @override
  Future onResponse(Response response, ResponseInterceptorHandler handler) {
    print('RESPONSE[${response.statusCode}] => PATH: ${response.request?.path}');
    return super.onResponse(response, handler);
  }
  @override
  Future onError(DioError err, ErrorInterceptorHandler handler) {
    print('ERROR[${err.response?.statusCode}] => PATH: ${err.request.path}');
    return super.onError(err, handler);
  }
}

이러한 Custom Interceptor 클래스를 만들면 각각의 요청과 응답 단계에서 원하는 작업을 수행할 수 있다.

Interceptor 활용

Interceptor를 활용하는 예시:
onRequest: 요청 전에 토큰 유무 확인 및 토큰 재발급 로직 추가
onResponse: 응답 후 공통 처리 및 Repository로 데이터 전달
onError: 오류 처리, 오류 메시지 처리 또는 모의 데이터 반환 등

Interceptor를 사용하여 Dio로 네트워크 요청을 보낼 때 요청과 응답을 효과적으로 관리하고 처리할 수 있다.

FromData

FormData는 폼 데이터를 구성하고 전송하는 데 사용되며, 주로 파일 업로드 또는 다중 파트 데이터를 처리하는 데 유용하다.

 FormData formData = FormData.fromMap({
                'username ': 'pyo',
                'email': 'pyo@test.com',
              });
              formData.files.add(
                MapEntry(
                  "profile_picture",
                  await MultipartFile.fromFile(
                    "path/to/file.jpg",
                    filename: "profile.jpg",
                  ),
                ),
              );
              try {
                Response response = await dio.post(
                  'https://example.com/api/endpoint',
                  data: formData,
                );

                // 성공적인 응답 처리
                print(response.data);
              } catch (e) {
                // 오류 처리
                print("Error: $e");
              }

Dio에 대해서 공부한 내용들을 적어보았다. 이번에 Dio를 처음 사용해보았는데 이해가 잘 가지 않는 부분도 있었지만 Http를 사용했을때 보다 편했던 점도 많았던것같다. 당분간은 Dio를 계속 사용하면서 적응해 가는 시간이 필요할 것 같다.

참고

https://velog.io/@leeeeeoy/Flutter-Dio-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC
https://kyungsnim.net/175
https://sudarlife.tistory.com/entry/%ED%94%8C%EB%9F%AC%ED%84%B0-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-API-%ED%86%B5%EC%8B%A0%EC%97%90-%ED%8E%B8%EB%A6%AC%ED%95%9C-dio%EC%9D%98-%EA%B8%B0%EB%8A%A5%EC%A0%95%EB%A6%AC

0개의 댓글