Dart 언어 오답노트 : 36. jsonEncode, jsonDecode, Uri.parse

샤워실의 바보·2023년 11월 8일
0
post-thumbnail
import 'dart:convert';

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

class ApiService {
  final String baseUrl = "https://webtoon-crawler.nomadcoders.workers.dev";
  final String today = "today";

  Future<List<WebtoonModel>> getTodaysToons() async {
    List<WebtoonModel> webtoonInstances = [];
    final url = Uri.parse('$baseUrl/$today');
    final response = await http.get(url);
    if (response.statusCode == 200) {
      final List<dynamic> webtoons = jsonDecode(response.body);
      for (var webtoon in webtoons) {
        webtoonInstances.add(WebtoonModel.fromJson(webtoon));
      }
      return webtoonInstances;
    }
    throw Error();
  }

class WebtoonModel {
  final String title, thumb, id;

  WebtoonModel.fromJson(Map<String, dynamic> json)
      : title = json['title'],
        thumb = json['thumb'],
        id = json['id'];
}

이 Dart 코드는 웹툰 정보를 가져오고 처리하기 위한 두 가지 주요 클래스, ApiServiceWebtoonModel을 정의하고 있습니다. 각 클래스와 그들의 주요 기능을 자세히 살펴보겠습니다.

1. ApiService 클래스

가. 목적:

ApiService 클래스는 웹툰 데이터를 웹 서버로부터 비동기적으로 가져오는 역할을 수행합니다.

나. 주요 구성 요소:

  • 필드(Field):

    • baseUrl: API의 기본 URL을 저장하는 문자열입니다. 이 URL은 웹툰 데이터를 가져오는 데 사용됩니다.
    • today: "오늘의 웹툰"을 나타내는 경로를 저장하는 문자열입니다. baseUrl과 결합하여 최종 URL을 생성합니다.
  • 메서드(Method):

    • getTodaysToons: 이 비동기 메서드는 웹 서버로부터 "오늘의 웹툰" 데이터를 가져옵니다.
      • http.get: http 패키지의 get 함수를 사용하여 HTTP GET 요청을 보냅니다.
      • 응답 처리: 서버의 응답이 성공적인 경우(상태 코드 200), 응답 본문은 jsonDecode를 통해 Dart 객체로 변환됩니다.
      • 웹툰 인스턴스 생성: 변환된 데이터(웹툰 목록)는 WebtoonModel의 인스턴스로 변환되어 webtoonInstances 리스트에 추가됩니다.
      • 오류 처리: 요청이 실패하거나 예상치 못한 상태 코드를 받는 경우 Error()를 던집니다.

2. WebtoonModel 클래스

1) 목적:

WebtoonModel 클래스는 웹툰 데이터를 모델링하고, JSON 데이터를 이 모델의 인스턴스로 변환하는 데 사용됩니다.

2) 주요 구성 요소:

  • 필드(Field):

    • title, thumb, id: 웹툰의 제목, 썸네일 URL, 고유 ID를 저장하는 문자열 필드입니다.
  • 생성자(Constructor):

    • WebtoonModel.fromJson: JSON 데이터를 받아 WebtoonModel의 인스턴스를 생성하는 팩토리 생성자입니다.
      • json['title'], json['thumb'], json['id']: JSON 객체에서 필요한 값을 추출하여 각 필드를 초기화합니다.

3. 전체적인 작동 방식:

  1. ApiServicegetTodaysToons 메서드가 호출됩니다.
  2. 이 메서드는 API URL로 HTTP GET 요청을 보내고 응답을 기다립니다.
  3. 응답이 성공적인 경우, 응답 데이터(JSON 형식)는 jsonDecode를 통해 Dart 객체로 변환됩니다.
  4. 이 데이터는 WebtoonModel.fromJson을 통해 WebtoonModel의 인스턴스로 변환되어 webtoonInstances 리스트에 추가됩니다.
  5. 최종적으로 이 메서드는 웹툰 모델의 인스턴스 리스트를 반환합니다.

이 코드는 Dart와 Flutter에서 흔히 사용되는 패턴을 따르고 있으며, API 호출과 JSON 데이터 처리의 기본적인 접근 방식을 보여줍니다. 데이터를 가져오고, 모델링하고, 화면에 표시하는 과정은 모바일 및 웹 애플리케이션 개발에서 매우 일반적입니다.

Dart에서 jsonDecode 메서드는 JSON 형식의 문자열을 Dart 객체로 변환하는 데 사용됩니다. 이는 dart:convert 라이브러리에 포함되어 있으며, JSON 형식의 데이터를 다루는 데 필수적인 기능입니다. jsonDecode 메서드에 대한 상세한 설명과 이 메서드가 ApiService 클래스에서 어떻게 사용되는지 살펴보겠습니다.

