Consumindo arquivos JSON no Dart

Neste artigo pretendo mostrar como consumir arquivos JSON no Dart. Não é bem como consumir uma API, algo que dependa de requisições web. Se trata de fato em consumir arquivos JSON da máquina local e atribuindo-os a objetos Dart.

Estruturando o arquivo JSON

Vamos criar um arquivo JSON em nosso projeto e, em seguida, estruturá-lo da seguinte forma:

[
 {
 "id": 1,
 "nome": "Bulbassaur",
 "regiao": "Kanto",
 "tipos": [
  "Grass",
  "Poison"
]
},
{
 "id": 2,
 "nome": "Ivyssaur",
 "regiao": "Kanto",
 "tipos": [
  "Grass",
  "Poison"
]
},
{
 "id": 4,
 "nome": "Charmander",
 "regiao": "Kanto",
 "tipos": [
  "Fire"
]
}
]

Antes de mais nada, vamos pegar esse arquivo JSON que escrevemos e chamá-lo de poke_db.json, por exemplo.

Definindo a classe

class Pokemon {
 int id;
 String? nome;
 String? regiao;
 List<String>? tipos;

 Pokemon({this.id, required this.nome, this.regiao, this.tipos});
}

Criando o método de deserialização do JSON

Antes de partirmos para a criação do método, vamos entender o que é deserializar um objeto JSON?
O que acontece é que o que está presente em nosso "poke_db.json" são dados prontos e fresquinhos para serem consumidos, e nós precisamos de alguma forma utilizar esses dados. Para isso, nós pegamos esses dados "fresquinhos" e reconstruímos eles na forma de um model, um modelo. No caso, atribuímos esses dados aos atributos de uma classe.

No mesmo arquivo da classe criada, criaremos o método fromJson().
O que acontece nesse método?

O fromJson serve para atribuir valores vindos de um objeto JSON para sua classe. Um objeto JSON é reconhecido como um Map devido ao seu comportamento e estruturação de chave-valor. Então pegamos os atributos da classe e fazemos com que recebam os valores do JSON referentes às chaves do Map correspondentes a estes.
Basicamente, esta função é uma espécie de MAPEAMENTO da classe para um objeto JSON.

Pokemon.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    nome = json['nome'];
    regiao = json['regiao'];
    tipos = json['tipos'].cast<String>();
  }

Por qual motivo o casting do Map utilizado como parâmetro é ?
Bom, já sabemos que o tipo informado no lado esquerdo é a tipagem das chaves. Já no direito, é a tipagem dos valores.
No caso, utilizamos o dynamic para os valores justamente pelo motivo de que podemos ter números (int, double), textos (String), listas (List), Maps...

Exemplo de um JSON genérico

{
   "chave": "valor"
}

Vamos consumir o objeto JSON

Vamos criar um arquivo chamado poke_repository.dart.

Neste arquivo iremos criar algumas funções que ficarão responsáveis pelo processo de consumo do nosso objeto JSON.

Primeiramente iremos realizar alguns imports

import 'dart:async';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';
import 'package:pokemon_json/poke_model.dart'; // import da classe

Criaremos uma função para carregar a String contendo todo o arquivo poke_db.json.

Future<String> _carregarPokemonJSON() async {
  return await rootBundle.loadString('poke_db.json');
  // Aqui passamos o [caminho] do arquivo JSON
}

Tendo a String do nosso arquivo JSON carregada, vamos criar uma função que irá nos retornar a lista contendo os objetos Dart de Pokémon.

// Como temos uma lista em nosso objeto JSON, podemos então dizer para nossa função que pode aguardar uma List<Pokemon>
Future<List<Pokemon>> carregarPokemon() async {
  // Atribuímos a String de todo o JSON para a variável pokeJsonString
  String pokeJsonString = await _carregarPokemonJSON();

  // Agora utilizamos o método json.decode() para "decodificarmos" essa String
  final respostaJson = json.decode(pokeJsonString);

  // criando lista genérica para armazenar os Pokémon do objeto JSON
  final lista = <Pokemon>[];

  // Atribuindo cada objeto da lista JSON para a classe Dart Pokémon utilizando o método Pokemon.fromJson()
  for (var pokemon in respostaJson) {
    final poke = new Pokemon.fromJson(pokemon);
    lista.add(poke);
}

  // e finalmente teremos a lista com nossos Pokémon
  return lista;
}

Pronto, com esta última função sendo chamada em alguma parte de seu código você já pode ter acesso aos dados do poke_db.json.

Exemplo:

Future<void> main() async {

 final listaPokemon = await carregarPokemon();

 print(listaPokemon[0].nome); // Bulbassaur


 for (Pokemon pkmn in listaPokemon) {
   print(pkmn.nome);
   /*
   Bulbassaur
   Ivyssaur
   Charmander
  */
}
}

Artigo que possa vir a te ajudar em caso de dúvidas mais específicas em relação ao Dart
Dart4Noobs

8