Consumindo arquivos JSON no Dart
Tags: flutter, dart, json, mobile
Published: 2021-07-27 15:10:11

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:

```json
 [
 {
 "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

```dart
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<String, dynamic> 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.

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

---

Por qual motivo a tipagem do Map utilizado como parâmetro é `<String, dynamic>`?
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<Object>), Maps...

> Exemplo de um JSON genérico
```json
{
   "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`

```dart
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`.

**É muito importante lembrar de colocarmos o caminho do arquivo JSON nos assets do nosso `pubspec.yaml`!**

```yaml
assets:
    - lib/poke_db.json
```

```dart
Future<String> _carregarPokemonJSON() async {
  return await rootBundle.loadString('lib/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.

```dart
// 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 = 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:

```dart
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](https://github.com/pksasso/dart4noobs)