Outro dia resolvi criar um frontend em angular para uma api que havia feito em python + flask. Por mera preguiça conveniência, resolvi colocar o Flask para ser o servidor do frontend. É bem simples e exige apenas a rota “catch all” com algumas modificações.
- O que é esta rota “catch all”? É um snippet feito pelo próprio pessoal do Flask, que captura todas as requests e as processa. Foi feito exatamente SPA (single page applications).
- Como as rotas da API estão organizadas? As rotas relativas a api em si estão em um blueprint e organizadas a partir da url “/api/v1“. Todas as outras rotas serão utilizadas pelo frontend. Como o foco do post não é a funcionalidade de blueprints do Flask, não vou detalhar esta parte.
Vamos aos passos necessários…
Definindo diretório para arquivos estáticos
from flask import Flask static_files_dir = "./templates/static" app = Flask(__name__, static_folder=app_settings.FLASK_STATIC_FOLDER)
O primeiro passo é definir o diretório onde ficarão os arquivos do frontend. No código acima, escolhi o diretório “./templates/static” como local para salvar estes arquivos. Então, agora você deve criar este diretório (caso não exista) e copiar o fonte compilado do angular para este local.
Criando rota ‘catch all’
@app.route('/', defaults={'path': ''}) @app.route('/<path:path>') def catch_all(path): _path = path.lower().strip() if path in ["", "/", None]: return send_from_directory(static_files_dir, "index.html", mimetype="text/html") elif _path.endswith(".css"): return send_from_directory(static_files_dir, path, mimetype="text/css") elif _path.endswith(".js"): return send_from_directory(static_files_dir, path, mimetype="application/javascript") return send_from_directory(static_files_dir, path)
O código acima é uma adaptação do código feito pelo pessoal do Flask. O que precisei fazer foi separar o que está sendo solicitado na request e devolver o arquivo junto com o seu respectivo tipo (mimetype). Em versões antigas, isso não era necessário. Todavia, a partir da versão 8 ou 9 do Angular, isso é necessário.
Detalhando um pouco o que está acontecendo nesta rota:
- Nas linhas @app.route(‘/’, defaults={‘path’: ”}) e @app.route(‘/<path:path>’), estou definindo que todas as rotas vão ser direcionadas para este método. Não importa se você acessar o site sem definir um caminho (http://localhost:5000/) ou se tentar acessar um caminho tipo http://localhost:5000/dashboard ou http://localhost:5000/admin/login, todas estas requests vão cair neste mesmo método.
- _path = path.lower().strip(): O argumento path é o caminho que o usuário tentou acessar. Criei a variável _path para normalizar o que está chegando, ou seja, deixo todas as rotas em minúsculo e removo espaços extras.
- Nos ifs, estou verificando:
- Se o usuário entrou no site sem informar uma rota: Neste caso, retorno o index.html.
- Se a rota normalizada terminar com .css: Neste caso, retorno o arquivo CSS solicitado, incluindo o mimetype correto.
- Se a rota normalizada terminar com .js: Neste caso, , retorno o script JS solicitado, incluindo o mimetype correto.
- Qualquer outra rota, retorno o arquivo solicitado, mas nao informo um mimetype específico.
Esta rota ‘catch-all’ não vai interferir com a api, pois, utilizando blueprint, já registrei as rotas iniciadas em /api/v1.
A aplicação Angular que eu fiz é bem simples, mas funcionou normalmente com esta abordagem.
Espero ter ajudado!
Latest posts by Breno RdV (see all)
- Estamos de mudança! - abril 28, 2024
- O que é Metaclass e como ela funciona. (#python #dev #metaclass) - janeiro 11, 2023
- Entenda a mágica dos Generators. (#python, #dev, #generator, #iterator) - dezembro 28, 2022