// aula 1 · Python · Web com Flask

Flask — criando sua
primeira aplicação web


Como a internet funciona — o básico que você precisa saber

O que acontece quando você abre um site?

Quando você digita um endereço no navegador e aperta Enter, o navegador envia uma requisição para um computador em algum lugar do mundo — chamado de servidor. Esse servidor recebe o pedido, processa, e devolve uma resposta — geralmente uma página HTML que o navegador exibe pra você.

Isso é a web inteira. Todo site, toda API, todo sistema online funciona assim: cliente pede, servidor responde. O Flask é a ferramenta que te permite criar esse servidor usando Python.

Analogia — o Flask é como uma pizzaria
🧑‍💻
Navegador Cliente — faz o pedido
📋
Requisição HTTP "Quero a página /cardapio"
🌶️
Flask Recebe, processa e responde
📄
Resposta HTTP HTML, JSON ou arquivo

O navegador é o cliente que faz o pedido. O Flask é a cozinha que recebe o pedido, prepara a resposta certa e manda de volta. Você, programando em Python, decide o que acontece em cada pedido.

O que é HTTP?

HTTP (HyperText Transfer Protocol) é o idioma que navegadores e servidores usam para se comunicar. Toda requisição HTTP diz duas coisas principais: qual URL está sendo acessada e qual método está sendo usado.

Os métodos mais importantes são GET (quero buscar alguma coisa) e POST (quero enviar dados). Quando você abre uma página, é um GET. Quando você faz login ou envia um formulário, é um POST.


O que é Flask e por que ele existe

Um micro-framework para web em Python

Flask é uma biblioteca Python que transforma seu código em um servidor web real. Sem ele, você teria que lidar manualmente com sockets de rede, parsear requisições HTTP, formatar respostas — coisas extremamente complexas. O Flask cuida de tudo isso, e deixa você focar só na lógica do seu sistema.

Ele é chamado de micro-framework não porque é fraco, mas porque começa pequeno e sem opinião — ele não te obriga a usar banco de dados X, template Y ou estrutura Z. Você escolhe o que precisa e adiciona aos poucos.

Um pouco de história

Flask foi criado por Armin Ronacher em 2010. Começou como uma piada de 1º de abril — um "framework em um arquivo só". As pessoas gostaram tanto que ele virou um projeto sério. Hoje é um dos frameworks Python mais populares do mundo, mantido por uma comunidade ativa.

Leve e legível

Uma aplicação Flask básica cabe em 10 linhas de Python. Perfeito para aprender como a web funciona sem ter que entender um sistema gigante antes de escrever a primeira linha.

Extensível do seu jeito

O que não vem por padrão, você adiciona com extensões: Flask-SQLAlchemy para banco de dados, Flask-Login para autenticação, Flask-Mail para e-mails. Cada uma quando você precisar.

Usado em produção de verdade

Netflix, LinkedIn e Pinterest já usaram Flask em partes dos seus sistemas. Ele é simples de aprender, mas é robusto o suficiente para produção.

Ideal para APIs

Flask é uma das escolhas mais populares para construir APIs REST em Python. Rápido de escrever, fácil de testar, e se encaixa perfeitamente com front-ends em React ou Vue.

FlaskDjango
Micro-framework — você monta o que precisaFramework completo — vem com tudo incluso
Curva de aprendizado baixa — ideal para começarCurva de aprendizado maior — mais conceitos de uma vez
Você escolhe banco, ORM, autenticaçãoJá vem com ORM, admin, autenticação prontos
Ideal para APIs, projetos pequenos e médiosIdeal para sistemas grandes com muitas funcionalidades
Estrutura livre — você organiza como quiserEstrutura rígida e definida pelo framework

Como o Flask funciona por dentro

O ciclo de vida de uma requisição

Toda vez que alguém acessa uma URL da sua aplicação Flask, um ciclo acontece: o Flask recebe a requisição HTTP, identifica qual função Python deve tratar aquela URL, executa essa função, e devolve a resposta para o navegador. Esse ciclo inteiro acontece em milissegundos.

