Trabalhe com dados JSON
Aprenda sobre desserialização de JSON em Dart, incluindo como usar `dart:convert`, `jsonDecode` e pattern matching para trabalhar com dados JSON da API da Wikipedia.
Neste capítulo, você vai aprender como trabalhar com dados
JSON (JavaScript Object Notation)
em Dart.
Crie modelos de dados para representar as respostas da API da Wikipedia,
use dart:convert para decodificar texto JSON em coleções Dart e
use pattern matching para extrair e validar os dados.
O que você vai realizar
Pré-requisitos
#Antes de começar este capítulo, certifique-se de:
-
Ter concluído o Capítulo 9 e ter um
ambiente de desenvolvimento Dart funcionando com o projeto
dartpedia. - Entender a sintaxe básica do Dart, incluindo classes e tipos de dados.
Como o Dart trata JSON
#JSON é um formato baseado em texto para representar dados estruturados, como objetos, arrays, números e strings. Quando você interage com APIs web, as respostas chegam como strings JSON.
No Dart, converter uma string JSON em um modelo de dados fortemente tipado envolve duas etapas:
-
Decodifique a string JSON em coleções Dart. A biblioteca
dart:convertfornece a funçãojsonDecode(), que transforma uma string JSON bruta em uma coleção Dart padrão:- Um objeto JSON (
{...}) vira umMap<String, dynamic>. - Um array JSON (
[...]) vira umaList<dynamic>.
dartimport 'dart:convert'; const String jsonString = '{"title": "Dart", "pageid": 12345}'; // jsonDecode parses the string, cast to a Map<String, Object?> final Map<String, Object?> jsonMap = jsonDecode(jsonString) as Map<String, Object?>; - Um objeto JSON (
-
Converta as coleções decodificadas em objetos de modelo personalizados. Embora você possa ler valores diretamente de um
Map(comojsonMap['title']), usar mapas brutos em toda a aplicação não oferece segurança de tipos, favorece erros de digitação e não tem autocompletar na IDE.Para resolver isso, aplicações Dart definem classes de modelo de dados com construtores
factory, convencionalmente chamados defromJson, que instanciam objetos tipados a partir de mapas decodificados:dartclass ArticleSummary { final String title; final int pageid; ArticleSummary({required this.title, required this.pageid}); factory ArticleSummary.fromJson(Map<String, Object?> json) { return ArticleSummary( title: json['title'] as String, pageid: json['pageid'] as int, ); } }
O Dart também suporta pattern matching em construtores fromJson,
permitindo validar a estrutura do mapa JSON e
extrair valores em uma única etapa concisa.
Tarefas
#As tarefas a seguir configuram um workspace com vários pacotes e criam as classes de modelo de dados para as respostas da API da Wikipedia.
Tarefa 1: Crie o pacote Wikipedia
#Primeiro, crie um novo pacote Dart para abrigar os modelos de dados.
Navegue até o diretório raiz do seu projeto (
/dartpedia).-
Execute o seguinte comando no terminal:
bashdart create wikipediaEsse comando cria um novo diretório chamado
wikipediacom a estrutura básica de um pacote Dart. Agora você deve ver uma nova pastawikipediana raiz do projeto, ao lado decliecommand_runner.
Tarefa 2: Configure um workspace Dart
#Workspaces Dart permitem gerenciar vários pacotes relacionados dentro de um único projeto, simplificando o gerenciamento de dependências e o desenvolvimento local. Agora que você está adicionando seu terceiro pacote, é um bom momento para configurar o projeto para usar um workspace Dart.
-
Crie o arquivo
pubspec.yamlraiz.Navegue até o diretório raiz do projeto (
/dartpedia) e crie um novo arquivo chamadopubspec.yamlcom o seguinte conteúdo:pubspec.yamlyamlname: _ publish_to: none environment: sdk: ^3.8.1 # IMPORTANT: Adjust this to match your Dart SDK version or a compatible range workspace: - cli - command_runner - wikipedia -
Adicione a resolução de workspace aos sub-pacotes.
Para cada um dos seus sub-pacotes (
cli,command_runnerewikipedia), abra os respectivos arquivospubspec.yamle adicioneresolution: workspaceempubspec.yaml. Isso diz ao Dart para resolver as dependências dentro do workspace.Para
cli/pubspec.yaml:cli/pubspec.yamlyaml# ... (existing content) ... name: cli description: A sample command-line application. version: 1.0.0 resolution: workspace # Add this line # ... (existing content) ...Para
command_runner/pubspec.yaml:command_runner/pubspec.yamlyaml# ... (existing content) ... name: command_runner description: A starting point for Dart libraries or applications. version: 1.0.0 resolution: workspace # Add this line # ... (existing content) ...Para
wikipedia/pubspec.yaml:wikipedia/pubspec.yamlyaml# ... (existing content) ... name: wikipedia description: A sample command-line application. version: 1.0.0 resolution: workspace # Add this line # ... (existing content) ...
-
Resolva as dependências do workspace.
Execute
dart pub getna raiz do projeto para resolver as dependências de todos os pacotes do workspace:bashdart pub get
Tarefa 3: Crie a classe Summary
#A API da Wikipedia retorna um objeto JSON contendo um resumo de um artigo. Uma resposta típica do endpoint de resumo de página tem este formato:
{
"titles": {
"canonical": "Dart_(programming_language)",
"normalized": "Dart (programming language)",
"display": "Dart (programming language)"
},
"pageid": 37194605,
"extract": "Dart is a client-optimized language for fast apps...",
"extract_html": "<p><b>Dart</b> is a client-optimized language...</p>",
"lang": "en",
"dir": "ltr",
"content_urls": {
"desktop": {
"page": "https://en.wikipedia.org/wiki/Dart_(programming_language)"
},
"mobile": {
"page": "https://en.m.wikipedia.org/wiki/Dart_(programming_language)"
}
},
"description": "Programming language"
}
Crie uma classe Dart para representar esse resumo.
-
Crie o diretório
wikipedia/lib/src/model.bashmkdir -p wikipedia/lib/src/model Crie o arquivo
wikipedia/lib/src/model/summary.dart.-
Adicione o seguinte código em
wikipedia/lib/src/model/summary.dart:wikipedia/lib/src/model/summary.dartdartimport 'title_set.dart'; class Summary { /// Returns a new [Summary] instance. Summary({ required this.titles, required this.pageid, required this.extract, required this.extractHtml, required this.lang, required this.dir, this.url, this.description, }); /// TitlesSet titles; /// The page ID int pageid; /// First several sentences of an article in plain text String extract; /// First several sentences of an article in simple HTML format String extractHtml; /// Url to the article on Wikipedia String? url; /// The page language code String lang; /// The page language direction code String dir; /// Wikidata description for the page String? description; /// Creates a [Summary] instance from a JSON map. factory Summary.fromJson(Map<String, Object?> json) { return switch (json) { { 'titles': final Map<String, Object?> titles, 'pageid': final int pageid, 'extract': final String extract, 'extract_html': final String extractHtml, 'lang': final String lang, 'dir': final String dir, 'content_urls': { 'desktop': {'page': final String url}, 'mobile': {'page': String _}, }, 'description': final String description, } => Summary( titles: TitlesSet.fromJson(titles), pageid: pageid, extract: extract, extractHtml: extractHtml, lang: lang, dir: dir, url: url, description: description, ), { 'titles': final Map<String, Object?> titles, 'pageid': final int pageid, 'extract': final String extract, 'extract_html': final String extractHtml, 'lang': final String lang, 'dir': final String dir, 'content_urls': { 'desktop': {'page': final String url}, 'mobile': {'page': String _}, }, } => Summary( titles: TitlesSet.fromJson(titles), pageid: pageid, extract: extract, extractHtml: extractHtml, lang: lang, dir: dir, url: url, ), _ => throw FormatException('Could not deserialize Summary, json=$json'), }; } @override String toString() => 'Summary[' 'titles=$titles, ' 'pageid=$pageid, ' 'extract=$extract, ' 'extractHtml=$extractHtml, ' 'lang=$lang, ' 'dir=$dir, ' 'description=$description' ']'; }Este código define uma classe
Summarypara representar os campos retornados pelo endpoint de resumo da Wikipedia:- Pattern matching no
fromJson: Embora você possa acessar as chaves do mapa individualmente com cast manual (comojson['pageid'] as int), o construtor factoryfromJsonusa pattern matching para validar a estrutura, confirmar os tipos e extrair os valores em uma única expressão declarativa. - Expressão
switch: Oferece dois casos para tratar o campo opcionaldescriptionda Wikipedia: um que o extrai quando está presente e um caso alternativo que corresponde quando ele é omitido. toString: Fornece uma representação em string legível do objetoSummarypara depuração.
- Pattern matching no
Tarefa 4: Crie a classe TitleSet
#
A classe Summary usa uma classe TitlesSet para representar as informações de título.
Crie essa classe a seguir.
Crie o arquivo
wikipedia/lib/src/model/title_set.dart.-
Adicione o seguinte código em
wikipedia/lib/src/model/title_set.dart:wikipedia/lib/src/model/title_set.dartdartclass TitlesSet { /// Returns a new [TitlesSet] instance. TitlesSet({ required this.canonical, required this.normalized, required this.display, }); /// the DB key (non-prefixed), e.g. may have _ instead of spaces, /// best for making request URIs, still requires Percent-encoding String canonical; /// the normalized title (https://www.mediawiki.org/wiki/API:Query#Example_2:_Title_normalization), /// e.g. may have spaces instead of _ String normalized; /// the title as it should be displayed to the user String display; /// Creates a [TitlesSet] instance from a JSON map. factory TitlesSet.fromJson(Map<String, Object?> json) { if (json case { 'canonical': final String canonical, 'normalized': final String normalized, 'display': final String display, }) { return TitlesSet( canonical: canonical, normalized: normalized, display: display, ); } throw FormatException('Could not deserialize TitleSet, json=$json'); } @override String toString() => 'TitlesSet[' 'canonical=$canonical, ' 'normalized=$normalized, ' 'display=$display' ']'; }Este código define uma classe
TitlesSetpara armazenar as variantes de título retornadas pela API da Wikipedia. Diferente deSummary, que usa uma expressãoswitchpara campos opcionais,TitlesSettem uma estrutura fixa e valida os três campos de uma vez usando uma instruçãoif case. Se o mapa JSON não corresponder ao padrão, ele lança umaFormatException.
Tarefa 5: Crie a classe Article
#A API da Wikipedia também retorna uma lista de artigos em um resultado de busca. Crie uma classe Dart para representar um artigo.
Crie o arquivo
wikipedia/lib/src/model/article.dart.-
Adicione o seguinte código em
wikipedia/lib/src/model/article.dart:wikipedia/lib/src/model/article.dartdartclass Article { Article({required this.title, required this.extract}); final String title; final String extract; static List<Article> listFromJson(Map<String, Object?> json) { final List<Article> articles = <Article>[]; if (json case {'query': {'pages': final Map<String, Object?> pages}}) { for (final MapEntry<String, Object?>(:Object? value) in pages.entries) { if (value case { 'title': final String title, 'extract': final String extract, }) { articles.add(Article(title: title, extract: extract)); } } return articles; } throw FormatException('Could not deserialize Article, json=$json'); } Map<String, Object?> toJson() => <String, Object?>{ 'title': title, 'extract': extract, }; @override String toString() { return 'Article{title: $title, extract: $extract}'; } }Este código define uma classe
Articlepara representar o título e o extrato de um artigo:listFromJson: Diferente dos modelos anteriores, que criam uma única instância, o endpoint de busca da Wikipedia retorna vários artigos em um mapa. Construtores Dart retornam apenas uma instância, entãoArticleusa um métodostaticchamadolistFromJsonpara retornar umaList<Article>.- Desestruturação com object pattern: O laço
forusafinal MapEntry(:value)para extrair o valor de cada entrada diretamente, sem acesso manual às propriedades. toJson: Converte uma instância deArticlede volta para um mapa JSON. Pela convenção do Dart,toJson()retorna umMap<String, Object?>que você pode passar parajsonEncode(), dedart:convert, ao serializar um objeto para uma string JSON.
Tarefa 6: Crie a classe SearchResults
#Por fim, crie uma classe para representar os resultados de busca da API da Wikipedia. O endpoint de busca da Wikipedia retorna um array contendo o termo buscado, os títulos dos artigos, as descrições (que são ignoradas) e as URLs:
[
"dart",
["Dart (programming language)", "Dart"],
["", ""],
[
"https://en.wikipedia.org/wiki/Dart_(programming_language)",
"https://en.wikipedia.org/wiki/Dart"
]
]
Crie o arquivo
wikipedia/lib/src/model/search_results.dart.-
Adicione o seguinte código em
wikipedia/lib/src/model/search_results.dart:wikipedia/lib/src/model/search_results.dartdartclass SearchResult { SearchResult({required this.title, required this.url}); final String title; final String url; } class SearchResults { SearchResults(this.results, {this.searchTerm}); final List<SearchResult> results; final String? searchTerm; /// Creates a [SearchResults] instance from a JSON list. factory SearchResults.fromJson(List<Object?> json) { final List<SearchResult> results = <SearchResult>[]; if (json case [ String searchTerm, Iterable articleTitles, Iterable _, Iterable urls, ]) { final List titlesList = articleTitles.toList(); final List urlList = urls.toList(); for (int i = 0; i < articleTitles.length; i++) { results.add(SearchResult(title: titlesList[i], url: urlList[i])); } return SearchResults(results, searchTerm: searchTerm); } throw FormatException('Could not deserialize SearchResults, json=$json'); } @override String toString() { final StringBuffer pretty = StringBuffer(); for (final SearchResult result in results) { pretty.write('${result.url} \n'); } return '\nSearchResults for $searchTerm: \n$pretty'; } }Este código define duas classes:
SearchResult, para armazenar o título e a URL de um artigo individual, eSearchResults, para armazenar a lista de resultados junto com a consulta de busca:fromJsoncomList<Object?>: O construtor aceita umaList<Object?>, em vez de umMap<String, Object?>, para corresponder ao array JSON de nível superior retornado pela API de busca da Wikipedia.- Pattern matching de lista: A instrução
if caseusa um padrão de lista[...]para corresponder ao array por posição e extrair cada seção. - Padrão curinga (
_): O padrãoIterable _corresponde e descarta o array de descrições, que a aplicação não precisa.
Agora você tem modelos de dados tipados para representar as respostas da API da Wikipedia.
Nos próximos capítulos, você vai usar o package:test para testar
como os dados são desserializados e o package:http para buscar
dados JSON ao vivo da API.
Revisão
#O que você realizou
Veja um resumo do que você construiu e aprendeu nesta lição.Aprendeu sobre o tratamento de JSON em Dart
Você explorou como dart:convert e jsonDecode() transformam strings JSON em coleções Dart (Map
e List), e por que modelos tipados com construtores factory fromJson são preferidos em vez de mapas brutos.
Configurou um workspace pub
Para simplificar o gerenciamento de dependências do seu projeto com vários pacotes, você criou um novo workspace pub. Para isso, criou um arquivo
pubspec.yaml raiz com uma seção workspace: listando seus pacotes e, depois, adicionou
resolution: workspace a cada sub-pacote.
Criou classes de modelo de dados para JSON
Você criou as classes Summary, TitlesSet, Article e SearchResults
para representar as respostas da API da Wikipedia. Esses modelos tipados oferecem segurança em tempo de compilação e suporte da IDE ao trabalhar com dados da API.
Usou pattern matching em construtores factory fromJson
Você implementou construtores factory fromJson usando o pattern matching do Dart, com expressões
switch e instruções if case. Essa estrutura valida o formato do JSON e extrai valores em expressões concisas e legíveis.
Quiz
#Confira seu entendimento
1 / 3-
Um formato leve de troca de dados, fácil de ler e escrever para humanos e fácil de interpretar e gerar para máquinas.
Isso mesmo!
JSON (JavaScript Object Notation) é um formato baseado em texto para representar dados estruturados. Ele é muito usado na troca de dados entre aplicativos, principalmente em APIs web.
-
Uma linguagem de programação criada especificamente para desenvolvimento web.
Não exatamente.
JSON não é uma linguagem de programação. Não é possível escrever lógica nem executar código com JSON.
-
Um formato de banco de dados usado exclusivamente por aplicativos JavaScript.
Não exatamente.
JSON não é um formato de banco de dados, nem é exclusivo do JavaScript. Embora tenha se originado da sintaxe do JavaScript, ele é usado em muitas linguagens e plataformas.
-
Uma biblioteca específica do Dart para serialização de dados.
Não exatamente.
JSON não é específico do Dart nem é uma biblioteca. Ele existia antes do Dart e é usado em todo lugar.
jsonDecode interpreta um objeto JSON como {"name": "Dart"}, qual tipo do Dart ele retorna?
-
Um
Map<String, dynamic>que representa o objeto JSON.Isso mesmo!
Objetos JSON viram
Map<String, dynamic>, em que as chaves são strings e os valores podem ser qualquer tipo compatível com JSON. -
Um
Stringcom o texto JSON.Não exatamente.
jsonDecodeinterpreta a string JSON e a converte em objetos Dart. Ele transforma a representação em texto em dados estruturados, incluindo maps e listas, e não mantém o conteúdo como string. -
Uma classe
JsonObjectpersonalizada dedart:convert.Não exatamente.
Não existe uma classe
JsonObjectno Dart.jsonDecoderetorna tipos de coleção padrão do Dart. -
Uma
List<String>com os pares chave-valor.Não exatamente.
Uma lista perderia a relação chave-valor. Objetos JSON têm propriedades nomeadas, o que exige uma estrutura de dados diferente de uma lista.
Summary com um construtor factory fromJson em vez de usar apenas o Map puro retornado por jsonDecode?
-
Segurança de tipos, autocompletar da IDE e um código mais claro que documenta a estrutura de dados esperada.
Isso mesmo!
Uma classe oferece verificação de tipos em tempo de compilação, autocompletar para as propriedades e um código que se documenta sozinho.
summary.titleé mais claro do quemap['title']. -
Maps puros são mais lentos de acessar do que propriedades de classe.
Não exatamente.
Desempenho não é o principal motivo. O acesso a Map é bem rápido no Dart. Pense na experiência do desenvolvedor.
-
O
jsonDecodenão consegue interpretar objetos JSON aninhados sem uma classe.Não exatamente.
O
jsonDecodelida bem com objetos aninhados: eles viram maps aninhados. Classes têm outra finalidade, diferente da interpretação. -
O Dart exige que todos os dados JSON sejam convertidos em classes antes do uso.
Não exatamente.
O Dart não exige isso. Você pode usar maps puros diretamente em todo o seu código.
Próxima lição
#
Na próxima lição, você vai aprender como
testar seu código Dart usando a biblioteca package:test.
Escreva testes para verificar se a lógica de
desserialização JSON funciona corretamente.
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Página atualizada pela última vez em 2026-11-12. Ver código-fonte ou relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.