@@ -8,26 +8,23 @@ description: >-
88layout : learn
99---
1010
11- In this chapter, you'll learn how to work with
11+ In this chapter, learn how to work with
1212[ JSON (JavaScript Object Notation)] [ ] data in Dart.
13- JSON is a common format for data exchange on the web, and
14- you'll often encounter it when working with APIs.
15- You'll learn how to convert JSON data into Dart objects,
16- making it easier to work with in your application.
17- You'll use the [ ` dart:convert ` library] [ ] ,
18- the ` jsonDecode ` function, and pattern matching.
13+ Create data models to represent Wikipedia API responses,
14+ use ` dart:convert ` to decode JSON text into Dart collections, and
15+ use pattern matching to extract and validate data.
1916
2017<SummaryCard >
2118title: What you'll accomplish
2219items:
23- - title: Create data model classes for JSON data
24- icon: data_object
25- - title: Use dart: convert to work with JSON data
20+ - title: Learn about JSON handling in Dart
2621 icon: convert_to_text
27- - title: Use pattern matching to extract data from JSON objects
28- icon: bento
2922 - title: Set up a multi-package workspace
3023 icon: workspaces
24+ - title: Create data model classes for JSON data
25+ icon: data_object
26+ - title: Use pattern matching in fromJson constructors
27+ icon: bento
3128</SummaryCard >
3229
3330[ JSON (JavaScript Object Notation) ] : https://en.wikipedia.org/wiki/JSON
@@ -43,11 +40,64 @@ Before you begin this chapter, ensure you:
4340
4441[ classes ] : /language/classes
4542
43+ ## How Dart handles JSON
44+
45+ JSON is a text-based format for
46+ representing structured data such as objects, arrays, numbers, and strings.
47+ When you interact with web APIs, responses arrive as JSON strings.
48+
49+ In Dart, converting a JSON string into a strongly-typed data model
50+ involves two steps:
51+
52+ 1 . ** Decode the JSON string into Dart collections.**
53+ The [ ` dart:convert ` library] [ ] provides the ` jsonDecode() ` function,
54+ which parses a raw JSON string into a standard Dart collection:
55+ - A JSON object (` {...} ` ) becomes a ` Map<String, dynamic> ` .
56+ - A JSON array (` [...] ` ) becomes a ` List<dynamic> ` .
57+
58+ ``` dart
59+ import 'dart:convert';
60+
61+ const String jsonString = '{"title": "Dart", "pageid": 12345}';
62+
63+ // jsonDecode parses the string, cast to a Map<String, Object?>
64+ final Map<String, Object?> jsonMap =
65+ jsonDecode(jsonString) as Map<String, Object?>;
66+ ```
67+
68+ 1. **Convert the decoded collections into custom model objects.**
69+ While you can read values directly from a `Map` (like `jsonMap['title']`),
70+ using raw maps throughout your application lacks type safety,
71+ invites typos, and provides no IDE autocompletion.
72+
73+ To solve this, Dart applications define data model classes with
74+ `factory` constructors, conventionally named `fromJson`, that
75+ instantiate typed objects from decoded maps:
76+
77+ ```dart
78+ class ArticleSummary {
79+ final String title;
80+ final int pageid;
81+
82+ ArticleSummary({required this.title, required this.pageid});
83+
84+ factory ArticleSummary.fromJson(Map<String, Object?> json) {
85+ return ArticleSummary(
86+ title: json['title'] as String,
87+ pageid: json['pageid'] as int,
88+ );
89+ }
90+ }
91+ ```
92+
93+ Dart also supports [pattern matching][] in `fromJson` constructors,
94+ allowing you to validate the shape of the JSON map and
95+ extract values in a single, concise step.
96+
4697## Tasks
4798
48- In this chapter, you'll create Dart classes to
49- represent the JSON data returned by the Wikipedia API.
50- This will allow you to easily access and use the data in your application.
99+ The following tasks set up a multi-package workspace and
100+ create the data model classes for Wikipedia API responses.
51101
52102### Task 1: Create the Wikipedia package
53103
@@ -130,10 +180,45 @@ it's a good time to configure your project to use a Dart workspace.
130180 # ... (existing content) ...
131181 ```
132182
183+ 1. **Resolve workspace dependencies.**
184+
185+ Run `dart pub get` in your project root to
186+ resolve dependencies across all packages in the workspace:
187+
188+ ```bash
189+ dart pub get
190+ ```
191+
133192### Task 3: Create the Summary class
134193
135194The Wikipedia API returns a JSON object containing a summary of an article.
136- Let' s create a Dart class to represent this summary.
195+ A typical response from the page summary endpoint looks like this:
196+
197+ ```json
198+ {
199+ "titles": {
200+ "canonical": "Dart_(programming_language)",
201+ "normalized": "Dart (programming language)",
202+ "display": "Dart (programming language)"
203+ },
204+ "pageid": 37194605,
205+ "extract": "Dart is a client-optimized language for fast apps...",
206+ "extract_html": "<p><b>Dart</b> is a client-optimized language...</p>",
207+ "lang": "en",
208+ "dir": "ltr",
209+ "content_urls": {
210+ "desktop": {
211+ "page": "https://en.wikipedia.org/wiki/Dart_(programming_language)"
212+ },
213+ "mobile": {
214+ "page": "https://en.m.wikipedia.org/wiki/Dart_(programming_language)"
215+ }
216+ },
217+ "description": "Programming language"
218+ }
219+ ```
220+
221+ Create a Dart class to represent this summary.
137222
1382231 . Create the directory ` wikipedia/lib/src/model ` .
139224
@@ -185,8 +270,8 @@ Let's create a Dart class to represent this summary.
185270 /// Wikidata description for the page
186271 String? description;
187272
188- /// Returns a new [Summary] instance
189- static Summary fromJson(Map<String, Object?> json) {
273+ /// Creates a [Summary] instance from a JSON map.
274+ factory Summary. fromJson(Map< String, Object? > json) {
190275 return switch (json) {
191276 {
192277 ' titles' : final Map< String, Object? > titles,
@@ -250,21 +335,31 @@ Let's create a Dart class to represent this summary.
250335 }
251336 ` ` `
252337
253- This code defines a `Summary` class with properties that
254- correspond to the fields in the JSON response from the Wikipedia API.
255- The `fromJson` method uses [pattern matching][] to
256- extract the data from the JSON object and create a new `Summary` instance.
257- The `toString` method provides a convenient way to
258- print the contents of the `Summary` object.
259- Note that the `TitlesSet` class is used in the `Summary` class,
260- so you' ll need to create that next.
338+ This code defines a ` Summary` class to represent the fields returned
339+ by the Wikipedia summary endpoint:
340+
341+ * ** ` fromJson` pattern matching:** While you can access map keys
342+ individually with manual casting (such as ` json[' pageid' ] as int` ),
343+ the ` fromJson` factory constructor uses [pattern matching][] to
344+ validate the structure, confirm types, and extract values in a single
345+ declarative expression.
346+ * ** ` switch` expression:** Provides two cases to handle Wikipedia' s
347+ optional `description` field: one that extracts it when present,
348+ and a fallback case that matches when it is omitted.
349+ * **`toString`:** Provides a readable string representation of
350+ the `Summary` object for debugging.
351+
352+ :::note
353+ Your editor might flag `import ' title_set.dart' ` and `TitlesSet`
354+ as unresolved references until you create `TitlesSet` in Task 4.
355+ :::
261356
262357[pattern matching]: /language/patterns
263358
264359### Task 4: Create the TitleSet class
265360
266361The `Summary` class uses a `TitlesSet` class to represent the title information.
267- Let ' s create that class now .
362+ Create that class next .
268363
2693641. Create the file `wikipedia/lib/src/model/title_set.dart`.
270365
@@ -290,8 +385,8 @@ Let's create that class now.
290385 /// the title as it should be displayed to the user
291386 String display;
292387
293- /// Returns a new [TitlesSet] instance and imports its values from a JSON map
294- static TitlesSet fromJson(Map<String, Object?> json) {
388+ /// Creates a [TitlesSet] instance from a JSON map.
389+ factory TitlesSet. fromJson(Map<String, Object?> json) {
295390 if (json case {
296391 ' canonical' : final String canonical,
297392 ' normalized' : final String normalized,
@@ -316,17 +411,18 @@ Let's create that class now.
316411 }
317412 ```
318413
319- This code defines a `TitlesSet` class with properties that correspond to
320- the title information in the JSON response from the Wikipedia API.
321- The `fromJson` method uses pattern matching to
322- extract the data from the JSON object and create a new `TitlesSet` instance.
323- The `toString` method provides a convenient way to
324- print the contents of the `TitlesSet` object.
414+ This code defines a `TitlesSet` class to hold the title variants
415+ returned by the Wikipedia API.
416+ Unlike `Summary`, which uses a `switch` expression for optional fields,
417+ `TitlesSet` has a fixed structure and validates all three fields at once
418+ using an `if case` statement.
419+ If the JSON map does not match the pattern, it throws a
420+ `FormatException`.
325421
326422### Task 5: Create the Article class
327423
328424The Wikipedia API also returns a list of articles in a search result.
329- Let ' s create a Dart class to represent an article.
425+ Create a Dart class to represent an article.
330426
3314271. Create the file `wikipedia/lib/src/model/article.dart`.
332428
@@ -367,19 +463,38 @@ Let's create a Dart class to represent an article.
367463 }
368464 ```
369465
370- This code defines an ` Article` class with properties for
371- the title and extract of an article.
372- The ` listFromJson` method uses pattern matching to
373- extract the data from the JSON object and
374- create a list of ` Article` instances.
375- The ` toJson` method converts the ` Article` object back into a JSON object.
376- The ` toString` method provides a convenient way to
377- print the contents of the ` Article` object.
466+ This code defines an `Article` class to represent an article' s
467+ title and extract:
468+
469+ * ** ` listFromJson` :** Unlike previous models that create a single instance,
470+ the Wikipedia search endpoint returns multiple articles in a map.
471+ Dart constructors only return a single instance, so ` Article` uses
472+ a ` static` method named ` listFromJson` to return a ` List< Article> ` .
473+ * ** Object pattern destructuring:** The ` for` loop uses
474+ ` final MapEntry(:value)` to extract each entry' s value directly
475+ without manual property access.
476+ * **`toJson`:** Converts an `Article` instance back into a JSON map.
477+ In Dart convention, `toJson()` returns a `Map<String, Object?>`
478+ that you can pass to `jsonEncode()` from `dart:convert`
479+ when serializing an object to a JSON string.
378480
379481### Task 6: Create the SearchResults class
380482
381- Finally, let' s create a class to represent the
382- search results from the Wikipedia API.
483+ Finally, create a class to represent search results from the Wikipedia API.
484+ The Wikipedia search endpoint returns an array containing the search term,
485+ article titles, descriptions (which are ignored), and URLs:
486+
487+ ```json
488+ [
489+ "dart",
490+ ["Dart (programming language)", "Dart"],
491+ ["", ""],
492+ [
493+ "https://en.wikipedia.org/wiki/Dart_(programming_language)",
494+ "https://en.wikipedia.org/wiki/Dart"
495+ ]
496+ ]
497+ ```
383498
3844991. Create the file `wikipedia/lib/src/model/search_results.dart`.
3855001. Add the following code to `wikipedia/lib/src/model/search_results.dart`:
@@ -396,7 +511,8 @@ search results from the Wikipedia API.
396511 final List<SearchResult> results;
397512 final String? searchTerm;
398513
399- static SearchResults fromJson(List<Object?> json) {
514+ /// Creates a [SearchResults] instance from a JSON list.
515+ factory SearchResults.fromJson(List<Object?> json) {
400516 final List<SearchResult> results = <SearchResult>[];
401517 if (json case [
402518 String searchTerm,
@@ -425,17 +541,22 @@ search results from the Wikipedia API.
425541 }
426542 ```
427543
428- This code defines a `SearchResults` class with a
429- list of `SearchResult` objects and a search term.
430- The `fromJson` method uses pattern matching to extract the data from
431- the JSON object and create a new `SearchResults` instance.
432- The `toString` method provides a convenient way to
433- print the contents of the `SearchResults` object.
544+ This code defines two classes: `SearchResult` to hold an individual
545+ article' s title and URL, and ` SearchResults` to hold the list of
546+ results along with the search query:
547+
548+ * ** ` fromJson` with ` List< Object? > ` :** The constructor accepts
549+ a ` List< Object? > ` rather than a ` Map< String, Object? > ` to match
550+ the top-level JSON array returned by Wikipedia' s search API.
551+ * **List pattern matching:** The `if case` statement uses a list pattern
552+ `[...]` to match the array positionally and extract each section.
553+ * **Wildcard pattern (`_`):** The `Iterable _` pattern matches and
554+ discards the descriptions array, which your application does not need.
434555
435- At this point, you ' ve created data models to represent JSON structures .
436- There ' s nothing to test at this point.
437- You ' ll add that application logic in the upcoming sections,
438- which will enable you to test how data is deserialized from the Wikipedia API.
556+ You now have typed data models to represent Wikipedia API responses .
557+ In upcoming chapters, use `package: test` to test
558+ how data is deserialized and use `package:http` to fetch
559+ live JSON data from the API.
439560
440561## Review
441562
@@ -444,26 +565,13 @@ title: What you accomplished
444565subtitle: Here' s a summary of what you built and learned in this lesson.
445566completed: true
446567items:
447- - title: Created data model classes for JSON
448- icon: data_object
449- details: >-
450- You built `Summary`, `TitlesSet`, `Article`, and `SearchResults` classes
451- to represent Wikipedia API responses.
452- These typed models provide compile-time safety and
453- IDE support when working with API data.
454- - title: Used dart:convert to work with JSON data
568+ - title: Learned about JSON handling in Dart
455569 icon: convert_to_text
456570 details: > -
457- You imported the `dart:convert` library and used `jsonDecode()` to
458- parse JSON strings into Dart objects, including `Map` and `List`,
459- that you can then work with programmatically.
460- - title: Used pattern matching to extract data from JSON objects
461- icon: bento
462- details: >-
463- You implemented `fromJson` factory methods using Dart' s pattern matching
464- with ` switch` expressions and ` if case` statement.
465- This structure allowed you to validate the JSON structure and
466- extract values from the JSON objects in single, readable expressions.
571+ You explored how ` dart:convert` and `jsonDecode ()`
572+ parse JSON strings into Dart collections (` Map` and ` List` ), and
573+ why typed models with ` fromJson` factory constructors are preferred
574+ over raw maps.
467575 - title: Set up a pub workspace
468576 icon: workspaces
469577 details: > -
@@ -472,6 +580,20 @@ items:
472580 To do so, you created a root ` pubspec.yaml` file with
473581 a ` workspace:` section listing your packages, then
474582 added ` resolution: workspace` to each sub-package.
583+ - title: Created data model classes for JSON
584+ icon: data_object
585+ details: > -
586+ You built ` Summary` , ` TitlesSet` , ` Article` , and ` SearchResults` classes
587+ to represent Wikipedia API responses.
588+ These typed models provide compile-time safety and
589+ IDE support when working with API data.
590+ - title: Used pattern matching in fromJson factory constructors
591+ icon: bento
592+ details: > -
593+ You implemented ` fromJson` factory constructors using Dart' s pattern
594+ matching with `switch` expressions and `if case` statements.
595+ This structure validates the JSON shape and
596+ extracts values in concise, readable expressions.
475597</SummaryCard>
476598
477599## Quiz
@@ -480,7 +602,7 @@ items:
480602
481603## Next lesson
482604
483- In the next lesson, you ' ll learn how to
605+ In the next lesson, learn how to
484606test your Dart code using the `package:test` library.
485- You ' ll write tests to ensure that your
486- JSON deserialization logic is working correctly.
607+ Write tests to verify that your
608+ JSON deserialization logic works correctly.
0 commit comments