Boas-vindas ao curso Flutter com Web API: Avançando na integração! Eu sou Ricarth Lima e serei o seu instrutor neste curso. Eu sou um homem de cabelos cacheados quase crespos, tenho a pele clara, uso um óculos que possui armação de cor escura, tenho um nariz grande, possuo uma barba espessa, e na maior parte deste curso usarei uma camisa na cor azul escuro.
Quais os pré-requisitos para este curso? É necessário ter visto dois cursos com antecedência:
O que produziremos neste curso? Construiremos um Diário, uma aplicação que possuirá telas com diversas funcionalidades:
Atenção: utilizaremos neste curso o Flutter versão 3.0.2 e o DART versão 2.17.3. É fortemente recomendado que você utilize as versões aqui listadas para evitar qualquer tipo de divergência entre o que será praticado no curso e em seu computador. Quando instalarmos as dependências, relembraremos as versões que estamos utilizando.
Quais as funcionalidades técnicas que aprenderemos neste curso? Vamos aprender a:
put
;delete
;Estou muito animado para continuarmos essa aventura com o Web API. Até o próximo vídeo!
Agora que conhecemos o funcionamento do curso, é importante entender o projeto que servirá de base para ele. Já que este curso é continuação direta de Flutter com Web API: Integrando sua aplicação, utilizaremos o projeto exatamente do ponto onde paramos no outro curso.
Antes de partirmos para o código e para o projeto rodando no emulador, é importante entendermos a API local que estamos utilizando desde o curso passado.
Por que usamos uma API local? Se utilizarmos uma API na Web, podem ocorrer alterações entre o momento da gravação desta aula e o momento em que você vai assisti-la, como por exemplo: mudanças na forma da integração, mudanças na forma da comunicação e até mesmo cobranças indevidas.
Estamos utilizando o JSON Server, um pacote do Node JS que possui uma API local juntamente com toda a comunicação e todos os testes que faríamos em uma API na Web, mas que faremos localmente em nossa máquina de forma segura. Caso você não possua este pacote, poderá revisar o conteúdo sobre instalação do JSON Server do curso anterior neste link.
Caso tenha interesse em se aprofundar no tema de API, recomendamos o seguinte material: APIs: Gerenciamento e Criação - Hipsters.tech
O banco de dados simulado pelo JSON Server pode ser encontrado no arquivo db.json
através do caminho "server > db.json" a partir da pasta raiz no diretório do nosso projeto. Conforme abordamos anteriormente, para rodar a API local, utilizamos o comando json-server --watch --host
+ seu endereço de IP + db.json
. Em caso de precisar reforçar os seus conhecimentos, é possível acessar o conteúdo sobre configuração do JSON Server do curso anterior neste link.
Agora vamos analisar o código do projeto funcionando. Com o emulador aberto, podemos visualizar a tela inicial de "Home" que simula um calendário diário onde ficam salvas todas as entradas feitas pela pessoa usuária. Podemos salvar essas entradas via API no JSON Server e recuperá-las para serem mostradas na tela.
Se clicarmos em alguma data que não possui entrada, somos direcionados a uma tela de preenchimento onde podemos digitar um conteúdo qualquer. Ao clicamos no botão de Salvar, a aplicação nos mostra o registro na tela já atualizada.
Como a aplicação funciona? Na tela do código, vamos acessar o explorador que fica na lateral da janela e examinar a a estrutura de pastas.
Observação: visualizaremos rapidamente os códigos pois eles não são o nosso foco no momento.
A pasta "database" foi empregada anteriormente para armazenar exemplos e não será mais utilizada. A pasta "helpers" contém auxiliadores que nos ajudam a mostrar de forma mais clara alguns conteúdos, como as frases aleatórias (que não serão mais utilizadas) e principalmente o arquivo weekday
que formata as datas em português.
A pasta "models" armazena somente um modelo por enquanto: o journal
, que representa uma entrada no diário. Cada entrada possui um uuid
, um content
que representa o conteúdo a ser escrito no diário, uma data de criação e uma data de alteração. O modelo também possui dois construtores: um deles cria o journal (ou diário) vazio enquanto o outro acessa os dados de um map (ou mapa) da Web API, transformando-o em um journal.
O arquivo journal
também possui dois métodos:
toMap
, que transforma um diário já feito em um map — este procedimento é útil para enviar informações à API;toString
que mostra o conteúdo de forma mais agradável.Pularemos a pasta "screens" por enquanto e seguiremos para a pasta "services". Nela existem dois arquivos:
http_interceptors
que possui interceptadores, os quais observam entradas e saídas de requisições HTTP e permite que as utilizemos. No caso do nosso projeto, utilizamos a biblioteca logger
para mostrar os dados na tela da melhor maneira possível, pois é importante que façamos verificações frequentemente;journal_service
onde ocorrem nossas transações com a Web API. Ele utiliza um client
do interceptador e se comunica com uma url
dentro de um resource
(que pode ser alterado posteriormente). Este arquivo também realiza o registro através do método post
e o getAll
através do método get
.Para utilizarmos os services acima, dentro da pasta "screens" existem duas pastas que possuem uma tela em cada. A pasta home_screen
armazena a tela inicial e é responsável por gerar a lista de entradas — que será atualizada quando necessário. Já a pasta add_journal_screen
armazena uma tela simples, responsável por adicionar novas entradas, gerar um novo journal e enviá-lo para a API.
Agora que entendemos em que ponto está o projeto que servirá de base para o nosso curso, implementaremos as novas funcionalidades. Vamos lá?
Quando clicamos em uma entrada já existente, não conseguimos lê-la — se for muito extensa — muito menos editá-la. Portanto, a primeira funcionalidade que adicionaremos será a de alteração. Para isso, devemos lembrar que cada bloco que aparece na lista é um journal card (ou cartão de diário), cuja responsabilidade é gerenciar o "clique". Através do explorador de arquivos, acessaremos arquivo do cartão seguindo o caminho "lib >screens > home_screen > widgets > journal_card.dart
".
Podemos acessar o código deste arquivo e visualizar a seguinte função:
se o journal entregue ao journal card for nulo, será exibida a versão simplificada do bloco com uma função implementada para o "clique". Mas se o *journal não for nulo, será exibida a tela formatada juntamente com o onTap
vazio*.
if (journal != null) {
return InkWell(
onTap: () {},
//Trecho de código omitido
} else {
return InkWell (
onTap: () {
callAddJournalScreen(context);
}
//Trecho de código omitido
Adicionaremos ao onTap
vazio uma chamada e salvaremos com "Ctrl + S".
if (journal != null) {
return InkWell(
onTap: () {
callAddJournalScreen(context);
},
//Trecho de código omitido
}
Se acessarmos o emulador e clicarmos em qualquer data, com ou sem registros adicionados, será aberta uma nova tela em branco, pois não estamos enviando os dados do registro para o método AddJournalScreen
. Nem sempre existirá um journal a ser recuperado pelo método, portanto estamos lidando com um parâmetro opcional que pode ou não ser nulo.
Voltando ao código, iremos até a linha 106 e acessaremos a configuração do método AddJournalScreen
. Nele criaremos um parâmetro opcional não nomeado que poderá ser nulo (portanto conterá ponto de interrogação): Journal?
. O nome desse parâmetro será journal
.
callAddJournalScreen(BuildContext context, {Journal? journal}){
Navigator.pushNamed(context, 'add-journal',
//Trecho de código omitido
refreshFunction();
}
Devemos entregar ao método pushNamed
um journal que poderá ser vazio ou com informações recebidas por parâmetro. Para isso, criaremos um innerJournal
(ou diário interno, em português).
callAddJournalScreen(BuildContext context, {Journal? journal}){
Journal innerJournal;
Navigator.pushNamed(context, 'add-journal',
//Trecho de código omitido
refreshFunction();
}
Se o diário que recebermos não for nulo, preencheremos o innerJournal
com as informações dele. Para tal, configuraremos um if
.
callAddJournalScreen(BuildContext context, {Journal? journal}){
Journal innerJournal;
if (journal !=null) {
innerJournal = Journal;
}
Navigator.pushNamed(context, 'add-journal',
//Trecho de código omitido
refreshFunction();
}
Para configurar o diário nulo, poderíamos criar um else
e inicializá-lo com os argumentos presentes no pushNamed
abaixo.
Navigator.pushNamed (context, 'add-journal',
arguments: Journal(
id: const Uuid().vl(),
content: "",
createdAt: showedDate,
updatedAt: showedDate,
)).then((value) { // Journal
refreshFunction();
No entanto, resolveremos de forma mais rápida, inserindo e inicializando o Journal
e também os argumentos do pushNamed
diretamente no innerJournal
. Eles passam a data, o content
vazio e geram um Uuid
. Além disso, vamos inserir o innerJournal
no lugar dos argumentos que movemos do pushNamed
. Em seguida adicionaremos vírgula e quebraremos as linhas para melhor indentação do código.
callAddJournalScreen(BuildContext context, {Journal? journal}){
Journal innerJournal = Journal(
id: const Uuid().vl(),
content: "",
createdAt: showedDate,
updatedAt: showedDate,
); // Journal
if (journal !=null) {
innerJournal = Journal;
}
Navigator.pushNamed(
context,
'add-journal',
arguments: innerJournal,
).then((value) {
refreshFunction();
}
Se o conteúdo for diferente de nulo, ele entrará no if
e haverá a substituição das informações iniciais pelos dados recebidos por parâmetro. Caso contrário, não entrará neste bloco e continuará a exibir o padrão inicial.
Vamos testar? No emulador, clicaremos em um dos cartões de diário que já contenham informações, mas a tela devolvida pela aplicação ainda está em branco. Isso ocorreu pois o callAddJournalScreen
ainda não foi preparado para receber informações externas.
Para resolver esse problema, voltaremos ao código e através do explorador acessaremos o caminho "lib > screens > add_journal_screen". Nele abriremos o arquivo add_journal_screen.dart
. Configuraremos o TextEditingController
para que a sua propriedade "text" seja substituída pelo innerJournal
assim que a tela for iniciada.
Dentro do nosso build
, adicionaremos o contentController
e o igualaremos ao journal.content
. Desta maneira, se entrarmos com um journal preenchido, as informações dele serão armazenadas. Caso contrário, se entrarmos com um journal vazio, ali será armazenada uma string vazia.
Widget build(BuildContext context) {
_contentController.text = journal.content;
return Scaffold(
Vamos conferir se deu certo reiniciando a aplicação e retornando ao emulador. Podemos ver que o problema ainda persiste graças à um detalhe que não configuramos ainda.
Voltaremos ao arquivo journal_card.dart
através do explorador e lembraremos do parâmetro journal
que passamos como opcional na configuração do método AddJournalScreen
.
callAddJournalScreen(BuildContext context, {Journal? journal}) {
Por ser um parâmetro opcional, quando recebemos um novo cartão diferente de nulo não estamos realizando a chamada com um journal
no build
. Nesta situação, devemos obrigatoriamente declarar o parâmetro journal
dentro do build
. Assim haverá o reconhecimento do cartão para que seja realizado o processo de envio. Não é necessário declarar esse parâmetro no código de cartão nulo.
@override
Widget build(BuildContext context) {
if (journal != null) {
return InkWell(
onTap: () {
callAddJournalScreen(context, journal: journal);
},
Vamos testar? Após essa configuração, salvaremos o código e voltaremos ao emulador. Quando clicamos em um cartão que possui informações, será aberta uma janela exibindo as informações do cartão.
Editaremos uma informação no emulador, salvaremos e voltaremos ao codigo. Nele abriremos a pasta "server" e acessaremos o arquivo db.json
e perceberemos que o código não foi alterado. Ao acessar o nosso Console de Depuração (ou logger) através do ícone na lateral esquerda, encontraremos o erro "id duplicado" conforme exibido abaixo.
Corpo: Error: insert failed, duplicate id
Este erro ocorreu o registro de um novo journal localizado no arquivo add_journal_screen
utiliza o serviço register
, que por sua vez utiliza o método post
. Ou seja, a applicação tentou criar um novo cartão ao invés de modificá-lo.
Se recorrermos aos nossos conhecimentos de HTTP, lembraremos que o post
não é utilizado para substituir, e sim o put
. Não podemos substituir o post
pelo put
, pois utilizamos o post
quando criamos os journals. Portanto, precisamos criar o put
em outro lugar do nosso serviço, ao mesmo tempo em que a tela de add_journal_screen
deverá possuir inteligência para discernir entre os métodos de editar e de criar. Realizaremos essa tarefa a seguir.
O curso Flutter com Web API: evoluindo na integração da aplicação possui 238 minutos de vídeos, em um total de 53 atividades. Gostou? Conheça nossos outros cursos de Flutter em Mobile, ou leia nossos artigos de Mobile.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.