Aula 9

Bem-vindo!

  • Nas semanas anteriores, você aprendeu várias linguagens de programação, técnicas e estratégias.
  • Na verdade, esta aula tem sido muito menos uma aula de C ou aula de Python e muito mais uma aula de programação, para que você possa seguir tendências futuras.
  • Nas últimas semanas, você aprendeu como aprender sobre programação.
  • Hoje, mudaremos de HTML e CSS para combinar HTML, CSS, SQL, Python e JavaScript para que você possa criar seus próprios aplicativos da web.

Estática para dinâmica

  • Até este momento, todo HTML que você viu foi pré-escrito e estático.
  • No passado, quando você visitava uma página, o navegador baixava uma página HTML e você poderia visualizá-la.
  • As páginas dinâmicas referem-se à capacidade do Python e linguagens semelhantes de criar arquivos HTML em tempo real. Assim, você pode ter páginas da Web geradas por opções selecionadas pelo usuário.
  • Você usou o http-server anteriormente para fornecer suas páginas da Web. Hoje, usaremos um novo servidor capaz de analisar um endereço da Web e executar ações com base na URL fornecida.

Flask

  • Flask é uma biblioteca de terceiros que permite hospedar aplicativos da Web usando o framework Flask no Python.
  • Você pode executar o flask executando flask run.
  • Para isso, você precisará de um arquivo chamado app.py e uma pasta chamada templates.
  • Para começar, crie uma pasta chamada templates e crie um arquivo chamado index.html com o seguinte código:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>hello</title>
          </head>
          <body>
              hello, {{ name }}
          </body>
      </html>
    

    Observe o duplo {{ name }} que é um placeholder para algo que será fornecido posteriormente por nosso servidor Flask.

  • Em seguida, na mesma pasta em que a pasta templates aparece, crie um arquivo chamado app.py e adicione o seguinte código:

      # Cumprimenta o usuário
    
      from flask import Flask, render_template, request
    
      app = Flask(__name__)
    
      @app.route("/")
      def index():
          return render_template("index.html", name=request.args.get("name", "world"))
    

    Observe que este código define app como o aplicativo Flask. Em seguida, define a rota / de app como o retorno do conteúdo de index.html com o argumento de name. Por padrão, a função request.args.get procurará o name fornecido pelo usuário. Se nenhum nome for fornecido, ele será definido como world.

  • Por fim, adicione um arquivo final na mesma pasta de app.py chamado requirements.txt que tem apenas uma única linha de código:

      Flask
    

    Observe que somente Flask aparece neste arquivo.

  • Você pode executar esse arquivo digitando flask run na janela do terminal. Caso o Flask não execute, verifique se sua sintaxe está correta em cada um dos arquivos acima. Além disso, se o Flask não for executado, verifique se seus arquivos estão organizados da seguinte forma:

      /modelos
          index.html
      app.py
      requirements.txt
    

    Assim que conseguir executar, você será solicitado a clicar em um link. Quando você navegar até essa página da web, tente adicionar ?name=[SeuNome] à URL base na barra de URL do seu navegador.

  • Melhorando nosso programa, sabemos que a maioria dos usuários não digitará argumentos na barra de endereços. Em vez disso, os programadores contam com os usuários para preencher formulários em páginas da web. Da mesma forma, podemos modificar o index.html da seguinte maneira:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>olá</title>
          </head>
          <body>
              <form action="/greet" method="get">
                  <input autocomplete="off" autofocus name="name" placeholder="Nome" type="text">
                  <button type="submit">Cumprimentar</button>
              </form>
          </body>
      </html>
    

    Observe que um formulário agora é criado que pega o nome do usuário e então o passa para uma rota chamada /greet.

  • Além disso, podemos alterar app.py da seguinte forma:

      # Adiciona um formulário, segunda rota
    
      from flask import Flask, render_template, request
    
      app = Flask(__name__)
    
      @app.route("/")
      def index():
          return render_template("index.html")
    
      @app.route("/greet")
      def greet():
          return render_template("greet.html", name=request.args.get("name", "mundo"))
    

    Observe que o caminho padrão exibirá um formulário para o usuário inserir seu nome. A rota /greet passará name para essa página da web.

  • Para finalizar essa implementação, você precisará de outro modelo para greet.html da seguinte forma:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>olá</title>
          </head>
          <body>
              olá, {{ name }}
          </body>
      </html>
    

    Observe que essa rota agora exibirá a saudação para o usuário, seguida por seu nome.