4. jsonDecode 메서드

  • 기능: JSON 형식의 문자열을 Dart의 객체로 변환합니다. 이 때 반환되는 객체의 타입은 주로 Map<String, dynamic>, List<dynamic> 등이 됩니다.
  • 사용법: jsonDecode(String source) 형태로 사용됩니다. 여기서 source는 JSON 형식의 문자열입니다.
  • 예시: var data = jsonDecode('{"name": "John", "age": 30}'); 이 코드는 JSON 문자열을 Dart의 Map 객체로 변환합니다.

5. ApiService 클래스에서의 jsonDecode 사용

  • 컨텍스트: getTodaysToons 메서드는 웹 서버로부터 웹툰 데이터를 JSON 형식으로 받아오고, 이를 Dart 객체로 변환해야 합니다.
  • 응답 처리: 서버로부터의 응답(response.body)은 JSON 형식의 문자열입니다. 이 문자열은 jsonDecode를 사용하여 Dart 객체로 변환됩니다.
  • 변환과정:
    • final List<dynamic> webtoons = jsonDecode(response.body); 이 부분에서, 서버 응답은 JSON 배열로 가정되며, jsonDecode를 통해 List<dynamic> 객체로 변환됩니다.
    • 각 웹툰 데이터는 이 리스트의 요소로 존재하며, 각 요소는 WebtoonModel.fromJson 메서드를 통해 WebtoonModel 객체로 변환됩니다. 이 변환 과정은 WebtoonModel 클래스에 정의된 fromJson 팩토리 생성자를 사용합니다.
    • 팩토리 생성자 fromJson은 JSON 객체(여기서는 Map<String, dynamic>)를 받아 WebtoonModel의 인스턴스를 생성합니다.

6. 자바스크립트와의 비교 : JSON.parse, JSON.stringify

jsonDecode 메서드는 웹 API로부터 받은 JSON 형식의 데이터를 Dart 객체로 변환하는 데 중요한 역할을 합니다. ApiService 클래스에서 이 메서드는 웹툰 데이터를 서버로부터 가져와 WebtoonModel 객체의 리스트로 변환하는 핵심 단계에 사용됩니다. 이러한 처리 과정은 Dart에서 웹 서비스와의 통신에 자주 사용되는 패턴입니다.

Dart의 jsonDecode 메서드는 JavaScript의 JSON.parse 메서드와 유사한 역할을 합니다. 두 메서드 모두 JSON 형식의 문자열을 해당 언어에서 사용 가능한 객체 형태로 변환하는 기능을 제공합니다. 간단히 비교해보면:

  • JavaScript의 JSON.parse:

    • 기능: JSON 형식의 문자열을 JavaScript 객체로 변환합니다.
    • 사용 예: let obj = JSON.parse('{"name": "John", "age": 30}');
    • 결과: obj는 JavaScript 객체가 되며, obj.nameobj.age로 접근 가능합니다.
  • Dart의 jsonDecode:

    • 기능: JSON 형식의 문자열을 Dart 객체로 변환합니다. 주로 Map<String, dynamic> 또는 List<dynamic> 타입의 객체를 생성합니다.
    • 사용 예: var data = jsonDecode('{"name": "John", "age": 30}');
    • 결과: data는 Dart의 Map 객체가 되며, data['name']data['age']로 접근 가능합니다.

두 메서드 모두 JSON 데이터를 다룰 때 필수적이며, 웹 개발에서 자주 사용되는 기능입니다. JSON 형식은 데이터 교환의 표준 포맷으로 널리 사용되기 때문에, 이러한 변환 메서드는 다양한 프로그래밍 언어에서 제공됩니다.

7. Uri.parse 메서드

Uri.parse 메서드는 Dart에서 중요한 역할을 하는 메서드 중 하나로, 문자열 형태의 URL 또는 URI를 Uri 객체로 변환하는 데 사용됩니다. 이 메서드는 Dart의 Uri 클래스에 정의되어 있으며, 네트워킹 및 웹 요청을 처리할 때 매우 유용합니다.

1) Uri.parse 메서드의 기본적인 특징과 작동 방식

  • 기능: 문자열 형태의 URL 또는 URI를 Uri 객체로 파싱합니다.
  • 사용법: Uri.parse(String uriString) 형태로 사용됩니다. 여기서 uriString은 파싱할 URL 또는 URI를 나타내는 문자열입니다.
  • 반환 타입: 이 메서드는 Uri 타입의 객체를 반환합니다. Uri 객체는 URL의 다양한 구성 요소(스키마, 호스트, 경로, 쿼리 매개변수 등)에 쉽게 접근할 수 있게 해줍니다.
  • 오류 처리: 잘못된 형식의 URL을 파싱하려고 할 경우, FormatException이 발생할 수 있습니다. 이러한 경우를 처리하기 위해 try-catch 블록을 사용할 수 있습니다.

