Fala galera sejam muito bem-vindos à nossa última aula da semana Java na prática e na aula de hoje a gente vai completar o nosso projeto de redirecionador de urls né na verdade encurtador e redirecionador e a gente vai finalizar hoje com chave de ouro criando aqui a nossa última lambda que vai ser a responsável por redirecionar o usuário paraa URL orig final E além disso a Gente vai conhecer mais um serviço da WS que é o Api Gateway que vai ser o responsável aqui por ser a porta de entrada dessa nossa aplicação então sem mais
enrolações a gente já pode partir lá para nosso checklist das coisas que a gente vai fazer na aula de hoje certo e a primeira etapa aqui é realmente criar a nossa função lá na WS então a gente já pode abrir o nosso painel aqui da WS o nosso console e abrir aqui o serviço de lambda certo que tá aqui no meu visitado Recentemente não tiver aparecendo para vocês é só buscar aqui por lambda certo e abrir aqui o serviço né de funções Serv da WS esse caminho agora a gente já conhece né então a gente
vai clicar em criar uma nova função e a gente vai dar um nome para essa nossa função que vai ser redirect URL shorten né coloca aqui shner essa função vai usar um tempo de execução de Java 17 e aqui nos AD configurations a gente vai habilitar o URL da função e vamos colocar como Autenticação n certo qualquer um vai poder fazer a chamada aqui para essa nossa redirect Vamos então criar essa função né criar a infra dela aqui na WS né criar toda a estrutura pra gente já começar a criar o nosso código Enquanto isso
a gente já pode abrir no intelij inclusive E clicando aqui em criar um novo projeto né aqui ele já terminou a criação da da Lda e a gente pode clicar aqui em Create New Project e abrir a o dashboard Zinho aqui pra gente iniciar Um novo projeto o nome desse nosso projeto vai ser redirect URL shner né para seguir o mesmo padrão que a gente tinha criado lá pra nossa função de Create a linguagem eu vou deixar como Java build system é o maven jdk a mesma da aula anterior né a mesma que a gente
usou pra nossa função de Create e no Advanced settings a gente pode deixar o group ID como com. City ponto redirect URL shner e o artifact ID sendo redirect URL shner perfeito vamos clicar em Create e ele já vai criar aqui o projeto pra gente certo a estrutura Inicial e a gente já pode começar a fazer as nossas primeiras configurações a primeira delas claro vai ser atualizar o nosso maven para adicionar as dependências básicas aqui que a gente precisa da WS E para isso eu vou usar como base o nosso projeto certo da a lambda
de criação das urls encurtadas que a gente estava trabalhando nas últimas aulas então vou abrir aqui recent projects e vou abrir Essa nossa lambda né a nossa Create URL lambda E aí eu vou abrir numa nova janela então New Window vou pegar aqui a nossa janela certo pra gente usar como base pras dependências aqui no pum XML Então a primeira as primeiras dependências na verdade aqui que a gente vai adicionar é o Core e o Java log forj certo então vamos pegar aqui né que vem dentro do SDK wws e colocar aqui na nossa lista
de dependências a gente vai ter que criar o nosso objeto de dependen Então vamos abrir ele aqui e colar as nossas dependências certo Além disso eu quero trazer para cá também o nosso L boock né o nosso salvador aqui que ajuda na geração de código boiler Plate que mesmo que a gente não esteja utilizando muito né Depois se a gente fosse aumentar o código criar adicionar mais funcionalidades ele ia nos ajudar bastante certo vamos trocar já aqui o compiler Version para 17 pra gente não cometeu o mesmo erro que a gente teve na Outra aula
né E a gente já pode adicionar também as configurações de build né para adicionar o plugin aqui do maven para fazer a geração do build junto com as bibliotecas externas que a gente precisa ter no nosso package então aqui h embaixo do objeto de dependências a gente cola o nosso objeto de build e ele já já vai né ter todas as configurações aqui necessárias pra gente começar a criar o código aqui da nossa lâmbda Então vou dar um Reload aqui do Maven ele Já identificou que houve mudanças Pronto já mudou aqui agora a gente pode
entrar aqui na nossa classe m e estruturar a nossa função handle request né Para que ela receba os requests lá da nossa da nossa lambda Então esse método né vai ser um método público Por enquanto vai retornar void e a gente vai chamar de handle request mas a gente pode usar a mesma base do nosso outro método aqui da nossa outra lambda né e ele tem à essa carinha aqui na verdade é só a gente implementar a interface de request handler que vem dentro né do SDK daws então a gente implementa essa interface aqui na
nossa classe certo que ele já vai pedir ali Obrigatoriamente pra gente ter o método né configurado certinho o o método render request temos que adicionar aqui o map né que vem dentro do Java útil e aqui o que que ele tá dando de erro é né que o a minha classe Main ela não tem o método rend request Que recebe um contexto né implementado então vou pedir aqui para ele implementar para mim ele já criou aqui a implementação do método que por enquanto tá só retornando nul não tem problema mas já tá aqui com override
recebendo os parâmetros certinhos Então posso excluir esse aqui que a gente criou antes né e pronto já temos a estrutura inicial do nosso projeto pra gente começar a escrever nosso código então vamos lá no notion vamos dar o OK aqui nessa Primeira parte e vamos dar um ok também na configuração do projeto e agora vamos começar a lidar com a nossa requisição certo extrair os dados e recuperar as informações lá do S3 Então vamos voltar aqui pro intelij e começar a escrever a lógica da nossa função a primeira coisa que a gente vai precisar fazer
é obter o uuid que identifica essa url que é curta né Essa URL cada por qu vamos voltar aqui pro pro notion só para mostrar aquela imagem do desenho para vocês ã é O seguinte né a nossa função aqui de Create shorten URL ela gera um uuid para nós que vai né identificar Aquela nossa URL encurtada né unicamente aí a gente salva lá no S3 certo o um arquivo Jason que o nome desse arquivo é o nosso uid né o ID gerado com as informações da URL original e o Expression time pra gente conseguir recuperar
a informação da URL original a gente precisa do o ID por quê Porque quando o usuário né quando o cliente acessar a nossa aplicação o que Que ele vai fazer ele vai acessar a aplicação no nosso domínio barra o o o ID que a gente Jou para ele Essa é a URL encurtada que ele vai estar acessando né então a gente precisa recuperar essa informação para poder consultar né se esse uid se essa URL encurtada realmente existe buscando isso lá no S3 e da aonde a gente vai tirar essa informação bom a gente vai tirar
essa informação da requisição então o usuário vai fazer uma chamada para por exemplo né https do Pontos barra barra ã Nossa função lambda né aqui o domínio da nossa função pcom barra e aí o ID aqui certo essa vai ser a URL encurtada que ele vai acessar e que vai acionar a execução dessa nossa função Então a gente vai extrair essa informação aqui da URL certo que é um pef parm é um parâmetro de pef Então a gente vai extrair isso aqui que está aqui por enquanto né no nosso string Object map né que aqui
a gente pode até trocar um nome para input para ficar Mais claro então a gente vai extrai essa informação aqui do input que é o que veio ali tudo da request http que a gente recebeu do usuário incluindo né o pef então aqui eu vou declarar uma nova variável que vai ser uma string eu vou chamar de parameters né e basicamente o que a gente vai fazer é o input pget recuperando o valor de Raw pef né que seria o pef Crew e eu vou fazer uma transformação aqui um C para string Então eu vou
pegar agora minha short URL code que basicamente vai ser o meu PF paramit pon replace certo substituindo aqui o Barra por vazio porque o seguinte né voltando para aquele exemplo aqui https do P Barra Barra Vou botar aqui hello world né que seria qualquer domínio comom aí o id o que que a gente vai receber aqui a gente vai receber o o oid certo quando a gente extrair aqui o Raw pef ele vai nos retornar tudo isso Daqui ó O Retorno desse Raw pef né o a gente pegar ã aqui o objeto rwf de dentro
do nosso input vai nos trazer essa informação que tá no formato de string aí a gente vai fazer um replace desse dessa barra por vazio para pegar somente o o o ID que com esse uid a gente faz as consultas lá no S3 certo e agora a gente vai adicionar uma validação né então a validação que eu vou fazer é se esse short URL code existe né então se o Short URL code for igual a n ou for igual a empty eu vou lançar uma nova exceção uma exceção de illegal argument Exception né que o
argumento é inválido e basicamente eu tô dizendo aqui que eu preciso desse desse short your L code para funcionar se isso não vier na requisit certo eu vou lançar uma exceção porque eu não tenho como continuar a partir daqui e agora o que a gente vai fazer bom agora a gente precisa consultar Essas informações lá no S3 mas pra gente fazer isso a gente precisa né de um cliente do S3 e pra gente criar um cliente do S3 a gente precisa do SDK da WS específico ali do serviço do S3 Então a gente vai ter
que adicionar no nosso pun XML mais uma dependência que a gente ainda não tinha adicionado a gente tinha adicionado a dependência de logs e a dependência do do Java Core aqui pras lambdas né mas a gente precisa também adicionar dependência do S3 igual a Gente fez na nossa outra função então eu vou abrir aqui a nossa Create URL lambda vou abrir o p XML dela e a gente pode copiar aqui também a dependência do S3 certo pegar exatamente aqui a mesma versão a mesma dependência e só colar aqui embaixo o maven ele já vai identificar
aqui a gente já vai dar um Reload para ele fazer né a instalação dessas dependências e agora aqui no nosso código a gente já pode seguir então eu vou declarar aqui um novo Atributo para essa minha classe né que vai ser final que vai ser o meu S3 client certo vai ser do tipo S3 client e aqui vai ser o meu S3 client né chamando S3 clientbuilder P build igual a gente fez na outra lâmbda e aqui eu tenho que importar esse S3 client da biblioteca da WS ele não tá encontrando aqui então vou tentar
importar na mão com pon software é realmente ele não pegou aqui então vamos ver se ele instalação vou dar um Reload aqui no Maven vamos ver se ele tá aqui as dependências hum software amazon É parece que tá tá aqui tudo certinho vamos tentar de novo né vamos ver aqui se ele não tá rateando ah na verdade não é com né direto software é por isso que eu tô me confundindo aqui é o o group ID é direto software.amazon.aws SDK os outros que são com. Amazon aqui software Amazon P awssdk Services ps PS3 client Beleza
o CoPilot aqui já matou a charada pra Gente perfeito aí agora aqui embaixo o que que a gente vai fazer a gente vai pegar esse S3 client para fazer uma requisição de get lá no nosso Bucket para isso a gente precisa montar uma request de get né então a gente vai fazer que nem a gente fez na outra função na Create your L lambda a gente criou uma request de né um Object request agora a gente vai criar uma get Object request então aqui vou criar uma nova variável do tipo get Object request e vem
aqui dentro do S3 também então deixa eu importar aqui o meu get get Object request importar aqui o meu Model pon getobject request perfeito e agora que eu já posso chamar de get Object request fazendo né chamando ponto Builder ponto Bucket que vai ser o nome do nosso Bucket aqui que ele deve usar para consultar ponto Key Né qual é a chave Qual é o nome do arquivo que ele deve buscar de lá e o nome desse arquivo é o meha meu o ID mais a extensão pon Jason né porque é um arquivo Jason pon
build só que aqui o Bucket name ele chutou aqui pra gente né tá bem parecido na verdade com o nome real mas eu vou salvar isso numa variável eu acho Ou a gente pode deixar aqui direto acho que lá no outro a gente deixou direto é deixamos aqui direto então podemos deixar também só o nome Aqui que a gente tem que atualizar porque é URL shorten Storage lambda galera antes da gente continuar a f do Futuro tá passando de novo para lembrar uma coisa para vocês ao longo de toda essa aula a gente vai precisar
mencionar o Bucket que a gente criou na aula passada e eu preciso que vocês lembrem de usar o nome do Bucket exatamente como vocês criaram então lembrando né que vocês não puderam utilizar o mesmo nome que eu dei ao meu Bucket a gente tem que Criar Bucket com nome exclusivo se a gente tiver dentro da mesma partição então é muito importante que ao longo da aula vocês lembrem disso e utilizem exatamente o nomezinho do Bucket de vocês então aqui eu criei alguns buckets de teste né só para reena isso para vocês lembrarem de usar exatamente
o nome que vocês deram pro Bucket de vocês seja URL shorten Storage URL shorten S3 Bucket e um hash né aqui eu criei com um hash para dar um exemplo seja uma outra Variação seja um nome que vocês colocaram diferente enfim lembrem de usar o nome que vocês deram se vocês não lembrarem qual o nome que vocês deram é só vir aqui na WS entrar no Amazon S3 né entrar aqui dentro do serviço do S3 que vai ter a lista de todos os buckets de vocês aí Vocês conseguem lembrar certinho o nome o nome do
Bucket Beleza agora bora continuar certo então vou colar aqui o nome correto perfeito Montamos o nosso get Object request Agora o que a gente vai fazer a gente vai declarar uma nova variável que vai ser do tipo input string que vem dentro do Java io mesmo eu vou chamar de S3 Object string por quê quando a gente recupera um arquivo lá do S3 a gente basicamente vai fazer um stram né a gente vai pegar esse arquivo e vai pegando partezinha dele pacotinhos e juntando né para formar o objeto final e depois quando a gente for
ler esse arquivo a gente vai ter que transformar Esse stram de pacotinhos num arquivo né porque o que a gente foi recebendo foi vários pacotinhos né de informações que compõem o arquivo final e aí por isso que a gente tem que declarar uma variável aqui do tipo input stram e eu CoPilot aqui de novo já foi ligeirinho pra gente então o que a gente vai fazer basicamente S3 client né o cliente D3 que a gente declarou aqui ponto get Object passando o Object request né é o request que a gente quer executar e ele Vai
nos retornar aqui um string né um input string que a gente tá salvando aqui na nossa variável de Object string Se der algum erro no momento de recuperar esse arquivo lá do S3 ou seja esse arquivo não existe ou o nome do Bucket tá errado ou algum motivo né nesse sentido ele vai estourar uma exceção e aí essa exceção eu vou capturar ela e vou lançar uma nova exceção de runtime dizendo que deu o erro né Na hora de recuperar aqui na Hora de recuperar os dados do S3 certo então a gente já mapei aqui
uma nova exceção e agora o que eu vou fazer é criar uma nova ã vari do tipo URL data certo que vai ser o dado da minha URL E aí eu vou pegar essa informação de URL data de dentro do meu Object stram né que basicamente aqui esse URL data é as informações lá de original URL e exploration time da mesma forma que a gente tinha criado aqui pra nossa função de Create shner URL né Essa classe aqui URL data que contém as informações de original URL e o expiration time per como sim Da onde
tu veio essa classe o que que é isso o que que tá acontecendo lembra né que nessa função aqui na função que a gente salvou as informações no S3 a gente salvou essas informações no formato de Jason e esse Jason nada mais é do que um objeto um objeto do tipo URL data né a gente criou um objeto que tem esse formato aqui que tem esses dois Campos o campo original URL e Exploration time agora quando a gente recuperar esse Jason lá naquela Nossa outra função certo na função que a gente criou agora a gente
vai ter que transformar esse Jason num objeto aqui do Java e esse objeto é o objeto your L data a gente vai declarar essa classe aqui também a gente poderia nomear ela com outro nome então por exemplo a gente poderia nomear como ã original URL data sendo o nome da classe tudo bem certo isso aqui tá tudo bem não precisa ser o Mesmo nome que a gente deu aqui nessa outra função eu tava usando o mesmo nome só para facilitar certo para ficar claro pra gente que é o mesmo valor que lá numa ponta a
gente salvou e nessa outra ponta a gente tá recuperando certo então a gente pode inclusive copiar essa classe aqui URL data e voltar aqui para nosso projeto né e criar uma nova classe aqui ao lado da nossa classe Main vou chamar de URL data e colar aqui as informações dessa classe né que Basicamente é ela tem esses dois Campos original ur e expiration time e aqui usando algumas anotações do do lombok como os getters os setters e o All ARS constructor Beleza agora a gente vai ter que transformar esse string num objeto desse tipo aqui
como é que a gente vai fazer isso a gente vai ter que usar o Object mapper da mesma forma que a gente usou na outra função certo então aqui o o Pilot de novo já completou pra gente a gente vai usar o Object mapper para ler O valor que tem aqui nesse string certo ler esse Jason e então transformar esse Jason numa classe Java que é essa classe your Aldira e a gente vai usar o Object Map para isso né a gente tá basicamente aqui fazendo a desserialização desses dados Então a gente vai ter que
adicionar de novo aqui a dependência do Jackson Core né a dependência aqui de de data binding do Jackson Core então vindo aqui pro pun XML da nossa função de novo eu tô copiando os as mesmas dependências Que a gente tinha criado pra nossa outra função tô colocando aqui na na função agora de redirect certo e acaba ficando as mesmas dependências né exatamente as mesmas nem nem uma mais nem uma mesma nemum a mais nemum menos a gente tá com exatamente as mesmas dependências aqui e agora lá em cima na nossa Classe A gente já consegue
mapear essa nova dependência como é que a gente vai fazer da mesma forma que a gente fez antes então Private final vai ser um objeto do tipo Object mapper certo que vem dentro de Jackson Core a gente já vai importar eu vou dar o nome de Object mapper também e eu vou fazer basicamente um New Object mapper instanciando né uma nova Estância dessa classe ja mapper isso aqui vem de dentro né do da biblioteca do Jackson Core então importe aqui de né então se o exploration time não foi atingido E se ele não tiver sido
atingido quer dizer que ela tá válida então a gente pode fazer o redirect Então aqui eu vou criar uma nova variável né do tipo long vai ser o tempo atual em segundos e aqui então a gente tá transformando em segundos porque lá na outra aula né quando a gente salvou a informação do expiration time a gente salvou essa informação em segundos né A gente só fez o parce ali do que a gente recebeu na requisição e salvou em segundos essa informação então por isso que aqui quando a gente pega o current time que a gente
tá pegando em Milissegundos a gente tá transformando com segundos para conseguir fazer a comparação correta aqui né se a gente pegar por exemplo current time em milissegundos e o tempo salvo lá né na informação original em segundos a gente não vai conseguir fazer uma comparação certa né que a gente vai estar comparando milisegundos com segundos Então a gente tem que fazer essa transformação dividindo aqui por 1000 porque dessa forma vai dar um match aqui Com a informação que a gente salvou na outra lambda né quando a URL encurtada foi gerada que a gente salvou a
informação em segundo certo então continuando aqui meu current time em Seconds e ele tem que ser menor do que o meu URL data pon get exploration time e aqui ele tem que ser menor por quê Porque o nosso tempo atual certo o momento o instante que eu estou agora ele não pode ter Passado o instante de quando essa URL Vai expirar porque imagina o seguinte a gente vai receber um time stamp certo na requisição vou botar um time stamp aleatório aqui E esse time stamp ele se traduz por exemplo pro dia 20 de outubro certo
só que o dia de hoje é o dia por exemplo 17 de outubro então quando eu pegar o time stamp do dia de hoje ele vai ser um outro time stamp que eu vou traduzir para essa data aqui esse time stamp ele É maior do que esse porque ele representa um um dia que é depois certo ele representa um instante depois desse instante aqui que acontece depois então quando eu fizer a comparação eu quero que o tempo atual em segundos ele seja menor do que o tempo quando essa URL Vai expirar porque eu quero que
na requisição o usuário né no caso ali pode ser o frontend da nossa aplicação ele me envie a data né em time stamp de quando a URL Vai expirar ou seja até quando ela Fica válida né então ela fica válida até o dia 20 de outubro até o dia 30 até o dia 5 de novembro e por aí vai E se o dia de hoje ele for menor do que o dia com que aquela URL vai esperar quer dizer que ela ainda tá válida certo só para vocês entenderem aqui a comparação que a gente tá
fazendo beleza e aí o que que a gente vai colocar aqui dentro do nosso if bom a gente vai colocar a resposta que a gente vai retornar pro usuário caso a URL esteja válida então Caso ela esteja inválida a gente já coloca o tratamento aqui embaixo Mas a gente tá tratando o caso onde a URL está válida e o que que vai acontecer a gente vai redirecionar esse usuário como é que a gente vai redirecionar ele a gente vai retornar uma resposta para ele certo contendo o status code de 302 que quer dizer o status
code de redirect E além disso a gente vai adicionar um campo no header certo que vai ser o campo de location esse campo location vai ser ser O campo que indica a URL na qual a gente vai est fazendo o redirecionamento do nosso usuário então através do status code 302 e do header location a gente vai conseguir com que a própria resposta que a gente envia pro nosso usuário já faz ele ser redirecionado automaticamente pelo browser certo o browser vai identificar aquela resposta como algo que ele deve fazer um redirecionamento Inclusive eu vou abrir aqui
o Google e vou mostrar para vocês Né status code em gatinhos né para vocês verem esse status code que eu tô falando para quem ainda não conhece então a gente vai usar esse daqui ó o 302 que é o found certo e que a gente vai fazer uma uma um redirecionamento então aqui se a gente vê a descrição desse status code ele diz o seguinte ó o status code 302 significa né o status de redirect que indica que aquele recurso ã que foi requisitado ele foi temporariamente né movido para outra Url que vai ser fornecida
no header de location então isso significa que o recurso que o usuário buscou foi né movido para uma outra URL e essa URL em específica tá sendo né fornecida ali no location header então o browser né automaticamente vai redirecionar para essa página certo ele vai fazer esse redirect certo pra gente então é assim que vai funcionar aqui a nossa aplicação Quando a gente tiver o Mat do uid e essa URL tiver válida a gente vai retornar Essa resposta então aqui a gente vai criar um novo objeto que vai ser do tipo map né que vai
ser aqui um map de string para objeto né a gente vai retornar aqui um um um mpp contendo Chaves que são string e Valores que são objetos é aqui eu vou chamar de response eu vou fazer um New Rash map da mesma forma que a gente fez na nossa outra função e aí eu vou pegar esse meu response e vou primeiro colocar nele né um campo que vai ser o nosso status code status code E o status code que a gente vai passar aqui é o 302 certo status code 302 além disso a gente quer
criar um novo objeto do tipo headers que a gente vai colocar dentro desse nosso response então aqui eu vou criar um novo map que agora vai ser de string para string né vai ser um um objeto nesse formato aqui contendo valores no tipo string e contendo Chaves no tipo string e valores no tipo string que basicamente vai ser o nosso location e aqui a URL original certo vai ser o Formato desses nossos headers por isso que a gente tá criando agora um map de string para string esse nosso outro map que representa a nossa response
basicamente a gente tá dizendo que tem Chaves do tipo string né Chaves do tipo string só que valores né do tipo objeto e aqui no caso vai ser né o nosso header aqui beleza então Aqui Nós criamos uma nova variável que eu vou chamar de headers e eu vou fazer um New hashmap eu vou fazer fazer headers.put location Passando aqui o rld data.get original URL e vou fazer aqui também headers PP não acho que é só esse só esse header aqui mesmo que a gente quer passar eu vou fazer então response PP headers né incluindo
aqui os headers na response então fazendo um return response esse aqui é o nosso caso feliz qual que é o nosso caso de erro certo Qual que é o nosso carro caso aqui Qual que é o qual que é o tratamento que a gente vai adicionar aqui caso a URL Esteja inspirada bom a gente vai adicionar uma resposta parecida com essa só que ao invés de retornar aqui um header location a gente vai colocar outra informação certo a gente vai colocar uma informação no B dizendo que aquela URL Tá inspirada e vamos trocar o status
code só que antes para ele parar de dar erro aqui pra gente a gente precisa trocar aqui o return Type do nosso método do nosso método render request não vai ser mais string para String vai ser string e objeto certo a gente vai retornar um map contendo H Chaves Strings valores objetos aí ele para de dar erro então aqui embaixo a gente vai montar né o caso defo que é quando essa URL Tá inspirada ou ela não foi encontrada enfim o que a gente vai fazer é basicamente criar um objeto Nesse estilo aqui também né
só que aqui pode ser é perfeito assim um response aqui o status code vai ser 410 né E a gente vai colocar aqui um Body também nessa resposta então eu vou fazer um response response PP passando aqui o BO né e a URL expirou então this URL Na verdade essa URL Pou e aqui eu vou retornar esse response certo Inclusive eu poderia declarar o response aqui em cima né para não precisar ficar declarando ele duas vezes então poderia fazer dessa forma e aqui eu só retorno direto Inclusive eu posso melhorar ainda mais esse código então
Aqui ao invés de eu fazer uma cláusula que quando ela der verdadeira vai ser o o cenário Positivo eu posso fazer uma cláusula de guarda né que eu quero que ela dê negativa para colocar o erro e caso ela não dê negativa quer dizer que deu o caso positivo então a gente pode fazer o seguinte ó em vez de fazer a comparação de que o current time em Seconds tem que ser menor do que o RL data P get expiration time eu poderia inver eu poderia dizer que o URL Expiration time né tem que ser
maior do que o current time in Seconds Isso quer dizer quer dizer tem que ser menor do que o current time em Seconds Isso quer dizer né que a URL expirou E aí entraria nesse caso aqui de que a minha URL expirou né nesse cenário aqui e aí eu poderia botar um ELS ou só retornar aqui direto response que nem a gente tinha feito né Eu só basicamente inverti a lógica aqui certo coloquei uma cláusula de guarda porque esse aqui Seria o cenário né aqui ó vou até mapear para vocês é o cenário onde a
URL expirou pois né Por que que ela o inspirou porque o exploration time tá sendo menor do que o current time certo e aqui é o cenário feliz então Aqui se chegar nessa parte do código quer dizer que ele já passou aqui por esse if e não deu o match ali então aqui é o cenário onde a URL ainda é válida E aí eu tô retornando n e fazendo redirect então perfeito acho que aqui da nossa lógica Que a gente tinha que fazer tá tudo certo e aí vamos só ver aqui o que que ele
tá dando de erro porque eu não posso retornar um string Object aqui por que que eu não posso retornar um string Object Ah porque aqui no mapeamento eu coloquei map de string para string então aqui eu tenho que mudar certo colocar que ele retorna oping Object e agora sim ele para de dar erro então a gente tem que atualizar aqui o mapeamento tanto na implementação da Interface né onde eu tô mapeando a entrada e a saída né aqui ó entrada certo entrada e entrada tô fazendo mapeamento do tipo Genérico e aqui o mapeamento da saída
E aí tem que dar um Mat aqui com o mesmo return Type do Meu método e aí ele para de dar erro perfeito então a gente pode gerar o package já desse nosso projeto né então vamos abrir aqui terminalzinho do maven fazer um mav and Clean package para gerar o package Desse nosso projeto e Então nós vamos subir esse nosso arquivo jar lá na WS e começar a fazer os testes para ver se a nossa lógica Tá funcionando então vou voltar lá pro nosso dashboard da WS certo aqui dentro da nossa função lambda que a
gente acabou de criar e a gente vai fazer aqui o upload do nosso arquivo jar certo do build aqui da nossa aplicação que a gente acabou de gerar vamos esperar aqui ele subir e atualizar função e aí né Assim que ele fizer a atualização a Gente precisa mudar mais uma configuração aqui na nossa função antes de começar a testar ela e depois discutir sobre o Api Gateway certo que é aqui a atualização das permissões da nossa função mas vamos esperar que ela terminar de subir o código pra gente mexer nisso então pronto ele já tá
atualizando aqui a função certo e a gente pode entrar aqui nessa aba de configuração para acessar a role dessa nossa função e como vocês podem ver ó Ele gerou uma rle nova para ela que é essa role redirect eurl shorten role certo a gente vai abrir essa role aqui numa outra aba né eu cliquei aqui no control e cliquei no no link né porque esse aqui é um link pra gente anexar uma política também nessa função que permita né que ela abra lá o Bucket faça o get dos objects Inclusive a gente pode voltar aqui
pra aba das lambidas e abrir aqui as nossas funções pegar generate shner URL pegar Roll dela também abrir Aqui numa outra página pra gente usar como base certo a gente vai vir aqui vamos adicionar permissões e vamos criar uma política em linha para essa função aqui certo o serviço vai ser o S3 perfeito aí a gente vai permitir leitura somente então aqui eu vou botar como get Object certo ele só pode recuperar objetos só fazer esse método aqui mesmo e aí eu vou colocar aqui que os recursos né Vamos definir aqui os recursos pode ser
qualquer Object name No Bucket ali específico que é o Bucket aqui deixa eu recuperar o nome do Bucket também certinho pra gente não errar é o URL o shner Storage lambda então a gente volta aqui né na criação da política cola o nome do Bucket e ele já faz o mapeamento aqui da arn do recurso nós vamos adicionar essa arn perfeito e a gente pode inclusive adicionar aqui não acho que tá tudo certo vamos próximo ah deixa eu voltar esqueci de uma coisa Na verdade aqui no Jason no resources a gente pode fazer a mesma
cois que a gente fez na política da nossa outra lâm colocar uma ar rei e permitir para ele o acesso ao Bucket e o acesso a todos os objetos do Bucket para evitar qualquer problema aqui então podemos copiar o resource aqui e colar no Jason então eu troquei do daqui do visual para a visão de Jason né pra gente conseguir editar a política em formato de Jason e eu colei aqui a configuração do resource certo Porque aqui querendo ou não as duas funções né acessam o mesmo Bucket é basicamente a mesma permissão aqui que eu
tô dando pras duas só que separado Porque caso uma tenha que fazer uma coisa e a outra não tenha permissão né Elas não ficam dependentes elas são totalmente Independentes aqui nas suas permissões E caso precisa atualizar atualiza de uma ou de outra né dependendo ali das funcionalidades de cada uma das funções no nosso caso elas Por enquanto tem a mesmo permissão mas caso projeto evoluísse Pode ser que uma poderia ter a permissão para fazer uma coisa enquanto a outra continuaria com essa permissão Inicial aqui que a gente criou certo essa permissão mais básica então vamos
dar aqui um próximo Vamos dar um nome pra política vou dar um nome bem parecido então acess né Bucket nã Vamos criar a política esperar aqui ela criar e beleza anexou aqui a política a nossa função de redirect your shner Perfeito Então deixa eu fechar aqui os as abas do e M certo quero editar beleza e agora eu vou voltar lá para minhas lâminas voltar pra minha função de redirect your Air shner e eu vou copiar a URL dela certo Por que que eu vou copiar a URL dela bom porque a gente vai testar a
gente vai colocar ela em prática agora a primeira coisa que eu quero fazer é colar o URL dela aqui e colocar um o ID aleatório tá vou colar aqui vou botar qualquer valor para Fingir que fosse um ID porque eu quero ver ela dando erro primeiro porque porque ela vai dar erro porque ela não vai encontrar esse o ID lá no S3 então aqui ele já deu internal server error se a gente abrir aqui o cloud watch né monitor e visualizar os logs do Cloud watch ele era né para tá mostrando ali que ele não
encontrou essa informação lá no S3 se tiver qualquer outro erro diferente desse a gente já sabe que tem mais alguma coisa pra gente ajustar aqui Ele deu um erro de ah Class not found então perfeito esquecemos de atualizar o handler também então aqui Lembra nas configurações da nossa função além de subir o código a gente tem que atualizar o nosso handler né O que que é o handler quando o gatilho for acionado seja o gatilho através de URL ou seja através de outro serviço da WS quando ele for acionado e trigar a execução da nossa
função para a WS saber qual classe ela deve instanciado do nosso código e qual É o método dessa classe que ela deve chamar a gente deve mapear isso aqui no manipulador no Ren Então tem que vir aqui e editar o handler certo qual que vai ser o handler dessa nossa função bom vai ser o nome lá Do nosso package então é com. Rocket City ponto deixa eu copiar lá certinho para não errar aqui na escrita mas é redirect URL shner aqui redirect URL shner certo o nome da nosssa classe é Main e o método é
o Rand request Então vamos Salvar esperar ele atualizar perfeito atualizou vamos voltar aqui pro Cloud watch e vamos tentar acessar essa nossa função de novo né Ele é para continuar dando erro mas é para ser um erro diferente né para ser o erro que ele não encontrou esse o ID lá no S3 beleza intern server error vamos dar aqui uma atualização mais um grupo de logs e agora perfeito ó error fetching data from S3 né agora ele tá dizendo que o usuário não tá atualizado não está Autorizado para listar o Bucket então mais um erro
nosso lá vamos lá nas permissões nas configurações né do Nossa da nossa função e vamos atualizar as permissões pelo jeito eu coloquei ali a né o método get Object mas não é esse método aqui que a gente deveria colocar é o método list Bucket né que ele disse aqui vamos ver o bom que a gente vai debugando e vocês vão aprendendo aqui como né ir lidando com as coisas aqui dentro da WS Né como é que a gente pode fazer o debug como é que a gente vai atualizando essas permissões eu até prefiro às vezes
que aconteçam bugs porque a gente sabe que no nosso dia a dia quando a gente tiver programando não vai ser 100% né tudo certo a gente não a gente sempre enfrenta algum problema a gente poucas vezes vai acertar tudo de primeira vez Então é bom que a gente vai pegando aqui alguns erros eu já vou aproveitando para explicar mais algumas coisinhas então eu Achei ó que era só a gente adicionar né o a ação de get Object Mas pelo jeito ele também precisa da permissão de list Bucket né para fazer a leitura lá então não
tem problema a gente vem aqui em editar política de forma visual vamos editar essa ação e aqui nos níveis de acesso de lista eu vou adicionar esse list Bucket também que foi o que ele disse lá que não tinha permissão então list Bucket próximo salvar alterações perfeito Espero que tenha Atualizado né l a função load aqui só para ter certeza Vamos acessar de novo a URL fechar aqui as permissões deixar só o cloud watch aberto perfeito Vamos acessar o URL de novo vou fechar aqui o nosso http Cat acessar de novo intern ser error beleza
vamos ver se é o erro que a gente tava querendo né até então não foi o erro que a gente estava buscando ele não atualizou ainda aqui os log Vamos dar um Reload mandar a requisição de novo só para ter certeza beleza ele concatenou aqui show então ah agora sim ó error fetching data from S3 the specify key does not exist Agora sim deu o erro que a gente queria né Ele tentou buscar por um arquivo né com esse valor aqui esse o ID né que eu que eu passei e não encontrou que era exatamente
o que a gente queria agora sim tá tudo certo então vamos testar agora se o redirect tá funcionando para Isso a gente vai copiar de novo a URL da nossa função e vamos não podemos deixar aqui no navegador mesmo mas eu vou abrir o insônia pra gente cadastrar certo uma url lá no nosso Jason uma url com exploration time que seja posterior ao dia de hoje né que esteja válido ainda pra gente conseguir testar se o redirect vai estar funcionando Então agora eu vou abrir o meu insônia pra gente testar certo se a nossa lambda
de red rect tá funcionando só que pra Gente conseguir testar a gente vai ter que inserir uma url válida lá né chamando a nossa função de generate então aqui eu vou trocar o regin l para ser o meu próprio site Então vou botar aqui https 2 bar bar Fernanda Keeper Fernand ker com barra links certo e aqui o exploration time eu vou trocar pro time stamp de agora onde eu vou pegar esse time stamp eu vou procurar aqui pelo app converter certo Que converte aqui uma época para time stamp e eu vou escolher o dia
de amanhã então Deixa eu escolher aqui não escolher aqui direto né o dia sei lá aqui o dia 20 de outubro certo gerar o time stamp né o time stamp aqui em segundos novamente né a gente tem que tomar muito cuidado para não enviar em milissegundos a gente tá tudo tratando em segundos lá no nosso backend então cuidado com isso aqui porque pode dar erro né Vamos pegar o timestamp em Segundos colar aqui o timestamp E aí a gente vai cadastrar ele lá no nosso S3 eu vou clicar aqui em enviar certo para enviar a
requisição lá paraa nossa lambda de geração de URL em Curt ela vai nos retornar um código e agora a gente vai pegar esse código e vai usar ele para fazer a consulta aqui na nossa lambda de redirect certo e era para dar tudo certo então vamos acessar aqui vamos ver o que que vai acontecer né esperando aqui ele Retornar não retornou erro que já é algo positivo agora deu Inter eror vamos ver o que que rolou aqui vamos abrir os nossos logs Ah tá aberto aqui vamos ver o que que aconteceu ele disse né que
não conseguiu derealizar a informação que foi salva lá no nosso S3 vamos dar uma olhada no formato com que o objeto foi salvo lá dentro Vamos abrir aqui o S3 e vamos abrir o nosso Bucket de URL shner lambda perfeito vamos buscar aqui pelo o ID que a gente acabou de salvar pegar aqui informação vou fazer o download né e vou abrir aqui esse TXT aqui Perfeito original URL e exploration time beleza Ah já sei que pode ter rolado aqui ó quando ele tentou vamos ver o nosso elira não tá como long is aqui é
a nossa redirect beleza parece tudo certo deixa eu ver de novo aqui o erro né erro ao desserializar São no Creators like default Ah tá foi porque a gente esqueceu aqui ó de colocar um no args constructor na nossa classe Então ela tem que ter um no args constructor para quando ele for fazer a dester realização né ele conseguir inserir ã ele criar um novo objeto e depois inserir cada dado né um de cada vez Então assim já deve resolver o nosso problema vamos fazer aqui um update do nosso package né É só adicionar o
no ARS constructor aqui na nossa classe your L Data vamos voltar aqui pra função lambda deixa eu abrir aqui ó lambda e vamos atualizar o nosso código e mas já é um bom sinal né já quer dizer que ele conseguiu encontrar o arquivo lá do S3 então eu já vejo né como um avanço vamos pegar aqui o nosso jar pegando aqui o errado beleza vamos enviar ele pronto ele tá atualizando já aqui a função né atualizando o nosso código vamos esperar ele terminar pra gente Conseguir testar novamente Então pronto ele atualizou aqui beleza vamos tentar
acessar de novo Vamos dar um novo request aqui Enviar uma nova requisição vamos ver o que vai acontecer pronto ó agora sim ele redirecionou para URL original certo então de novo vamos vamos ver a mágica acontecendo é sempre bom ver quando dá certo então colar aqui a nossa URL certo e acessar através do id E aí ele já redireciona aqui para URL original então Perfeito a nossa lógica tá funcionando e agora falta bem pouquinho pra gente terminar a nossa aplicação então Recebemos a requisição extraímos o id acessamos o S3 validamos o exploration date e redirecionamos
para URL original testamos a nossa função e agora para finalizar com chave de ouro a gente vai criar um epi Gate que vai concentrar as nossas requisições porque uma coisa que vocês devem ter percebido é que pra gente fazer a geração de uma url Encurtada a gente teve que chamar um domínio né específico que era o domínio lá da nossa lambda de generate só que para acessar para acessar o RL encurtada a gente teve que acessar outro domínio né esse domínio aqui tivemos que fazer a requisição para ele então a nossa aplicação ela não tá
concentrada num lugar só e o que a gente vai fazer é utilizar o epi Gateway para ser uma porta de entrada da nossa aplicação então o ap gator vai receber as nossas Requisições tudo em um mesmo domínio e então vai repassar essas requisições aqui pras nossas funções lambda certo então vamos ver a mágica acontecer então vamos voltar lá pro nosso dashboard da WS e vamos criar o nosso api Gateway certo e eu já vou explicar aqui para quem ainda não conhece o como é que funciona esse serviço então o Api gator da WS ele é
como se fosse uma interface certo para que a aplicação do cliente ou seja o Frontend quando ele acione a nossa api certo ele se comunica aqui com os nossos serviços do backend de uma forma mais segura e eficiente então aqui o nosso IP Gate no nosso caso ele vai servir como um porteiro né ele vai concentrar ali todas as requisições do cliente e vai encaminhar essas requisições pro nosso backend né então aqui ó de novo ele vai servir como um porteiro recebe as requisições do do front né do cliente pode ser o front pode ser
o insônia Enfim e aí ele vai H encaminhar essas requisições aqui paraa lambida específica que que tem que tratar dessa requisição mas ele não funciona só com lambidas né a gente pode ã atrelar api gateways a outros serviços da WS como por exemplo servidores ec2 inclusive banco de dados né contêiners ã usando ecs por exemplo então a gente consegue criar esse porteiro aqui aqui para concentrar nossas requisições E então depois destinar elas né pros nossos Serviços eh corretos aqui do backend e como a gente tá trabalhando numa função seress né numa arquitetura servas ã a
gente tá criando uma arquitetura que é totalmente independente a gente tem as duas funções ali que não se conhecem que estão rodando em locais diferentes e a gente tá usando aqui o Api Gateway para concentrar elas num único domínio né E aí h a gente vai ter end points diferentes ali para acionar cada uma delas mas na visão de fora é como se Fosse uma única coisa certo é como se fosse uma única aplicação então agora a gente vai aqui dentro do API gat a gente vai clicar aqui em API htp certo é uma API
rest que a gente vai criar E aí esse essa opção aqui que a gente vai escolher Então a gente vai compilar uma nova api certo uma API aqui do estilo http e o nome dela vai ser URL shorten api certo vai ser a nossa api aqui de encurta encurtamento de urls vamos avançar por enquanto eu vou deixar aqui Vazio as rotas certo então vamos avançar aqui os estágios vamos deixar os defaults também e vamos clicar em criar certo vamos criar aqui a nossa api E agora vocês vão ver que a a configuração aqui das rotas
na nossa api vai ser Super Simples então a gente vai vir aqui ó a gente já tá com a ap criada certo vamos criar uma nova rota essa rota vai ser do tipo post e vai ser pra Barra Create certo nós vamos criar aqui E esse post aqui ele vai Redirecionar para algum lugar para algum lugar então a gente vai fazer uma integração vamos anexar uma integração vamos aqui Criar e anexar uma integração e vai ser uma integração com uma função lambda que função lambda vai ser essa vai ser a nossa função generate shner URL
E aí aqui a gente vai né automaticamente conceder permissão ao API para invocar a função lambda né então aqui ó ele já tá especificando ó quando você criar Isso você já vai est Concedendo essa permissão de api na política de recursos dessa função lambda certo então é aquilo que eu falei para vocês Nenhum serviço da WS nenhum recurso nosso pode acessar os outro serviço se ele não ganhar essa permissão explicitamente então aqui a gente já tá dizendo que quando a gente tá fazendo essa integração a gente já tá explicitamente anexando essa permissão certo essa permissão
para que o Api Gateway invoque né seja o gatilho que Acione a nossa função lambda Então vamos criar aqui certo essa integração e beleza criamos aqui perfeito agora o que a gente vai fazer é implantar Então vou vir aqui e vou clicar em implantar a implantação vai ser aqui implantação default vamos não tá deixando eu selecionar deixa eu criar um novo estágio aqui E aí eu vou chamar de produção certo vamos criar esse estágio e eu Vou né implantar aqui em produção implantar beleza eu posso ter mais de um estágio mas no caso a minha
meu estágio Def ele já tava fazendo o o Deploy automático certo então aqui Teoricamente ele já implantou E agora como é que a gente pega o URL aqui dessa nossa api bom a gente pode vir aqui ó aqui na lateral mesmo ele já vai est mostrando a nossa api e o nome dela e o ID dela quando a gente abrir a gente já vai ver Aqui o end Point padrão dela e a gente vai est encontrando os dois estágios que a gente criou Então olha só que legal eu tenho o estágio default né que veio
por padrão que é o estágio que o Deploy é automático certo então o Deploy tá habilitado de forma automática ó implantação automática nesse estágio aqui qualquer modificação que eu faço nas rotas já implica numa implantação automática naquele estágio certo e ele é acessível por essa Rota Só que eu criei Um outro estágio que é esse estágio produção e ele anexou esse endp aqui de barra produção certo na minha URL e esse estágio aqui ele não tem implantação automática então ele só vai implantar quando eu clicar naquele botão lá implantar certo V ver aqui nas minhas
rotas e clicar em implantar e escolher qual o estágio né que eu quero fazer o deplo no nosso caso a gente vai continuar usando o default mas eu quis criar isso aqui para mostrar para vocês Que a gente pode criar né diferentes estágios para por exemplo criar um um de staging um desenvolvimento um de homologação para caso a gente quisesse né testar a nossa aplicação ali com diferentes rotas antes de implantar ela geral né então a gente poderia inclusive desabilitar o a implantação automática pro nosso domínio aqui padrão e habilitar a implantação automática só para
ambiente de testes por exemplo E aí no ambiente de teste tudo que for Alterado já faz Deploy aí já pode testar enfim eu tô só mostrando essa possibilidade para vocês Tá mas o que importa aqui pra gente é que a gente vai pegar essa URL certo a URL aqui da nossa api quando eu acesso ela ela dá um not found porque essa rota não existe mas a gente vai tentar Acessar agora a rota de Create certo então vou abrir lá o insônia e agora eu vou disparar essa requisição ao invés da paraa URL aqui da
minha lambda eu vou disparar para URL Aqui da nossa api no end Point de barra Create certo e aqui fazendo um método do tipo post vou enviar essa requisição vamos esperar ela retornar pronto ela retornou aqui o Code né o código aqui da nossa URL Então tá tudo certo tá funcionando estamos conseguindo fazer a chamada pro endp de Create através da nossa api e agora falta a gente configurar aqui o redirecionamento Então vamos abrir aqui as nossas rotas e vamos criar uma nova Rota então create uma rota do tipo get e agora a gente vai
ter que colocar aqui né que ela recebe um parâmetro então aqui nessa rota a gente vai colocar Chaves certo e vamos mapear o nome desse parâmetro por exemplo vai ser o meu URL code certo é só para dizer que aqui ele vai vir uma informação que é dinâmica né que é um parâmetro variável não é um um um endp fixo isso daqui certo então essa chamada de get vai ser sempre paraa raiz do meu domínio barra o código aqui da da URL certo eu vou criar aqui essa Rota e eu vou integrar ela então vou
fazer uma integração certo com uma função lambda então Criar e anexar integração que função lambda é essa é a função lambda de redirect Então a gente vai pegar aqui a redirect shorten vamos conceder o acesso padrão criar beleza criado eu poderia implantar aqui no meu estágio de produção mas não tem necessidade né ele já fez a implantação aqui no meu estágio Def por Padrão e agora a gente pode pode ir aqui copiar de novo a nossa URL e tentar acessar ela no nosso navegador para ver se o redirect vai funcionar Então a gente vai vir
aqui vamos colar a URL e aqui vamos dar nossa api né E vamos colocar barra e aí o ID que a gente acabou de gerar lá no nosso insônia vamos copiar aqui o ID colar vamos ver se vai funcionar esperar que ele retornar e pronto ó ele fez o redirecionamento aqui pro site né da URL Original Então tá funcionando a nossa api e dessa forma a gente concentrou as nossas requisições aqui no nosso II Gateway E aí para fechar com chave de ouro a gente poderia ir lá na nossa lambda certo e aí desabilitar aqui
nessa lambda a chamada via ã url de função então a gente pode vir aqui em ações a gente pode vir aqui em configurações URL da função certo e excluir essa URL da função dessa forma Eu Não Vou permitir chamadas diretas Para essa minha URL a minha função só vai poder ser acionada pelo meu api Gateway E se a gente observa aqui ó a gente está vendo que o meu api Gateway ele é um Trigger agora dessa minha função ele é um gatilho dela né eu não preciso mais ter essa URL própria dela ela vai ser
acionada pelo mepi Gateway e a mesma coisa a gente pode fazer na nossa lambda de redirect certo ela já tá aqui também ó com o gatilho atrelado certo e eu posso vir nas configurações Dela e excluir aqui a URL da função ela não precisa mais ter uma url exclusiva dela certo ela vai ser acionada somente pelo meu epi Gateway E agora se a gente acessar aqui de novo a URL era para continuar funcionando então deixa eu pegar aqui o URL da nossa função voltar lá pro IP Gateway pegar aqui a URL né que eu acabei
perdendo ela certinho aqui Beleza deixa eu na verdade colar aqui o ID certo um enter aqui só para não perder esse ID pegar o URL da nossa Função então colar aqui depois do meu ID barra para mostrar para vocês que continua funcionando mesmo depois da gente ter desabilitado a URL da nossa função por quê Porque agora o gatilho é o nosso api Gateway e não mais a chamada direta pra nossa função então podemos voltar lá pro nosso notion e dá um ok na última etapa que era a criação do API gator para concentrar as requisições
da nossa função que bom te ver aqui no finalzinho do nosso curso gratuito de Java você faz parte de 15% dos inscritos que finalizam todas as aulas e constroem o projeto até o final junto comigo então isso já é um motivo para você se orgulhar mas o nosso curso não termina por aqui ainda tem uma última etapa E para você garantir o seu certificado é muito importante que você participe dela na quinta-feira teremos um encontro ao vivo para fechar com de ouro esse nosso curso e lá nós vamos liberar a palavra-chave para você conseguir gerar
O seu certificado então não perde essa todas as informações também serão enviadas no nosso grupo do WhatsApp então é só ficar de olho lá combinado e a boa notícia é que esse é apenas o começo da sua jornada de aprendizado na Rocket City tanto em Java quanto em outras tecnologias que estão super em alta no mercado porque com a assinatura completa da Rocket você garante acesso a todo o conteúdo liberado na plataforma Porque pensa comigo se em apenas três Aulas você aprendeu tudo isso imagina tudo que você pode aprender dentro da plataforma e eu tenho
certeza que você vai aprender demais porque eu já estive no seu lugar se você não sabe eu sou ex-aluna da Rocket City eu fiz a trilha de react quando eu ainda era uma estagiária e hoje tô aqui falando sobre Java e a Rocket City fez muita diferença no início da minha carreira como desenvolvedora full stch porque depois da trilha de react JS eu comecei meus Estudos de nodejs e conseguir combinar esses conhecimentos para me tornar uma desenvolvedora fulltech e no futuro chegar no javin e para ficar ainda melhor ainda dá tempo de aproveitar o desconto
da black friday junto com a Rocket nós preparamos um bônus exclusivo para reconhecer a sua dedicação até aqui eu gravei um novo curso de microsserviços com Spring Cloud para você seguir a sua jornada de estudos de Java comigo e você pode ter a chance de Ganhar esse curso de presente então se você quer saber como não perde o nosso encontro ao vivo na quinta-feira pois lá a gente vai dar todos os detalhes de como você pode fazer PR garantir esse bônus a gente se vê em breve e muito obrigado por ter me acompanhado até aqui
foi um prazer estar junto contigo ao longo dessa jornada