Layout

  • Ambas as nossas páginas da web, index.html e greet.html, têm muitos dados em comum. Não seria ótimo permitir que o corpo fosse único, mas copiar o mesmo layout de página para página?
  • Primeiro, crie um novo template chamado layout.html e escreva o código da seguinte forma:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>hello</title>
          </head>
          <body>
              {% block body %}{% endblock %}
          </body>
      </html>
    

    Observe que {% block body %}{% endblock %} permite a inserção de outro código de outros arquivos HTML.

  • Em seguida, modifique seu index.html da seguinte forma:

      {% extends "layout.html" %}
    
      {% block body %}
    
          <form action="/greet" method="post">
              <input autocomplete="off" autofocus name="name" placeholder="Name" type="text">
              <button type="submit">Greet</button>
          </form>
    
      {% endblock %}
    

    Observe que a linha {% extends "layout.html" %} informa ao servidor onde obter o layout desta página. Em seguida, {% block body %}{% endblock %} informa qual código deve ser inserido em layout.html.

  • Finalmente, altere greet.html da seguinte forma:

      {% extends "layout.html" %}
    
      {% block body %}
          hello, {{ name }}
      {% endblock %}
    

    Observe como este código é mais curto e compacto.

POST

  • Você pode imaginar cenários em que não é seguro utilizar get, pois nomes de usuários e senhas apareceriam na URL.
  • Podemos utilizar o método post para ajudar neste problema modificando app.py da seguinte forma:

      # Altera para POST
    
      from flask import Flask, render_template, request
    
      app = Flask(__name__)
    
      @app.route("/")
      def index():
          return render_template("index.html")
    
      @app.route("/greet", methods=["POST"])
      def greet():
          return render_template("greet.html", name=request.form.get("name", "world"))
    

    Observe que POST é adicionado à rota /greet, e que usamos request.form.get em vez de request.args.get.

  • Isso informa ao servidor para procurar mais profundamente no envelope virtual e não revelar os itens em post na URL.

  • Ainda assim, esse código pode ser refinado ainda mais, utilizando uma rota única para get e post. Para fazer isso, modifique app.py da seguinte forma:

      # Usa uma rota única
    
      from flask import Flask, render_template, request
    
      app = Flask(__name__)
    
      @app.route("/", methods=["GET", "POST"])
      def index():
          if request.method == "POST":
              return render_template("greet.html", name=request.form.get("name", "world"))
          return render_template("index.html")
    

    Observe que get e post são feitos em um único roteamento. No entanto, request.method é utilizado para rotear adequadamente com base no tipo de roteamento solicitado pelo usuário.