O ciclo completo de uma requisição Flask
1
Navegador envia a requisição Você digita localhost:5000/produtos e aperta Enter. O navegador monta uma requisição HTTP GET e envia para o servidor Flask.
2
Flask recebe e analisa a URL O servidor Flask, rodando em Python, recebe a requisição. Ele olha para a URL (/produtos) e para o método (GET) e procura uma rota registrada que combine.
3
Flask executa a função correspondente Achou a rota! Ele chama a função Python que foi registrada com @app.route("/produtos"). Pode buscar dados no banco, processar lógica — o que você programar.
4
A função retorna uma resposta A função Python retorna algo — uma string HTML, um JSON, um redirecionamento. O Flask empacota isso em uma resposta HTTP com o código de status correto (200, 404, etc.).
5
Navegador recebe e exibe O navegador recebe a resposta, interpreta o HTML (ou JSON) e exibe para o usuário. O ciclo se completa — pronto para a próxima requisição.

Os três pilares do Flask

1. Werkzeug — é a biblioteca que fica embaixo do Flask e cuida de tudo relacionado ao HTTP: receber requisições, parsear formulários, lidar com cookies e muito mais. Você raramente vai interagir com ela diretamente, mas ela está sempre trabalhando.

2. Jinja2 — é o motor de templates. Ele permite que você escreva HTML com variáveis, condicionais e laços dentro, misturando Python com HTML de forma limpa e segura. Quando você chama render_template(), é o Jinja2 que entra em ação.

3. O roteador — é o coração do Flask. Quando você escreve @app.route("/sobre"), você está dizendo ao roteador: "registre que a URL /sobre deve chamar essa função". O roteador guarda essa tabela e consulta a cada requisição.

💡 O que significa "servidor de desenvolvimento"?

Quando você roda flask run ou app.run(debug=True), o Flask inicia um servidor embutido que é ótimo para desenvolver e testar. Mas ele não é feito para produção. Em produção, o Flask fica por trás de servidores como Gunicorn ou uWSGI, que são muito mais robustos e seguros.


Instalação e primeira rota

Terminal
# 1. Crie uma pasta para o projeto
mkdir meu_projeto && cd meu_projeto

# 2. Crie e ative o ambiente virtual
python -m venv venv
source venv/bin/activate        # Linux / Mac
venv\Scripts\activate           # Windows

# 3. Instale o Flask
pip install flask

✅ Sempre use ambiente virtual

O venv cria um Python isolado para cada projeto. Assim as dependências de um projeto não conflitam com as de outro. É uma boa prática que todo desenvolvedor Python segue.

O menor app Flask possível

Python — app.py
from flask import Flask

# Cria a aplicação. __name__ diz ao Flask onde estão os arquivos do projeto.
app = Flask(__name__)

# @app.route é um decorador — ele registra a URL "/" nessa função.
@app.route("/")
def index():
    return "Olá, mundo! 🌍"   # isso vira a resposta HTTP

if __name__ == "__main__":
    app.run(debug=True)   # debug=True reinicia ao salvar e mostra erros detalhados
Terminal — rodando
python app.py

# * Running on http://127.0.0.1:5000
# Abra esse endereço no navegador!

Linha por linha — entendendo o código

Flask(__name__) — cria o objeto da aplicação. O __name__ é uma variável especial do Python que contém o nome do arquivo atual. O Flask usa isso para saber onde procurar templates e arquivos estáticos.

@app.route("/") — este é um decorador. Ele "envolve" a função de baixo e a registra no roteador do Flask, ligando a URL / a essa função. Quando alguém acessar /, o Flask vai chamar index().

return "Olá, mundo!" — tudo que a função retornar vira o corpo da resposta HTTP. Pode ser texto simples, HTML completo, ou JSON.


Rotas e métodos HTTP

O que é uma rota?

Uma rota é a combinação de uma URL com uma função Python. É o Flask dizendo: "se alguém acessar essa URL, execute essa função e devolva o que ela retornar". Você pode ter quantas rotas quiser, cada uma tratando um endereço diferente da sua aplicação.

Python — rotas variadas
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Página inicial"

@app.route("/sobre")
def sobre():
    return "Sobre mim"

# <nome> captura qualquer texto na URL e passa para a função
@app.route("/usuario/<nome>")
def perfil(nome):
    return f"Perfil de {nome}"   # /usuario/lucilia → "Perfil de lucilia"

# <int:id> garante que o parâmetro seja um número inteiro
@app.route("/produto/<int:id>")
def produto(id):
    return f"Produto número {id}"

