A maioria dos aplicativos precisa realizar solicitações de rede pela Internet. Como tal, é importante lidar com chamadas de rede de forma elegante para evitar erros desnecessários em chamadas de API.

Neste artigo, vamos dar uma olhada em como podemos lidar com solicitações de API REST no Flutter usando o pacote http.

Primeiros passos

Crie um novo Flutter projeto usando o seguinte comando:

flutter create flutter_http_networking

Você pode abrir o projeto usando seu IDE favorito, mas para este exemplo, estarei usando o código VS:

code flutter_http_networking

Adicione o http pacote para seu arquivo pubspec.yaml:

dependências: http: ^ 0.13.3

Substitua o conteúdo do seu arquivo main.dart pela seguinte estrutura básica:

import’package: flutter/material.dart’; importar’telas/home_page.dart’; void main () {runApp (MyApp ()); } class MyApp extends StatelessWidget {@override Widget build (BuildContext context) {return MaterialApp (title:’Flutter Networking’, theme: ThemeData (primarySwatch: Colors.teal,), debugShowCheckedModeBanner: false, home: HomePage (),); }}

Criaremos a HomePage depois de dar uma olhada na API que executará as operações de rede.

Solicitando dados da API

Para esta demonstração de solicitações de API, iremos use os dados de amostra/posts de JSONPlaceholder . Começaremos buscando dados de uma única postagem usando a solicitação GET. O ponto de extremidade que você deve usar é:

GET https://jsonplaceholder.typicode.com/posts/

Aqui, você deve substituir o por um valor inteiro representando o ID do post que você deseja recuperar.

Se sua solicitação for bem-sucedida, a resposta JSON de amostra que você receberá será semelhante a:

{“userId”: 1,”id”: 1,”title”:”sunt aut facere repellat provident occaecati excepturi optio reprehenderit”,”body”:”quia et suscipit \ nsuscipit recusandae consequuntur expedita et cum \ nreprehenderit molestiae ut ut quas totam \ nnostrum rerum est autem sunectot rem even”} h2> Especificando a classe do modelo

A classe do modelo ajuda a empacotar os dados retornados por uma chamada de API ou enviar dados usando uma solicitação de rede.

Definiremos uma classe de modelo para tratamento um único post de dados. Você pode usar uma ferramenta de conversão de classe JSON para Dart como quicktype para gerar facilmente uma classe de modelo. Copie e cole dentro de um arquivo chamado post.dart:

class Post {Post ({this.id, this.userId, this.title, this.body,}); int? eu ia; int? ID do usuário; Fragmento? título; Fragmento? corpo; fábrica Post.fromJson (Map json)=> Post (userId: json [“userId”], id: json [“id”], title: json [“title”], body: json [“body”],); Mapear toJson ()=> {“userId”: userId,”id”: id,”title”: title,”body”: body,}; }

Como alternativa, você também pode usar a serialização JSON e gerar os métodos fromJson e toJson automaticamente, o que ajuda a evitar quaisquer erros despercebidos que possam ocorrer durante a definição manual.

Se você usar a serialização JSON, será necessário os seguintes pacotes:

json_serializable json_annotation build_runner

Adicione-os ao seu pubspec arquivo.yaml:

dependencies: json_annotation: ^ 4.0.1 dev_dependencies: json_serializable: ^ 4.1.3 build_runner: ^ 2.0.4

Para usar a serialização JSON, você deve modificar a classe Post da seguinte maneira:

import’package: json_annotation/json_annotation.dart’; parte’post.g.dart’; @JsonSerializable () class Post {Post ({this.id, this.userId, this.title, this.body,}); int? eu ia; int? ID do usuário; Fragmento? título; Fragmento? corpo; fábrica Post.fromJson (Map json)=> _ $ PostFromJson (json); Map toJson ()=> _ $ PostToJson (this); }

Você pode acionar a ferramenta de geração de código usando o seguinte comando:

flutter pub run build_runner build

Se você deseja manter a ferramenta de geração de código em execução em segundo plano-o que aplicará automaticamente quaisquer modificações posteriores que você faça para a classe de modelo-use o comando:

flutter pub run build_runner serve–delete-conflito-outputs

O sinalizador–delete-conflito-outputs ajuda a regenerar uma parte da classe gerada se houver algum conflito são encontrados.

Executando solicitações de API

Agora você pode começar a executar as várias solicitações de rede na API REST. Para manter seu código limpo, você pode definir os métodos relacionados às solicitações de rede dentro de uma classe separada.

Crie um novo arquivo chamado post_client.dart e defina a classe PostClient dentro dele:

