An Interest In:
Web News this Week
- March 15, 2024
- March 14, 2024
- March 13, 2024
- March 12, 2024
- March 11, 2024
- March 10, 2024
- March 9, 2024
Dart/Flutter da Json Ayrtrma
JSON'u ayrtrmak, nternet'ten veri almas gereken uygulamalar iin ok yaygn bir grevdir.
Ne kadar JSON verisi ilemeniz gerektiine bal olarak iki seeneiniz vardr:
- Tm JSON ayrtrma kodunu manuel olarak yazn
- Kod oluturma ile sreci otomatikletirin
Bu klavuz, aadakiler dahil olmak zere JSON'un Dart koduna manuel olarak nasl ayrtrlacana odaklanacaktr :
JSON encoding (kodlama) ve decoding (kod zme)
Type-safe (tip gvenli) model snflar tanmlama
Factory cunstructor kullanarak JSON'u Dart koduna ayrtrma
Nullable/optional (null yaplabilir/istee bal) deerlerle almak
Data validation (veri dorulama)
JSON serializing
Complex/nested (karmak/i ie) JSON verilerini ayrtrma
deep_pick paketinin kullanm
Bu makalenin sonunda, salam JSON ayrtrma ve dorulama koduyla model snflarnn nasl yazlacan reneceksiniz.
Ve bir sonraki makalede , tm ayrtrma kodunu elle yazmak zorunda kalmamak iin kod oluturma aralaryla (code generation tools) JSON ayrtrma hakknda bilgi edineceksiniz.
JSON Kodlama ve Kod zme (Encoding and Decoding JSON)
A zerinden bir JSON yant gnderildiinde, ykn tamam bir dize olarak kodlanr .
Ancak Flutter uygulamalarmzn iinde, verileri bir dizeden manuel olarak karmak istemiyoruz:
final json = '{ "name": "Pizza da Mario", "cuisine": "Italian", "reviews": [{"score": 4.5,"review": "The pizza was amazing!"},{"score": 5.0,"review": "Very friendly staff, excellent service!"}]}';
Bunun yerine JSON'un kodunu zerek ierii okuyabiliyoruz .
JSON verilerini a zerinden gndermek iin nce kodlanmas (encoded) veya seriletirilmesi (serialized) gerekir . Kodlama , bir veri yapsn (data structure) bir string'e dntrme ilemidir . Ters ilem, decoding veya deserialization (seri durumdan karma) olarak adlandrlr . Dize olarak bir JSON yk aldnzda, kullanmadan nce kodunu zmeniz (decode) veya seri durumdan karmanz (deserialize) gerekir.
Dart ile JSON kodunu zme:dntrme (Decoding JSON with dart:convert)
Basit olmas iin, bu kk JSON ykn ele alalm:
//bu, adan aldmz baz yant verilerini temsil eder, rnein:// final response = await http.get(uri);// final jsonData = response.bodyfinal jsonData = '{ "name": "Pizza da Mario", "cuisine": "Italian" }';
indeki anahtarlar ve deerleri okumak iin nce dart:convert
paketini kullanarak kodunu zmemiz gerekiyor
// 1. import dart:convertimport 'dart:convert';// bu, adan aldmz baz yant verilerini temsil ederfinal jsonData = '{ "name": "Pizza da Mario", "cuisine": "Italian" }';// 2. json kodunu zfinal parsedJson = jsonDecode(jsonData);// 3. tr ve deeri yazdrprint('${parsedJson.runtimeType} : $parsedJson');
Bu kodu altrrsak u kty alrz:
_InternalLinkedHashMap<String, dynamic> : {name: Pizza da Mario, cuisine: Italian}
Pratikte, sonu tr ile ayndr Map.
_InternalLinkedHashMap , srayla Map'i uygulayan LinkedHashMap'in zel bir uygulamasdr.
Bu nedenle, anahtarlar String ve deerler dynamic trndedir . Bu mantkldr nk her JSON deeri primitive type (ilkel bir tr => boolean/number/string) veya bir koleksiyon (list veya map) olabilir.
Aslnda, jsonDecode(), iinde ne olduuna baklmakszn herhangi bir geerli JSON yk zerinde alan genel bir yntemdir. Tek yapt, kodunu zmek ve dinamik bir deer dndrmek.
Ancak Dart'ta dinamik deerlerle alrsak, strong type-safety (gl tip gvenliinin) tm avantajlarn kaybederiz. ok daha iyi bir yaklam, duruma gre (on a case-by-case basis) yant verilerimizi temsil eden baz zel model snflar tanmlamaktr.
Dart statik olarak yazlm bir dil olduundan, JSON verilerini gerek dnya nesnelerini (yemek tarifi, alan vb.) temsil eden model snflarna dntrmek ve tr sisteminden (type system) en iyi ekilde yararlanmak nemlidir.
yleyse bunun nasl yaplacan grelim.
JSON'u bir Dart modeli snfna ayrtrma
Bu basit JSON verildiinde:
{ "name": "Pizza da Mario", "cuisine": "Italian"}
Onu temsil edecek bir Restaurant
snf yazabiliriz:
class Restaurant { Restaurant({required this.name, required this.cuisine}); final String name; final String cuisine;}
Sonu olarak, verileri yle okumak yerine:
parsedJson['name']; // dynamicparsedJson['cuisine']; // dynamic
yle okuyabiliriz:
restaurant.name; //geersiz klnamaz, deimez bir string olmas garanti edilirrestaurant.cuisine; // geersiz klnamaz, deimez bir stringolmas garanti edilir
Bu ok daha temizdir ve derleme zaman gvenlii ( compile-time safety) elde etmek ve yazm hatalarn ve dier hatalardan kanmak iin tr sisteminden yararlanabiliriz.
Ancak, parsedJson'umuzu bir Restaurant nesnesine nasl dntreceimizi henz belirlemedik!
JSON da Dart'a Factory Constructor Ekleme
Bunu halletmek iin bir factory constructor tanmlayalm:
factory Restaurant.fromJson(Map<String, dynamic> data) { // note the explicit cast to String // this is required if robust lint rules are enabled final name = data['name'] as String; final cuisine = data['cuisine'] as String; return Restaurant(name: name, cuisine: cuisine);}
Bir factory constructor, sonucu dndrmeden nce baz iler yapmamza (deikenler oluturma, baz dorulamalar gerekletirme) izin verdii iin JSON ayrtrmas (parsing) iin iyi bir seimdir . Bu, normal (generative-retken) constructor'larla mmkn deildir.
Constructor' u ekilde kullanabiliriz:
// type: Stringfinal jsonData = '{ "name": "Pizza da Mario", "cuisine": "Italian" }';// type: dynamic (runtime type: _InternalLinkedHashMap<String, dynamic>)final parsedJson = jsonDecode(jsonData);// type: Restaurantfinal restaurant = Restaurant.fromJson(parsedJson);
ok daha iyi. Artk kodumuzun geri kalan Restaurant class'n kullanabilir ve Dart'ta gl tip gvenliinin (type-safety) tm avantajlarn elde edebilir.
Bazen , belirli bir key/value iftine sahip olan veya olmayan baz JSON'lar ayrtrmamz gerekir .
rnein, bir restorann ilk ne zaman aldn bize bildiren istee bal bir alanmz olduunu varsayalm:
{ "name": "Ezo Sushi", "cuisine": "Japanese", "year_opened": 1990}
Year_opened alan istee balysa (optional), onu model snfmzda bo bir deikenle (nullable variable) temsil edebiliriz.
te Restaurant snf iin gncellenmi bir uygulama:
class Restaurant { Restaurant({required this.name, required this.cuisine, this.yearOpened}); final String name; // non-nullable final String cuisine; // non-nullable final int? yearOpened; // nullable factory Restaurant.fromJson(Map<String, dynamic> data) { final name = data['name'] as String; // cast as non-nullable String final cuisine = data['cuisine'] as String; // cast as non-nullable String final yearOpened = data['year_opened'] as int?; // cast as nullable int return Restaurant(name: name, cuisine: cuisine, yearOpened: yearOpened); }}
Genel bir kural olarak, istee bal JSON deerlerini (optional JSON values) null yaplabilir Dart zelliklerine (nullable Dart properties) elemeliyiz . Alternatif olarak, bu rnekte olduu gibi, null yaplamayan Dart zelliklerini (non-nullable Dart properties) mantkl bir varsaylan deerle kullanabiliriz:
// note: all the previous properties have been omitted for simplicityclass Restaurant { Restaurant({ // 1. required required this.hasIndoorSeating, }); // 2. *non-nullable* final bool hasIndoorSeating; factory Restaurant.fromJson(Map<String, dynamic> data) { // 3. cast as *nullable* bool final hasIndoorSeating = data['has_indoor_seating'] as bool?; return Restaurant( // 4. varsaylan bir dddeer atamak iin ?? operatrn kullanmak hasIndoorSeating: hasIndoorSeating ?? true, ); }}
Bu durumda, varsaylan bir deer salamak iin bo birletirme operatrn (null-coalescing operator) (??)
nasl kullandmza dikkat edin.
Veri Dorulama
Factory constructor kullanmann bir yarar, gerekirse baz ek dorulamalar yapabilmemizdir.
rnein, gerekli bir deer eksikse UnsupportedError veren bir savunma kodu yazabiliriz.
factory Restaurant.fromJson(Map<String, dynamic> data) { // casting as a nullable String so we can do an explicit null check final name = data['name'] as String?; if (name == null) { throw UnsupportedError('Invalid data: $data -> "name" is missing'); } final cuisine = data['cuisine'] as String?; if (cuisine == null) { throw UnsupportedError('Invalid data: $data -> "cuisine" is missing'); } final yearOpened = data['year_opened'] as int?; // Yukardaki if ifadeleri sayesinde, burada name ve cuisine deerlerinin bo olmayaca garanti edilir. return Restaurant(name: name, cuisine: cuisine, yearOpened: yearOpened);}
Genel olarak, her bir deer iin almak API tketicisi olarak bizim iimizdir:
tr (String, int, vb.)
istee balysa veya deilse (nullable vs non-nullable)
hangi deer aralna izin verilirse
Bu, JSON ayrtrma kodumuzu daha salam hale getirecektir. Ve tm dorulamalar nceden yapldndan , widget snflarmzda geersiz verilerle uramak zorunda kalmayacaz .
toJson() ile JSON Seriletirme
JSON'u ayrtrmak yararldr, ancak bazen bir model nesnesini JSON'a geri dntrmek ve a zerinden gndermek isteriz.
Bunu yapmak iin Restaurant snfmz iin bir toJson() yntemi tanmlayabiliriz:
// note the return typeMap<String, dynamic> toJson() { // return a map literal with all the non-null key-value pairs return { 'name': name, 'cuisine': cuisine, if (yearOpened != null) 'year_opened': yearOpened, };}
Ve bunu yle kullanabiliriz:
// bir Restoran nesnesi verildifinal restaurant = Restaurant(name: "Patatas Bravas", cuisine: "Spanish");// convert it to mapfinal jsonMap = restaurant.toJson();// onu bir JSON dizgisine kodlafinal encodedJson = jsonEncode(jsonMap);// sonra herhangi bir a paketiyle istek gvdesi olarak gnder
e JSON' Ayrtrma: List of Map
Artk JSON ayrtrma ve dorulamann temellerini anladmza gre, ilk rneimize geri dnelim ve nasl ayrtrlacan grelim:
{ "name": "Pizza da Mario", "cuisine": "Italian", "reviews": [ { "score": 4.5, "review": "The pizza was amazing!" }, { "score": 5.0, "review": "Very friendly staff, excellent service!" } ]}
Model snflarn ve tip gvenliini (type-safety) sonuna kadar kullanmak istiyoruz, bu yzden bir Review snf tanmlayalm:
class Review { Review({required this.score, this.review}); // non-nullable - puan alannn her zaman mevcut olduu varsaylr final double score; // nullable - inceleme alannn istee bal olduunu varsayarsak final String? review; factory Review.fromJson(Map<String, dynamic> data) { final score = data['score'] as double; final review = data['review'] as String?; return Review(score: score, review: review); } Map<String, dynamic> toJson() { return { 'score': score, // burada, null deerleri hesaba katmak iin collection-if kullanyoruz if (review != null) 'review': review, }; }}
Ardndan, bir reviews listesi eklemek iin Restoran class'n gncelleyebiliriz:
class Restaurant { Restaurant({ required this.name, required this.cuisine, this.yearOpened, required this.reviews, }); final String name; final String cuisine; final int? yearOpened; final List<Review> reviews;}
Ayrca factory cunstructor'n da gncelleyebiliriz:
factory Restaurant.fromJson(Map<String, dynamic> data) { final name = data['name'] as String; final cuisine = data['cuisine'] as String; final yearOpened = data['year_opened'] as int?; // reviews eksik olabileceinden null yaplabilir bir listeye dntrn final reviewsData = data['reviews'] as List<dynamic>?; // reviews eksik deilse final reviews = reviewsData != null // her review'i bir Review object'e eleyin ? reviewsData.map((reviewData) => Review.fromJson(reviewData)) // map() yinelenebilir bir deer dndrr bylece onu listeye evirebiliriz .toList() // geri dn deeri olarak bo bir liste kullann : <Review>[]; // tm argmanlar geen sonucu dndr return Restaurant( name: name, cuisine: cuisine, yearOpened: yearOpened, reviews: reviews, );}
reviews eksik olabilir, bu nedenle nullable bir Listeye yaynlyoruz.
listedeki deerlerin herhangi bir tr olabilir, bu nedenle List kullanyoruz.
Review.fromJson() kullanarak her dinamik deeri bir Review nesnesine dntrmek iin .map() operatrn kullanrz.
reviews eksikse, yedek olarak bo bir liste ([]) kullanrz.
Bu zel uygulama, neyin bo olup olmayaca, hangi yedek deerlerin kullanlaca vb. hakknda baz varsaymlarda bulunur. Kullanm durumunuz iin en uygun ayrtrma kodunu yazmanz gerekir.
e (Nested) Modelleri Seriletirme
Son adm olarak, bir Restoran tekrar Map'e dntrmek iin toJson() yntemini burada bulabilirsiniz:
Map<String, dynamic> toJson() { return { 'name': name, 'cuisine': cuisine, if (yearOpened != null) 'year_opened': yearOpened, 'reviews': reviews.map((review) => review.toJson()).toList(), };}
Tm i ie deerleri de seriletirmemiz gerektiinden (yalnzca Restaurant snfnn kendisini deil) List esini nasl List>'e dntrdmze dikkat edin.
Yukardaki kod ile bir Restaurant nesnesi oluturup onu tekrar kodlanp yazdrlabilen veya a zerinden gnderilebilen bir map'e dntrebiliriz:
final restaurant = Restaurant( name: 'Pizza da Mario', cuisine: 'Italian', reviews: [ Review(score: 4.5, review: 'The pizza was amazing!'), Review(score: 5.0, review: 'Very friendly staff, excellent service!'), ],);final encoded = jsonEncode(restaurant.toJson());print(encoded);// output: {"name":"Pizza da Mario","cuisine":"Italian","reviews":[{"score":4.5,"review":"The pizza was amazing!"},{"score":5.0,"review":"Very friendly staff, excellent service!"}]}
Derin Deerler (Deep Values) Semek
Tm bir JSON belgesini type-safe model snflarna ayrtrmak ok yaygn bir kullanm durumudur.
Ancak bazen derinden i ie (deeply nested) olabilecek baz belirli deerleri okumak isteriz.
rnek JSON'umuzu bir kez daha ele alalm:
{ "name": "Pizza da Mario", "cuisine": "Italian", "reviews": [ { "score": 4.5, "review": "The pizza was amazing!" }, { "score": 5.0, "review": "Very friendly staff, excellent service!" } ]}
reviews listesindeki ilk score deerini almak isteseydik yle yazardk:
final decodedJson = jsonDecode(jsonData); // dynamicfinal score = decodedJson['reviews'][0]['score'] as double;
Bu geerli Dart kodudur nk decodedJson deikeni dinamiktir ve onunla birlikte indis operatrn kullanabiliriz ([]).
Ancak yukardaki kod ne null safe ne de type safe ve ayrtrlan deeri aka istediimiz tre (double) evirmemiz gerekiyor.
Bunu nasl iyiletirebiliriz?
deep_pick Paketi
Deep_pick paketi, tr asndan type-safe API ile JSON parsing'i basitletirir.
import 'dart:convert';import 'package:deep_pick/deep_pick.dart';final decodedJson = jsonDecode(jsonData); // dynamicfinal score = pick(decodedJson, 'reviews', 0, 'score').asDoubleOrThrow();
deep_pick, ilkel trleri (primitive types), listeleri, mapleri, DateTime nesnelerini ve daha fazlasn ayrtrmak iin kullanabileceimiz eitli esnek API'ler sunar.
toString() yntemi ekleme
Model snflaryla alrken, konsola kolayca yazdrlabilmeleri iin bir toString() yntemi salamak ok yararldr.
Zaten bir toJson() yntemimiz olduundan, onu u ekilde kullanabiliriz:
@overrideString toString() => toJson().toString();
Sonu olarak, restoranmz dorudan u ekilde yazdrabiliriz:
print(restaurant);// output: {name: Pizza da Mario, cuisine: Italian, reviews: [{score: 4.5, review: The pizza was amazing!}, {score: 5.0, review: Very friendly staff, excellent service!}]}
Performans Hakknda Not
Kk JSON belgelerini ayrtrdnzda, uygulamanzn yant vermeye devam etmesi ve performans sorunlar yaamamas muhtemeldir.
Ancak ok byk JSON belgelerinin ayrtrlmas, arka planda en iyi ekilde ayr bir Dart isolate zerinde yaplan pahal hesaplamalara neden olabilir . Resmi belgelerin bu konuda iyi bir klavuzu var:
JSON'u arka planda ayrtrn
zm
JSON seriletirme ok sradan bir itir. Ancak uygulamalarmzn doru almasn istiyorsak, bunu doru yapmamz ve ayrntlara dikkat etmemiz ok nemlidir:
JSON verilerini seri hale getirmek iin 'dart:convert'
esinden jsonEncode()
ve jsonDecode()
kullann
Uygulamanzdaki tm alana zg (domain-specific) JSON nesneleri iin fromJson()
ve toJson()
ile model snflar oluturun
Ayrtrma kodunu daha salam hale getirmek iin fromJson()
iine explicit casts, validation ve bo denetimler(null checks) ekleyin
ie (nested) JSON verileri (list of maps) iin fromJson()
ve toJson()
yntemlerini uygulayn
JSON'u tr asndan gvenli(type-safe) bir ekilde ayrtrmak (parse) iin deep_pick paketini kullanmay dnn
Farkl model snfnz varsa veya her snfn birok zellii varsa, tm ayrtrma kodunu elle yazmak zaman alc ve hataya ak hale gelir.
Bu gibi durumlarda kod oluturma(code generation) ok daha iyi bir seenektir.
Original Link: https://dev.to/gulsenkeskin/dartflutter-da-json-ayristirma-104b
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To