2) 사용 예시

var uri = Uri.parse('https://example.com/path?query=example');

print(uri.scheme); // 'https'
print(uri.host);   // 'example.com'
print(uri.path);   // '/path'
print(uri.query);  // 'query=example'

3)활용

  • 네트워킹: HTTP 요청을 보낼 때, URL은 Uri 객체로 변환되어야 합니다. http 패키지 등에서 HTTP 요청을 보낼 때 URL 문자열 대신 Uri 객체를 사용합니다.
  • URL 조작 및 분석: Uri 객체를 사용하면 URL의 구성 요소에 쉽게 접근하고, 수정하거나 분석할 수 있습니다.
  • 안전한 URL 생성: Uri 객체를 사용하여 URL을 생성하면, 특수 문자를 적절히 인코딩하고, URL 구조를 올바르게 유지할 수 있습니다.

4) 결론

Uri.parse 메서드는 Dart에서 URL과 URI를 처리하는 기본적이고 중요한 수단입니다. 이를 통해 네트워킹 요청, URL 분석 및 조작 등 다양한 작업을 보다 안전하고 효율적으로 수행할 수 있습니다.

8. as 키워드

Dart에서 import 'package:...' as http; 형태로 as 키워드를 사용하는 것은, 해당 패키지를 별칭(alias)으로 가져오기 위함입니다. 이러한 방식은 특히 다음과 같은 상황에서 유용합니다:

1) 이름 충돌 방지

다른 패키지들이 동일한 이름의 클래스나 함수를 제공할 때, as 키워드를 사용하여 각 패키지에 대한 명확한 별칭을 지정함으로써 이름 충돌을 방지할 수 있습니다.

2) 코드의 가독성 향상

패키지에 별칭을 부여함으로써, 코드를 읽는 사람이 해당 패키지에서 제공하는 클래스나 함수를 쉽게 식별할 수 있게 합니다. 특히, 여러 패키지를 동시에 사용할 때 이 방법이 매우 유용합니다.

3) 편리한 사용

특정 패키지에 짧고 기억하기 쉬운 별칭을 부여함으로써, 코드를 작성할 때 해당 패키지의 기능을 더 빠르고 쉽게 접근할 수 있습니다.

4) 예시

http 패키지의 경우, 다음과 같은 이유로 as http를 사용합니다:

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

void main() async {
  var response = await http.get(Uri.parse('https://example.com'));
  print(response.body);
}
  • 명확성: http.get처럼 사용함으로써, 이 코드가 http 패키지의 get 함수를 사용하고 있음을 명확하게 합니다.
  • 충돌 방지: 만약 다른 패키지에서도 get 함수를 제공한다면, http.get과 같은 형태로 사용함으로써 어떤 get 함수인지 명확히 구분할 수 있습니다.

따라서, as http를 사용하는 것은 코드의 명확성과 유지보수성을 높이는 좋은 방법입니다.

9. named constructor의 this 생략

Dart에서 생성자 내에서 this 키워드를 생략하는 것은 흔히 발생하는 상황입니다. this 키워드는 클래스의 현재 인스턴스를 가리키며, 주로 클래스의 필드와 생성자의 매개변수 이름이 같을 때 혼동을 방지하기 위해 사용됩니다. 하지만, 생성자의 매개변수 이름과 클래스 필드의 이름이 다를 경우 this 키워드를 생략할 수 있습니다.

WebtoonModel.fromJson(Map<String, dynamic> json) 생성자에서 this를 생략한 이유는 다음과 같습니다:

  1. 매개변수와 필드 이름의 차이: 이 생성자에서는 매개변수 json과 클래스 필드 title, thumb, id 사이에 이름이 다릅니다. 이 경우, 클래스 필드에 접근할 때 this 키워드를 사용하지 않아도 혼동의 여지가 없습니다.

  2. 명확한 범위 구분: json['title'], json['thumb'], json['id']json 매개변수에서 특정 키에 해당하는 값을 의미합니다. 여기서 json은 메서드 매개변수이므로 this를 사용할 필요가 없습니다.

1) 생성자에서의 this 사용 예시:

class WebtoonModel {
  String title;
  String thumb;
  String id;

  WebtoonModel({this.title, this.thumb, this.id});
}

이 예시에서는 생성자 매개변수와 클래스 필드가 같은 이름(title, thumb, id)을 가지므로 this.title, this.thumb, this.id 형태로 사용합니다.

2) 요약

WebtoonModel.fromJson 생성자에서 this를 생략한 것은 매개변수와 클래스 필드 간의 이름 차이가 명확하기 때문입니다. 이로 인해 코드가 더 간결해지고, 의도가 명확해집니다. Dart에서는 이러한 방식이 일반적이며, 코드의 가독성을 높이는 데 도움이 됩니다.

profile
공부하는 개발자

0개의 댓글