Frosh IMs

  • O Frosh IMs ou froshims é um aplicativo da web que permite que os alunos se inscrevam em esportes intercolegiais.
  • Crie uma pasta digitando mkdir froshims na janela do terminal. Em seguida, digite cd froshims para navegar até essa pasta. Dentro dela, crie um diretório chamado models digitando mkdir templates. Por fim, digite code app.py e escreva o código como segue:

      # Implementa um formulário de inscrição usando um menu de seleção
    
      de flask import Flask, render_template, request
    
      app = Flask(__name__)
    
      ESPORTES = [
          "Basquete",
          "Futebol",
          "Ultimate Frisbee"
      ]
    
      @app.route("/")
      def index():
          return render_template("index.html", esportes=ESPORTES)
    
      @app.route("/registrar", methods=["POST"])
      def registrar():
    
          # Validade a submissão
          se não request.form.get("nome") ou request.form.get("esporte") não em ESPORTES:
              return render_template("falha.html")
    
          # Confirme o registro
          return render_template("sucesso.html")
    

    Observe que uma opção de falha é fornecida, de modo que uma mensagem de falha será exibida ao usuário se o campo nome ou esporte não for preenchido corretamente.

  • Em seguida, crie um arquivo na pasta templates chamado index.html digitando code templates/index.html e escreva o código da seguinte forma:

      {% extends "layout.html" %}
    
      {% bloco body %}
          <h1>Registrar</h1>
          <form action="/register" method="post">
              <input autocomplete="off" autofocus name="name" placeholder="Nome" type="text">
              <select name="sport">
                  <option disabled selected>Esporte</option>
                  {% for sport in sports %}
                      <option value="{{ sport }}">{{ sport }}</option>
                  {% endfor %}
              </select>
              <button type="submit">Registrar</button>
          </form>
      {% endblock %}
    
  • Em seguida, crie um arquivo chamado layout.html digitando code templates/layout.html e escreva o código da seguinte forma:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>froshims</title>
          </head>
          <body>
              {% bloco body %}{% endblock %}
          </body>
      </html>
    
  • Em quarto lugar, crie um arquivo nos modelos chamado success.html da seguinte forma:

      {% extends "layout.html" %}
    
      {% bloco body %}
          Você está registrado!
      {% endblock %}
    
  • Por fim, crie um arquivo nos modelos chamado failure.html da seguinte forma:

      {% extends "layout.html" %}
    
      {% bloco body %}
          Você não está registrado!
      {% endblock %}
    
  • Você pode imaginar como queremos aceitar o registro de muitos registradores diferentes. Podemos melhorar o app.py da seguinte maneira:

      # Implementa um formulário de registro, armazenando os registradores em um dicionário, com mensagens de erro
    
      from flask import Flask, redirect, render_template, request
    
      app = Flask(__name__)
    
      REGISTRANTS = {}
    
      SPORTS = [
          "Basquete",
          "Futebol",
          "Ultimate Frisbee"
      ]
    
      @app.route("/")
      def index():
          return render_template("index.html", sports=SPORTS)
    
      @app.route("/register", methods=["POST"])
      def register():
    
          # Valida o nome
          name = request.form.get("name")
          if not name:
              return render_template("error.html", message="Nome ausente")
    
          # Valida o esporte
          sport = request.form.get("sport")
          if not sport:
              return render_template("error.html", message="Esporte ausente")
          if sport not in SPORTS:
              return render_template("error.html", message="Esporte inválido")
    
          # Lembra do registrador
          REGISTRANTS[name] = sport
    
          # Confirma o registro
          return redirect("/registrants")
    
      @app.route("/registrants")
      def registrants():
          return render_template("registrants.html", registrants=REGISTRANTS)
    

    Observe que um dicionário chamado REGISTRANTS é usado para registrar o sport selecionado por REGISTRANTS[name]. Além disso, observe que registrants=REGISTRANTS passa o dicionário para esse template.

  • Além disso, crie um novo template chamado registrants.html da seguinte maneira:

      {% extends "layout.html" %}
    
      {% block body %}
          <h1>Registrantes</h1>
          <table>
              <thead>
                  <tr>
                      <th>Nome</th>
                      <th>Esporte</th>
                  </tr>
              </thead>
              <tbody>
                  {% for name in registrants %}
                      <tr>
                          <td>{{ name }}</td>
                          <td>{{ registrants[name] }}</td>
                      </tr>
                  {% endfor %}
              </tbody>
          </table>
      {% endblock %}
    

    Observe que {% for name in registrants %}...{% endfor %} irá iterar por cada um dos registrantes. Muito poderoso para conseguir iterar em uma página da web dinâmica!

  • Executando flask run e inserindo vários nomes e esportes, você pode navegar até /registrants para ver quais dados foram registrados.

  • Você tem agora um aplicativo da web! No entanto, existem algumas falhas de segurança! Por estar tudo no lado do cliente, um adversário poderia alterar o HTML e hackear um site. Além disso, esses dados não persistirão caso o servidor seja desligado. Existe alguma maneira de fazer com que nossos dados persistam mesmo quando o servidor for reiniciado?