class PostClient {//TODO: Defina os métodos para solicitações de rede}

Defina a URL base do servidor junto com o endpoint necessário nas variáveis:

class PostClient {static final baseURL=”https://jsonplaceholder.typicode.com”; postsEndpoint final estático=baseURL +”/posts”; }

Usaremos essas variáveis ​​ao realizar as solicitações.

Buscando dados

Você pode usar a solicitação GET para recuperar informações da API. Para buscar dados de um único post, você pode definir um método como este:

Future fetchPost (int postId) async {final url=Uri.parse (postsEndpoint +”/$ postId”); resposta final=espera http.get (url); }

Este método tenta recuperar os dados de uma postagem de acordo com o ID passado a ela. O método http.get () usa o URL para buscar dados do servidor que estão armazenados na variável de resposta.

Verifique se a solicitação foi bem-sucedida verificando o código de status HTTP, que deve ser 200 se for bem-sucedido. Agora você pode decodificar os dados JSON brutos e usar Post.fromJson () para armazená-los de uma maneira agradável e estruturada usando a classe de modelo.

Future fetchPost (int postId) async {final url=Uri.parse (postsEndpoint +”/$ postId”); resposta final=espera http.get (url); if (response.statusCode==200) {return Post.fromJson (jsonDecode (response.body)); } else {throw Exception (‘Falha ao carregar a postagem: $ postId’); }}

Enviando dados

Você pode usar a solicitação POST para enviar dados à API. Criaremos uma nova postagem enviando dados usando o seguinte método:

Future createPost (String title, String body) async {final url=Uri.parse (postsEndpoint); final response=await http.post (url, headers: {‘Content-Type’:’application/json; charset=UTF-8′,}, body: jsonEncode ({‘title’: title,’body’: body, }),); }

Ao enviar dados, você deve especificar o tipo de cabeçalho nos cabeçalhos e o corpo que deseja enviar para o endpoint especificado. Além disso, os dados JSON devem ser enviados em um formato codificado usando o método jsonEncode.

Você pode verificar se sua solicitação POST foi bem-sucedida usando o código de status HTTP. Se retornar um código de status 201, a solicitação foi bem-sucedida e podemos retornar os dados da postagem.

Future createPost (String title, String body) async {//… if (response.statusCode==201) {return Post.fromJson (jsonDecode (response.body)); } else {throw Exception (‘Falha ao criar postagem’); }}

Atualizando dados

Você pode atualizar qualquer informação de postagem presente no servidor API usando a solicitação PUT. Defina o método como este:

Future updatePost (int postId, String title, String body) async {final url=Uri.parse (postsEndpoint +”/$ postId”); resposta final=await http.put (url, headers: {‘Content-Type’:’application/json; charset=UTF-8′,}, body: jsonEncode ({‘title’: title,’body’: body, }),); }

Aqui, usamos o ID da postagem para especificar para qual postagem atualizar e enviar a solicitação. Se o código de status de resposta for 200, a solicitação foi bem-sucedida e você pode retornar a postagem atualizada enviada pelo servidor.

Future updatePost (int postId, String title, String body) async {//… if (response.statusCode==200) {return Post.fromJson (jsonDecode (response.body)); } else {throw Exception (‘Falha ao atualizar a postagem’); }}

Excluindo dados

Você pode remover uma postagem do servidor API usando a solicitação DELETE. O método pode ser definido como segue:

Future deletePost (int postId) async {url final=Uri.parse (postsEndpoint +”/$ postId”); resposta final=espera http.delete (url, cabeçalhos: {‘Content-Type’:’application/json; charset=UTF-8′,},); if (response.statusCode==200) {return Post.fromJson (jsonDecode (response.body)); } else {throw Exception (‘Falha ao deletar postagem: $ postId’); }}

Usamos o ID da postagem para especificar qual postagem excluir e enviar a solicitação ao respectivo endpoint. Você pode verificar se a solicitação foi bem-sucedida verificando se o código de status HTTP é 200.

Você deve observar que, no caso de exclusão, a resposta retorna dados vazios.

Futuro deletePost (int postId) async {//… if (response.statusCode==200) {return Post.fromJson (jsonDecode (response.body)); } else {throw Exception (‘Falha ao deletar postagem: $ postId’); }}

Construindo a IU

A interface do usuário será definida no widget HomePage. Será um StatefulWidget porque precisaremos atualizar seu estado após cada solicitação de rede.

import’package: flutter/material.dart’; import’package: flutter_http_networking/utils/post_client.dart’; importe’pacote: http/http.dart’como http; a classe HomePage estende StatefulWidget {@override _HomePageState createState ()=> _HomePageState (); } classe _HomePageState extends State {@override Widget build (contexto BuildContext) {return Scaffold (); }}

Primeiro, definiremos as duas variáveis ​​que irão armazenar o título e o corpo da postagem retornada por uma chamada de API e, em seguida, inicializaremos a classe PostClient:

import’package: flutter/material.dart’; import’package: flutter_http_networking/utils/post_client.dart’; importe’pacote: http/http.dart’como http; a classe HomePage estende StatefulWidget {@override _HomePageState createState ()=> _HomePageState (); } class _HomePageState extends State {final PostClient _postClient=PostClient (); Fragmento? _postTitle; Fragmento? _postBody; @override Widget build (contexto BuildContext) {return Scaffold (); }}

Agora criaremos botões que irão acionar os métodos de solicitação de rede e atualizar as variáveis ​​com as informações retornadas pelo servidor. Abaixo está o snippet de código para acionar o método fetchPost ():

ElevatedButton (onPressed: () async {final post=await _postClient.fetchPost (1); setState (() {_postTitle=post.title; _postBody=post.body;});}, child: Text (‘GET’),)

Você pode acionar os métodos de solicitação de rede restantes da mesma forma.

A interface do usuário final do aplicativo se parece com isto:

Teste de solicitações de rede

Você pode testar as solicitações de API no Dart usando Mockito , um pacote que ajuda a simular solicitações de rede e testar se seu aplicativo lida de maneira eficaz com os vários tipos de solicitações, incluindo respostas nulas e de erro.

Para testar com o Mockito, adicione-o ao seu pubspec. arquivo yaml e certifique-se de que você também tenha as dependências build_runner e flutter_test definidas:

dev_dependencies: flutter_test: sdk: flutter build_runner: ^ 2.0.4 mockito: ^ 5.0.10

Agora, você precisa fazer uma pequena modificação nos métodos de solicitação de rede que deseja testar. Faremos a modificação no método fetchPost ().

Forneça um http.Client para o método e use o cliente para executar a solicitação get (). O método modificado terá a seguinte aparência:

Future fetchPost (http.Client client, int postId) async {final url=Uri.parse (postsEndpoint +”/$ postId”); resposta final=espera client.get (url); if (response.statusCode==200) {return Post.fromJson (jsonDecode (response.body)); } else {throw Exception (‘Falha ao carregar a postagem: $ postId’); }}

Crie um arquivo de teste chamado fetch_post_test.dart dentro da pasta de teste e anote a função principal com @GenerateMocks ([http.Client]).

import’package: flutter_http_networking/models/post.dart’; import’package: flutter_http_networking/utils/post_client.dart’; import’package: flutter_test/flutter_test.dart’; importe’pacote: http/http.dart’como http; import’package: mockito/annotations.dart’; import’package: mockito/mockito.dart’; import’fetch_post_test.mocks.dart’; @GenerateMocks ([http.Client]) void main () {}

Isso ajudará a gerar a classe MockClient usando a ferramenta build_runner. Acione a geração de código usando o seguinte comando:

flutter pub run build_runner build

Definiremos apenas dois testes: um para uma solicitação de API bem-sucedida e outro para uma solicitação malsucedida com erro. Você pode testar essas condições usando a função when () fornecida pelo Mockito.

@GenerateMocks ([http.Client]) void main () {PostClient _postClient=PostClient (); final postEndpoint=Uri.parse (‘https://jsonplaceholder.typicode.com/posts/1’); group (‘fetchPost’, () {test (‘solicitação bem-sucedida’, () async {final client=MockClient (); when (client.get (postEndpoint),).thenAnswer ((_) async=> http.Response (‘{“userId”: 1,”id”: 2,”title”:”mock post”,”body”:”post body”}’, 200)); expect (await _postClient.fetchPost (client, 1), isA ());}); test (‘solicitação malsucedida’, () {cliente final=MockClient (); when (client.get (postEndpoint),).thenAnswer ((_) async=> http.Response (‘Não encontrado’, 404)); expect (_postClient.fetchPost (cliente, 1), throwsException);});}); }

Você pode executar os testes usando o comando:

flutter test test/fetch_post_test.dart

Ou você também pode executar os testes diretamente dentro do seu IDE. Quando executei os testes usando o VS Code, recebi este resultado:

Conclusão

O pacote http ajuda a realizar todos os tipos de solicitações de rede no Flutter. Ele também fornece suporte para Mockito que simplifica o teste de chamadas de API.

Se você deseja ter um controle mais avançado sobre suas solicitações, pode use o pacote Dio , que ajuda a evitar alguns códigos clichê e tem suporte para configuração global, interceptores, transformadores e outros recursos.

Obrigado por ler este artigo! Se você tiver sugestões ou perguntas sobre o artigo ou exemplos, sinta-se à vontade para entrar em contato comigo no Twitter ou LinkedIn . Você pode encontrar o repositório do aplicativo de amostra em meu GitHub .