Métodos HTTP — GET e POST

GET Busca ou lê informação. É o método padrão — toda vez que você digita uma URL no navegador, está fazendo um GET. Não envia dados no corpo da requisição.
POST Envia dados para o servidor. Formulários de login, cadastro e busca usam POST. Os dados vão no corpo da requisição, não aparecem na URL.
PUT Atualiza um recurso existente. Muito usado em APIs REST para editar dados.
DELETE Remove um recurso. Também mais comum em APIs — o HTML padrão não suporta DELETE em formulários.
Python — rota com GET e POST
from flask import Flask, request

app = Flask(__name__)

# methods define quais métodos HTTP essa rota aceita
@app.route("/contato", methods=["GET", "POST"])
def contato():
    if request.method == "POST":
        # request.form acessa os dados enviados pelo formulário
        nome = request.form.get("nome")
        return f"Olá, {nome}! Mensagem recebida."
    # Se for GET, exibe o formulário
    return "<form method='POST'><input name='nome'><button>Enviar</button></form>"

Templates com Jinja2

Por que separar HTML do Python?

Retornar HTML dentro de strings Python funciona para exemplos simples, mas vira um pesadelo em páginas reais. Templates resolvem isso: você escreve o HTML em arquivos separados, e o Jinja2 permite inserir variáveis Python dentro desse HTML de forma limpa.

É a separação entre lógica (Python) e apresentação (HTML). O Python decide os dados, o template decide como exibi-los.

Estrutura de pastas
meu_projeto/
├── app.py
├── templates/         # Flask procura templates aqui automaticamente
│   ├── base.html      # layout base (herança de template)
│   ├── index.html
│   └── perfil.html
└── static/            # CSS, JS e imagens ficam aqui
    └── style.css

Template base — herança de layout

templates/base.html
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}Meu Site{% endblock %}</title>
  <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
  <nav>
    <a href="{{ url_for('index') }}">Início</a>
  </nav>
  <main>
    {% block conteudo %}{% endblock %}
  </main>
</body>
</html>

Template filho — herdando o base