Flask e SQL

  • Da mesma forma que vimos como o Python pode se conectar a um banco de dados SQL, podemos combinar o poder do Flask, Python e SQL para criar um aplicativo web onde os dados serão persistentes!
  • Para implementar isso, você precisará seguir algumas etapas.
  • Primeiro, modifique requirements.txt como a seguir:

      cs50
      Flask
    
  • Modifique index.html como a seguir:

      {% extends "layout.html" %}
    
      {% block body %}
          <h1>Registrar</h1>
          <form action="/register" method="post">
              <input autocomplete="off" autofocus name="name" placeholder="Nome" type="text">
              {% for sport in sports %}
                  <input name="sport" type="radio" value="{{ sport }}"> {{ sport }}
              {% endfor %}
              <button type="submit">Registrar</button>
          </form>
      {% endblock %}
    
  • Modifique layout.html como a seguir:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>froshims</title>
          </head>
          <body>
              {% block body %}{% endblock %}
          </body>
      </html>
    
  • Verifique se failure.html é mostrado como a seguir:

      {% extends "layout.html" %}
    
      {% block body %}
          Você não está registrado!
      {% endblock %}
    
  • Modifique registrants.html para ser mostrado como a seguir:

      {% extends "layout.html" %}
    
      {% block body %}
          <h1>Registrados</h1>
          <table>
              <thead>
                  <tr>
                      <th>Nome</th>
                      <th>Esporte</th>
                      <th></th>
                  </tr>
              </thead>
              <tbody>
                  {% for registrant in registrants %}
                      <tr>
                          <td>{{ registrant.name }}</td>
                          <td>{{ registrant.sport }}</td>
                          <td>
                              <form action="/deregister" method="post">
                                  <input name="id" type="hidden" value="{{ registrant.id }}">
                                  <button type="submit">Cancelar registro</button>
                              </form>
                          </td>
                      </tr>
                  {% endfor %}
              </tbody>
          </table>
      {% endblock %}
    
  • Observe que um valor oculto registrant.id é incluído para que seja possível usar o id depois em app.py

Por fim, modifique app.py conforme segue:

```python

Implementa um formulário de registro, armazena registrados em um banco de dados SQLite, com suporte para cancelamento de registro

from cs50 import SQL from flask import Flask, redirect, render_template, request

app = Flask(name)

db = SQL("sqlite:///froshims.db")

SPORTS = [ "Basquetebol", "Futebol", "Ultimate Frisbee" ]

@app.route("/") def index(): return render_template("index.html", sports=SPORTS)

@app.route("/deregister", methods=["POST"]) def deregister():

  # Esquece o registrado
  id = request.form.get("id")
  if id:
      db.execute("DELETE FROM registrants WHERE id = ?", id)
  return redirect("/registrants")

@app.route("/register", methods=["POST"]) def register():

  # Valida envio
  name = request.form.get("name")
  sport = request.form.get("sport")
  if not name or sport not in SPORTS:
      return render_template("failure.html")

  # Lembra do registrado
  db.execute("INSERT INTO registrants (name, sport) VALUES(?, ?)", name, sport)

  # Confirma registro
  return redirect("/registrants")

@app.route("/registrants") def registrants(): registrants = db.execute("SELECT * FROM registrants") return render_template("registrants.html", registrants=registrants) ```

Observe que a biblioteca cs50 é utilizada. Uma rota para register** é incluída para o método post. Essa rota pegará o nome e esporte obtidos a partir do formulário de registro e executará uma consulta SQL para adicionar o nome e o esporte à tabela registrants. A rota deregister direciona para uma consulta SQL que obterá o id do usuário e utilizará essa informação para cancelar o registro desse indivíduo.

Você pode saber mais na documentação do Flask.

