dio를 통한 api 통신은 5단계로 나눌 수 있다.
결국엔 dio도 HTTP 통신을 이용하기에 데이터가 어떻게 오가는지를 정리한다.

dio 패키지는 api 통신을 위해 개발되었으며, flutter에서 사랑받고 있는 통신 패키지 중 하나이다.
현재 시간 기준, 47시간 전에도 업데이트가 되었을 만큼 개발자가 지속적으로 신경쓰고 있다.
현재는 최신 버전은 5.9.1ver 이며, 패키지 추가 명령어는 아래와 같다.
flutter pub add dio
GET, POST 등 기본적인 REST API 통신 뿐만 아니라 인터셉터를 이용한 데이터 검증 및 부가정보 포함까지 간편하게 할 수 있다.
결론부터 말하자면 1단계에서는 모든 요청이 Dio 객체, RequestOptions라는 거대한 객체로 변환된다.
Dio 인스턴스를 만들 때 설정했던 BaseOptions와 개별 Option(파라미터 등)가 합쳐진다.
이후, baseUrl을 기반으로 절대경로 http 주소를 만든다.
이때, 요청 경로에 잘못 기입된 부분은 없는지, 중복된 값은 없는지 자체적으로 체크한다.
마지막으로 QueryParameter를 쿼리 스트링 형태로 http 주소 뒤에 붙인다.
POST 요청에서는 전달되는 data를 확인한다.
Map 형태는 JSON으로 인식되고, FormData는 멀티파트 요청으로 준비한다.
자, 이제 RequestOptions는 준비가 끝났다.
1단계를 거쳐 만들어진 Dio 객체를 서버로 전달하기 전, interceptor는 몇가지 검사, 추가 및 수정작업을 진행한다.
Access Token이 없다면 Token을 직접 주입해주고, 해당 객체가 어디로 가는지 log를 통해 기록한다.
또, 데이터 형식이 잘못 되었다면 서버로 데이터를 보내기 전에 자체적으로 에러를 반환한다.
Dio에는 interceptors가 List형식으로 존재한다.
각 interceptor 별 작업 응답은 다음과 같다.
인터셉터를 여러개 등록했다면 모든 요청과 응답을 거친 뒤 서버로 요청이 전송된다.
3단계에서는 실제 요청 전송이 이루어진다.
dio는 http통신을 사용하기에, 서버와 TCP/IP 연결을 통해 데이터 전송 길목을 설정한다.
TCP/IP의 간단한 전송 순서는 다음과 같다.
1. SYN, SYN-ACK, ACK를 통해 서버와 클라이언트 사이의 데이터 전송 길목을 설정한다.
2. 데이터 요청을 잘게 잘라 순서를 붙여 전송한다.(이 때가 onSnedProgress가 실행되는 시점이다)
데이터를 잘게 전송하는 이유는 데이터를 한번에 서버로 던지게 되면 ui에서 버벅거림이 나타날 수 있다.
마찬가지로 서버에서 응답 데이터가 돌아올 때도 잘게 잘라 보낸 뒤 데이터를 뒤에서 다시 합친다.
Flutter는 크로스 플랫폼이다.
하지만, flutter를 통해 실행되는 각 플랫폼마다 데이터를 보내는 방식이 다르다.
모바일 같은 경우는 IOHttpClientAdaptor를 사용하며, 웹 같은 경우는 BrowserHttpClientAdaptor를 사용한다.
4단계에서는 서버에서 돌아온 응답 데이터를 요리한다.
서버에서 돌아온 데이터는 TCP/IP를 통한 응답 데이터로, 바이트(0과 1) 형태로 저장되어 있다.
Dio의 Transformer는 해당 바이트 뭉치 데이터에서 우리가 읽을 수 있는 UTF-8 문자열로 먼저 해독한다.
그리고, 만약 해당 데이터의 형태가 {} String 형태라면 Dart의 Map 형식으로 자동 jsonDecode를 실행한다.
한번에 많은 양이 파싱되는 동안에는 ui가 끊길 수 있다.
Dio는 이러한 현상을 막기 위해 Isolate에 맡겨 실행한다.
추가적으로, Dio는 응답 데이터의 타입을 직접 설정할 수 있다.
기본적으로 JSON으로 설정되어 있지만, String 자체를 넘길 수도 있고 바이트 등의 타입으로도 설정할 수 있다.
이제 데이터가 완벽한지 StatusCode를 통해 알아볼 시간이다.
정상 응답 데이터는 StatusCode에 200,201을 포함하고 있고 그렇지 않다면 404 Not Found, 500 Server Error 등을 포함하고 있을 것이다.
통신 과정 중 에러가 발생했다면 Dio는 전용 예외, DioException을 내뱉는다.
이 예외에는 상세한 이유가 포함되어 있으니 try-catch 블록을 통해 간편하게 처리할 수 있다.