templates/index.html
{% extends "base.html" %}         {# herda tudo do base.html #}

{% block title %}Início{% endblock %}

{% block conteudo %}
  <h1>Olá, {{ nome }}!</h1>

  {% if tarefas %}
    <ul>
      {% for t in tarefas %}
        <li>{{ t.titulo }}</li>
      {% endfor %}
    </ul>
  {% else %}
    <p>Nenhuma tarefa ainda.</p>
  {% endif %}
{% endblock %}
Python — passando dados para o template
from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index():
    tarefas = [
        {"titulo": "Estudar Flask"},
        {"titulo": "Fazer o projeto"},
    ]
    # Tudo que você passar como argumento vira variável no template
    return render_template("index.html", nome="Lucilia", tarefas=tarefas)
Sintaxe Jinja2O que faz
{{ variavel }}Exibe o valor de uma variável Python
{% if ... %} {% endif %}Condicional — bloco aparece só se a condição for verdadeira
{% for x in lista %} {% endfor %}Laço — repete o bloco para cada item da lista
{% extends "base.html" %}Herda o layout de outro template
{% block nome %} {% endblock %}Define um espaço que o template filho pode preencher
{{ url_for('nome_da_funcao') }}Gera a URL de uma rota pelo nome da função
{# comentário #}Comentário — não aparece no HTML final

Recebendo dados de formulários

templates/form.html
<form action="/adicionar" method="POST">
  <input type="text" name="titulo" placeholder="Nova tarefa" required>
  <button type="submit">Adicionar</button>
</form>
Python — recebendo o formulário
from flask import Flask, request, redirect, url_for

app = Flask(__name__)
tarefas = []

@app.route("/adicionar", methods=["POST"])
def adicionar():
    # request.form é um dicionário com os campos do formulário
    titulo = request.form.get("titulo")   # "titulo" = atributo name do input
    if titulo:
        tarefas.append({"titulo": titulo})
    # Após POST, sempre redirecione — padrão Post/Redirect/Get
    return redirect(url_for("index"))

✅ Post/Redirect/Get — por que redirecionar após o POST?

Se você retornar HTML direto após um POST e o usuário atualizar a página (F5), o navegador pergunta se quer "reenviar o formulário" — e o dado pode ser duplicado. Redirecionando para um GET com redirect(url_for(...)), o problema some. Esse padrão tem nome: Post/Redirect/Get (PRG).


Criando uma API JSON

Flask como back-end de API

Além de servir páginas HTML, o Flask é excelente para criar APIs. Em vez de retornar HTML, suas rotas retornam JSON — o formato de dados que front-ends React, Vue, apps mobile e qualquer cliente moderno sabem consumir. O Flask tem a função jsonify() que converte dicionários Python em JSON automaticamente.

Python — api.py
from flask import Flask, jsonify, request

app = Flask(__name__)

usuarios = [
    {"id": 1, "nome": "Lucilia", "email": "lucilia@email.com"},
    {"id": 2, "nome": "Ana",    "email": "ana@email.com"},
]

# GET /api/usuarios — retorna todos os usuários em JSON
@app.route("/api/usuarios")
def listar_usuarios():
    return jsonify(usuarios)   # converte a lista Python em JSON

# GET /api/usuarios/1 — retorna um usuário específico
@app.route("/api/usuarios/<int:uid>")
def get_usuario(uid):
    u = next((u for u in usuarios if u["id"] == uid), None)
    if not u:
        return jsonify({"erro": "não encontrado"}), 404   # segundo valor = status HTTP
    return jsonify(u)

# POST /api/usuarios — cria um novo usuário
@app.route("/api/usuarios", methods=["POST"])
def criar_usuario():
    dados = request.get_json()   # lê o corpo JSON da requisição
    novo = {
        "id": len(usuarios) + 1,
        "nome": dados["nome"],
        "email": dados["email"]
    }
    usuarios.append(novo)
    return jsonify(novo), 201   # 201 Created — recurso criado com sucesso
Código HTTPSignificadoQuando usar
200 OKTudo certoResposta padrão de sucesso (Flask usa por padrão)
201 CreatedCriado com sucessoApós um POST que cria um novo recurso
400 Bad RequestRequisição inválidaDados enviados pelo cliente estão errados
404 Not FoundNão encontradoRecurso não existe no servidor
500 Internal Server ErrorErro no servidorAlgo deu errado no código do servidor

Mini projeto — Lista de Tarefas

📝 O que vamos construir

Uma lista de tarefas funcional no navegador — você adiciona e remove tarefas, com tudo processado pelo Flask. Os dados ficam em memória para focar no Flask puro, sem banco de dados ainda.

1
Estrutura do projeto
Estrutura
tarefas_app/
├── app.py
└── templates/
    └── index.html
2
app.py — toda a lógica
app.py
from flask import Flask, render_template, request, redirect, url_for

app = Flask(__name__)

tarefas = []
proximo_id = 1

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

@app.route("/adicionar", methods=["POST"])
def adicionar():
    global proximo_id
    titulo = request.form.get("titulo", "").strip()
    if titulo:
        tarefas.append({"id": proximo_id, "titulo": titulo})
        proximo_id += 1
    return redirect(url_for("index"))

@app.route("/remover/<int:tid>")
def remover(tid):
    global tarefas
    tarefas = [t for t in tarefas if t["id"] != tid]
    return redirect(url_for("index"))

if __name__ == "__main__":
    app.run(debug=True)
3
templates/index.html
templates/index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head><title>Tarefas</title></head>
<body>
  <h1>📝 Minhas Tarefas</h1>

  <form action="/adicionar" method="POST">
    <input type="text" name="titulo" placeholder="Nova tarefa..." required>
    <button>Adicionar</button>
  </form>

  {% if tarefas %}
    <ul>
      {% for t in tarefas %}
        <li>
          {{ t.titulo }}
          <a href="/remover/{{ t.id }}"></a>
        </li>
      {% endfor %}
    </ul>
  {% else %}
    <p>Nenhuma tarefa ainda!</p>
  {% endif %}
</body>
</html>

Próximos passos naturais

As tarefas somem ao reiniciar o servidor pois ficam em memória. O próximo passo é conectar ao PostgreSQL com psycopg2 ou SQLAlchemy para persistir os dados. Ou dar um salto maior e conhecer o Django — que já vem com banco de dados integrado desde o início.