Sessão

  • Enquanto o código acima é útil sob um ponto de vista administrativo, onde um administrador de back-office pode adicionar e remover usuários do banco de dados, pode-se imaginar como este código não é seguro para implementar num servidor público.
  • De um lado, agentes maliciosos poderiam tomar decisões em nome de outros usuários ao clicar no botão de cancelamento de cadastro - excluindo efetivamente sua resposta gravada do servidor.
  • Serviços da web como o Google usam credenciais de login para garantir que os usuários tenham acesso apenas aos dados certos.
  • Na verdade, podemos implementar isso usado cookies. Cookies são arquivos pequenos que são armazenados em seu computador, assim sendo o seu computador pode se comunicar com o servidor e efetivamente dizer, "Sou um usuário autorizado que já fez login."
  • Na forma mais simples, podemos implementar isso criando uma pasta chamada login e então adicionando os seguintes arquivos.
  • Primeiro, crie um arquivo chamado requirements.txt que lê como a seguir:

      Flask
      Flask-Session
    

    Observe que além de Flask, também incluímos Flask-Session, que é necessário para suportar sessões de login.

  • Segundo, numa pasta templates, crie um arquivo chamado layout.html que aparece como segue:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>store</title>
          </head>
          <body>
              {% block body %}{% endblock %}
          </body>
      </html>
    

    Observe que isso oferece um layout muito simples com um título e um corpo.

  • Terceiro, crie um arquivo na pasta templates chamado index.html que aparece como segue:

      {% extends "layout.html" %}
    
      {% block body %}
    
          {% if session["name"] %}
              Você está logado como {{ session["name"] }}. <a href="/logout">Sair</a>.
          {% else %}
              Você não está logado. <a href="/login">Logar</a>.
          {% endif %}
    
      {% endblock %}
    

    Observe que este arquivo procura ver se session["name"] existe. Se existir, ele mostrará uma mensagem de boas-vindas. Se não existir, recomendará que você navegue até uma página para fazer login.

  • Em quarto lugar, crie um arquivo com o nome login.html e adicione o código a seguir:

      {% extends "layout.html" %}
    
      {% block body %}
    
          <form action="/login" method="post">
              <input autocomplete="off" autofocus name="name" placeholder="Nome" type="text">
              <button type="submit">Fazer login</button>
          </form>
    
      {% endblock %}
    

    Note que esse é o layout de uma página básica de login.

  • Por fim, crie um arquivo na pasta login chamado app.py e escreva o código como se segue:

      from flask import Flask, redirect, render_template, request, session
      from flask_session import Session
    
      # Configure o app
      app = Flask(__name__)
    
      # Configure a sessão
      app.config["SESSION_PERMANENT"] = False
      app.config["SESSION_TYPE"] = "filesystem"
      Session(app)
    
      @app.route("/")
      def index():
          if not session.get("name"):
              return redirect("/login")
          return render_template("index.html")
    
      @app.route("/login", methods=["GET", "POST"])
      def login():
          if request.method == "POST":
              session["name"] = request.form.get("name")
              return redirect("/")
          return render_template("login.html")
    
      @app.route("/logout")
      def logout():
          session["name"] = None
          return redirect("/")
    

    Note os imports modificados na parte superior do arquivo, incluindo session, que permitirá que você use sessões. Mais importante, note como session["name"] é usado nas rotas login e logout. A rota login atribuirá o nome de login fornecido e o atribuirá a session["name"]. No entanto, na rota logout, o logout é implementado simplesmente configurando session["name"] como None.

  • Você pode ler mais sobre sessões na documentação do Flask.

Armazenamento

  • Passando para um exemplo final de utilização da capacidade do Flask de habilitar uma sessão.
  • Examinamos o código a seguir para Armazenamento em app.py. O código a seguir foi mostrado:

```python from cs50 import SQL from flask import Flask, redirect, render_template, request, session from flask_session import Session

Configurar aplicativo

app = Flask(name)

Conectar ao banco de dados

db = SQL("sqlite:///store.db")

Configurar sessão

app.config["SESSION_PERMANENT"] = False app.config["SESSION_TYPE"] = "filesystem" Session(app)

@app.route("/") def index(): books = db.execute("SELECT * FROM books") return render_template("books.html", books=books)

@app.route("/cart", methods=["GET", "POST"]) def cart():

        # Garantir que o carrinho exista
        if "cart" not in session:
            session["cart"] = []

        # POST
        if request.method == "POST":
            id = request.form.get("id")
            if id:
                session["cart"].append(id)
            return redirect("/cart")

        # GET
        books = db.execute("SELECT * FROM books WHERE id IN (?)", session["cart"])
        return render_template("cart.html", books=books)

```

