Busca de CEP no Flutter que não cai quando a ViaCEP sai do ar
Quase todo app brasileiro tem um campo de CEP. E quase todo app resolve isso do
mesmo jeito: uma chamada para viacep.com.br/ws/{cep}/json, um jsonDecode e
pronto. Funciona até o dia em que não funciona.
Os problemas de chamar a ViaCEP direto
Montando o flutter_cep2, esbarrei em detalhes que pegam muita implementação
caseira:
- CEP inexistente não é 404. A ViaCEP responde
200com{"erro": "true"},
e hoje o valor vem como string. Quem testadata['erro'] == truerecebe um
endereço vazio em vez de um erro. - Acento quebrado. A resposta vem em UTF-8 sem
charsetno cabeçalho. O
response.bodydopackage:httpcai para latin1 e "São Paulo" vira
"São Paulo". É preciso decodificar os bytes como UTF-8. - Um único ponto de falha. A ViaCEP é gratuita, mantida por voluntários, e
pede para não fazer consultas em massa: IP que exagera pode ser bloqueado.
Quando ela fica fora do ar, o cadastro do seu app para junto. - As bases são diferentes. O CEP 99999-999 não existe na ViaCEP, mas existe
no OpenCEP e na BrasilAPI (Avenida das Torres, Sarandi/PR).
A solução: fallback entre provedores e cache
import 'package:flutter_cep2/flutter_cep2.dart';
final cep = FlutterCep2(
providers: [CepProvider.viaCep, CepProvider.brasilApi, CepProvider.openCep],
cacheDuration: const Duration(hours: 1),
);
final endereco = await cep.search('01310-100');
print('${endereco.logradouro}, ${endereco.bairro} - ${endereco.localidade}/${endereco.uf}');
// Avenida Paulista, Bela Vista - São Paulo/SP
O search tenta os provedores na ordem. Se um cai, demora demais ou não conhece
o CEP, passa para o próximo. O resultado é sempre o mesmo Cep tipado, venha de
onde vier. Com o cache ligado, a segunda consulta do mesmo CEP sai da memória,
sem rede e sem gastar o limite da ViaCEP.
Os erros têm tipo, então a mensagem certa para o usuário vira um switch:
try {
await cep.search(entrada);
} on CepException catch (e) {
final mensagem = switch (e.type) {
CepErrorType.invalidFormat => 'Digite os 8 números do CEP',
CepErrorType.notFound => 'CEP não encontrado',
_ => 'Não deu para consultar o CEP agora, tente de novo',
};
}
Mais coisas que vêm junto
Busca por endereço, quando o usuário não sabe o CEP:
final ruas = await cep.searchAddress('RS', 'Porto Alegre', 'Domingos Jose');
// 91790-072 Rua Domingos José Poli, 90420-200 Rua Domingos José de Almeida...
Latitude e longitude, pela BrasilAPI:
final ponto = await FlutterCep2(providers: [CepProvider.brasilApi]).search('01310-100');
print('${ponto.latitude}, ${ponto.longitude}'); // -23.5617698, -46.6553299
Utilitários offline, sem nenhuma requisição, bons para formulário:
isValidCep('01310-100'); // true
formatCep('01310100'); // '01310-100'
cepState('01310-100'); // (uf: 'SP', estado: 'São Paulo', regiao: 'Sudeste')
O cepState usa as faixas numéricas dos Correios. Conferi a tabela contra
3.676 CEPs reais das 27 UFs, sem nenhuma divergência.
Dá para usar fora do Flutter
Apesar do nome, o pacote é Dart puro: roda em Android, iOS, web, desktop, CLI e
servidor. As três APIs liberam CORS, então funciona no Flutter web também.
Instalação
flutter pub add flutter_cep2
- pub.dev: https://pub.dev/packages/flutter_cep2
- GitHub: https://github.com/vitoramaral10/flutter_cep2
Se te ajudar, uma estrela no GitHub e um like no pub.dev fazem o pacote
aparecer para mais gente. Issues e PRs são bem-vindos.