Note que cart é implementado usando uma lista. Os itens podem ser adicionados a esta lista usando os botões Adicionar ao Carrinho em books.html. Ao clicar em tal botão, o método post é invocado, onde o id do item é anexado ao cart. Ao visualizar o carrinho, invocando o método get, o SQL é executado para exibir uma lista dos livros no carrinho.

API

  • Uma interface de programação de aplicativo ou API é uma série de especificações que permite que você se conecte com outro serviço. Por exemplo, podemos utilizar a API do IMDB para nos conectarmos com o banco de dados deles. Podemos até integrar APIs para controlar tipos específicos de dados baixáveis de um servidor.
  • Vimos um exemplo chamado shows.
  • Ao analisar app.py, vimos o seguinte:

      # Pesquisa programas usando Ajax
    
      from cs50 import SQL
      from flask import Flask, render_template, request
    
      app = Flask(__name__)
    
      db = SQL("sqlite:///shows.db")
    
      @app.route("/")
      def index():
          return render_template("index.html")
    
      @app.route("/search")
      def search():
          q = request.args.get("q")
          if q:
              shows = db.execute("SELECT * FROM shows WHERE title LIKE ? LIMIT 50", "%" + q + "%")
          else:
              shows = []
          return render_template("search.html", shows=shows)
    

    Observe que a rota search executa uma consulta SQL.

  • Ao observar search.html, você notará que é muito simples:

      {% for show in shows %}
          <li>{{ show["title"] }}</li>
      {% endfor %}
    

    Observe que ele fornece uma lista com marcadores.

  • Por fim, ao analisar index.html, observe que um código AJAX é utilizado para impulsionar a pesquisa:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>shows</title>
          </head>
          <body>
    
              <input autocomplete="off" autofocus placeholder="Pesquisa" type="search">
    
              <ul></ul>
    
              <script>
    
                  let input = document.querySelector('input');
                  input.addEventListener('input', async function() {
                      let response = await fetch('/search?q=' + input.value);
                      let shows = await response.text();
                      document.querySelector('ul').innerHTML = shows;
                  });
    
              </script>
    
          </body>
      </html>
    

    Observe que um ouvinte de evento é utilizado para consultar dinamicamente o servidor para fornecer uma lista que corresponda ao título fornecido. Isso localizará a tag ul no HTML e modificará a página da Web de acordo para incluir a lista de correspondências.

  • Você pode obter mais informações na documentação do AJAX.

JSON

  • JavaScript Object Notation ou JSON é um arquivo de texto de dicionários com chaves e valores. Essa é uma maneira bruta e amigável ao computador de obter muitos dados.
  • JSON é uma forma muito útil de obter dados do servidor.
  • Você pode ver isso em ação em index.html que examinamos juntos:

      <!DOCTYPE html>
    
      <html lang="en">
          <head>
              <meta name="viewport" content="initial-scale=1, width=device-width">
              <title>shows</title>
          </head>
          <body>
    
              <input autocomplete="off" autofocus placeholder="Query" type="text">
    
              <ul></ul>
    
              <script>
    
                  let input = document.querySelector('input');
                  input.addEventListener('input', async function() {
                      let response = await fetch('/search?q=' + input.value);
                      let shows = await response.json();
                      let html = '';
                      for (let id in shows) {
                          let title = shows[id].title.replace('<', '&lt;').replace('&', '&amp;');
                          html += '<li>' + title + '</li>';
                      }
                      document.querySelector('ul').innerHTML = html;
                  });
    
              </script>
    
          </body>
      </html>
    

    Enquanto o acima pode ser algo críptico, ele oferece um ponto de partida para você pesquisar por JSON por conta própria para ver como ele pode ser implementado em seus próprios aplicativos web.

  • Você pode ler mais na documentação JSON.

Resumo

Nesta lição, você aprendeu como utilizar Python, SQL e Flask para criar aplicativos web. Especificamente, discutimos…

  • GET
  • POST
  • Flask
  • Session
  • AJAX
  • JSON

Vejo vocês na próxima vez para nossa aula final!