Programação em Python – Criando uma API com Flask

Python

Por ser uma linguagem versátil, a programação em Python é bem mais simples, Python possui recursos que, apesar de simples de se utilizar, tornam o aprendizado muito divertido. E utilizado a combinação Python Flask você consegue criar uma aplicação muito poderosa.

Neste tutorial, vamos construir uma API, ou um serviço web, para um aplicativo de lista de tarefas escrito em React. O serviço da API será implementado usando uma arquitetura baseada em REST.

Nosso aplicativo terá as seguintes características principais:

  • Criar um item na lista
  • Consultar todos os itens de uma lista
  • Atualizar os itens com status “Não Iniciado”, “Em andamento”, ou “Completo”.
  • Excluir os itens da lista

Nesse tutorial nós vamos focar apenas na parte do Back-end, então se você quiser criar o front-end do seu aplicativo, eu recomendo fortemente você visitar esse artigo, onde eu ensino passo a passo como criar uma ToDo list usando React. É com esse front-end que vamos trabalhar nesse tutorial.

Vamos conhecer a nossa principal ferramenta para esse projeto.

Programação em Python: O que é Flask

Flask é um framework para o desenvolvimento de aplicações web Python. Flask é do tipo “faça você mesmo”, ele não restringe a estrutura da sua aplicação de nenhuma forma particular. Ele fornece maior flexibilidade e controle aos desenvolvedores. Flask fornece as ferramentas básicas para criar um aplicativo web.

Flask faz parte das categorias da micro-frameworks. Micro-framework são normalmente framework com pouca ou nenhuma dependência de bibliotecas externas.

Isto tem prós e contras. Prós seria que o framework é leve, há pouca dependência para atualização o que pode garantir extra pontos em segurança e estabilidade, contras é que algum tempo você terá que fazer mais trabalho sozinho ou aumentar a lista de dependências adicionando plugins. No caso do Flask, suas dependências são:

  • Werkzeug uma biblioteca de utilidades do WSGI
  • jinja2 que é o seu mecanismo de templates.

Instalando Flask

Antes de instalar o framework eu recomendo, fortemente, que você crie uma ambiente virtual para a sua aplicação. Se você tem intenção de trabalhar com Python, essa deve ser sempre uma das primeiras coisas a fazer, se você não sabe como fazer isso, também tenho aqui um outro post que ensina o passo a passo, tudo o que você precisa saber sobre ambientes virtuais em Python

Feito isso, podemos então instalar o framework dentro do nosso ambiente virtual, executando o comando:

pip install Flask

Vamos configurar rapidamente o Flask e rodar um servidor web em nossa máquina local. Crie um arquivo com o nome main.py na pasta todo_service e insira esse código.

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello World!'

Após a importação do Flask, nós criamos uma rota. Uma rota, utilizando Flask, é especificada por:

  • Um padrão URL (ex. example.com/api)
  • Um método HTTP (ex. GET, POST)
  • Uma função que recebe e lida com a requisição HTTP.

We link this route with a Python function that will be invoked every time this URL is requested via HTTP. In this case, we configure the root route (/) so that it can be accessed via the default URL http://localhost:5000/.

Iniciando a Aplicação

Com isso já podemos rodar o nosso servidor. Flask é bem simples com isso também, basta rodar o comando abaixo no seu terminal:

FLASK_APP=main.py flask run

essa mensagem deve aparecer no seu console:

Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Certo, o primeiro passo foi dado, já temos um servidor rodando e a nossa primeira rota definida. Se quiser, você pode usar o Postman para testar.

Criando a estrutura de rotas com Flask

Como você vai perceber ao longo desse post, programação em Python é bem simples, e Flaks não torna as coisas complicadas.

O que precisamos fazer agora, é definir as nossas rotas, as rotas serão:

  • GET: /todo/getall- Consulta todas as tarefas
  • POST: /todo/create – Cria uma nova tarefa
  • UPDATE: /todo/update – Atualiza uma tarefa existente
  • DELETE: /todo/delete – Deleta uma tarefa da lista

Para manter as coisas simples, vamos escrever todas as nossas rotas em um único arquivo, embora isso nem sempre seja uma boa prática, especialmente para aplicações muito grandes.

from flask import Flask
app = Flask(__name__)
app.run(debug=True)
@app.route('/todo/getall',methods=['GET'])
def getTasks():
    return 'Get all taks!'
@app.route('/todo/create',methods=['POST'])
def createTask():
    return 'Create new task'
@app.route('/todo/update',methods=['UPDATE'])
def updateTask():
    return 'Update Task'
@app.route('/todo/delete',methods=['DELETE'])
def deleteTask():
    return 'Delete task'

Vamos também criar um arquivo estático para representar nossa lista de tarefas, mas temos um outro post aqui que mostra como conectar o seu projeto em Python ao banco de dados MySQL.

Nossa lista de tarefas inicial vai ser essa:

[
   { "complete": false, "task": "Read about MongoDb" },
   { "complete": false, "task": "Create a React ToDo App" },
   { "complete": false, "task": "Find my key" }
 ]

Uma vez que você esteja confortável com esta estrutura inicial do Flask, você pode reestruturar seu aplicativo da maneira que quiser.

Consultando todas as tarefas

Vamos começar enviando a nossa lista de tarefas para o usuário quando ele consultar a rota todo/getall. Para fazer isso precisamos importa duas bibliotecas que vai nos permitir trabalhar com JSON, jsonfy e json

from flask import Flask
from flask import jsonify
import json
app = Flask(__name__)
app.run(debug=True)
# read file
with open('tasks.json', 'r') as myfile:
    data=myfile.read()
# parse file
obj = json.loads(data)
@app.route('/todo/getall',methods=['GET'])
def getTasks():
    return jsonify(obj)

Se você acessar a rota http://127.0.0.1:5000/todo/getall você vai ver um resultado igual a esse:

Agora vamos fazer o nosso front-end em React receber essas tarefas, vamos fazer algumas mudanças no seu arquivo App.js, Vamos usar mais um Hook, useEffect() para fazer o request da nossa lista.

import React, { useState, useEffect } from 'react';
import './App.css';
import TodoList from './components/TodoList';
import TodoForm from './components/TodoForm';
function App() {
   const [todos, setTodos] = useState([]);
   useEffect(() => {
      const fetchTasks = async () => {
         let response = await fetch('http://localhost:5000/todo/getall'
         );
         if (response.ok) { // if HTTP-status is 200-299
            // get the task lists
            let json = await response.json();
            setTodos(json);
         } else {
            alert("HTTP-Error: " + response.status);
         }
      }
      fetchTasks();
   }, [])
   return (
      <div className="App">
         <TodoForm addTodo={(todo) => {
            if (todo.task.trim().length > 0) {
               setTodos([...todos, todo]);
            }
         }} />
         <TodoList todos={todos} updateTodos={(list) => { setTodos(list) }}></TodoList>
      </div>
   );
}
export default App;

Se você não faz idéia de onde esse código veio, eu sugiro que você de uma conferida nesse post, onde tem todo o código front end que estamos usando.

É bem provável que você terá algum problema com CORS, que é facilmente resolvido em Flask instalando uma pequena biblioteca que resolve esse problema. Instale a biblioteca com o comando:

$pip install -U flask-cors

Depois disso, inclua essas duas linhas no seu arquivo main.py.

from flask import Flask
from flask import jsonify
import json
from flask_cors import CORS #include this line
app = Flask(__name__)
app.run(debug=True)
CORS(app) # include this line

Agora vamos rodar nossa aplicação React para ver o resultado, utilize o comando npm start na pasta do projeto para iniciar.

Programação em Python e Flask

O nosso aplicativo continua funcionando como antes. e se olharmos no Chrome Developer Tools vamos ver que as tarefas já estão vindo do servidor Flask. Sucesso!

Criando um novo item

Para criar um nova tarefa na nossa lista vamos usar o método POST. Precisamos incluir o novo item na lista e retornar para o usuário.

No nosso arquivo main.py vamos alterar a rota todo/create. Vamos definir uma função que vai receber o valor do usuário, adicionar ao array e retornar o item para o usuário, indicando que a operação foi bem sucedida.

@app.route('/todo/create', methods=['POST'])
def createTask():
    # Get item from the POST body
    req_data = request.get_json()
    obj.append(req_data)
    return jsonify(req_data)

No lado do Front end o que precisamos fazer é modificar o nosso arquivo TodoForm.js. Vamos incluir uma função que vai submeter, de forma assíncrona, o item que o usuário digitar no formulário. A função de para submissão é essa:

   async function postData(url = '', data = {}) {
      const response = await fetch(url, {
         method: 'POST',
         headers: {
            'Content-Type': 'application/json'
         },
         body: JSON.stringify(data)
      });
      return response.json();
   }

E vamos chamar a função no nosso método handleSubmit, dessa forma:

   const handleSubmit = async e => {
      e.preventDefault();
      if (!userInput) return;
      await postData('http://localhost:5000/todo/create',
        { complete: false, task: userInput })
        .then(data => {
            addTodo(data);
            setUserInput("");
         })
   };

Nossa aplicação vais estar funcionando assim no momento:

todo app python react flask

Removendo itens da lista

Para deletar um item da lista, vamos enviar um objeto contendo o item, vamos fazer a busca dentro da lista, no servidor, se o item for encontrado, nós removemos usando o método pop().

@app.route('/todo/delete', methods=['DELETE'])
def deleteTask():
    req_data = request.get_json()
    for idx, task in enumerate(obj):
        if task.get('task') == req_data["task"]:
            obj.pop(idx)
            return jsonify(req_data)
    return "Item Not Found"

No front-end precisamos alterar o nosso TodoList.js. Que antes de atualizar a lista no front-end, a função removeTask() vai enviar os objeto com o item para o servidor, se o o retorno for OK nós atualizamos a lista no front-end. A função que vai submeter os valores para o servidor é essa:

async function deleteData(url = '', data = {}) {
   const response = await fetch(url, {
      method: 'DELETE',
      headers: {
         'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
   });
   return response.json();
}

E vamos altera a função removeTask() para incluir a chamada dessa função.

const removeTask = async (index, todo) => {
   await deleteData('http://localhost:5000/todo/delete',
      todo)
      .then(data => {
         const updatedList = todos.filter((task, taskIndex) => {
            return taskIndex !== index;
         });
         updateTodos(updatedList);
      })
}

Um ultimo detalhe, precisamos também atualizar o botão de deletar, antes estávamos passando apenas o index, agora precisamos passar também o objeto todo.

<button className="button" onClick={() => removeTask(index, todo)}>Delete</button>

Atualizando itens da lista

Estamos chegando ao final do projeto. Ultima etapa agora, precisamos atualizar a nossa lista, que no nosso caso é marcar o item como completo ou incompleto. Vamos começar com a nossa rota no nosso servidor Flask.

@app.route('/todo/update', methods=['PUT'])
def updateTask():
    req_data = request.get_json()
    for idx, task in enumerate(obj):
        if task.get('task') == req_data["task"]:
            obj.pop(idx)
            obj.insert(idx,req_data)
            break
    return jsonify(req_data)

Pra não super complicar as coisas, o que estou fazendo é bem simples, eu busco o item na lista, assim que eu encontro, eu removo ele da lista e insiro uma o mesmo elemento, com o valor que estou recebendo do usuário, que para essa função a única coisa que vai mudar é o valor complete:false/true.

Agora o nosso front-end, também segue a mesma idea das outras funções. Vamos primeiro criar uma função para enviar os dados para o servidor, e assim que recebermos a resposta, atualizamos o front-end.

async function updateData(url = '', data = {}) {
   const response = await fetch(url, {
      method: 'PUT',
      headers: {
         'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
   });
   return response.json();
}

Precisamos atualizar nossa função markComplete() para enviar o item que queremos atualizar no servidor. Já faço a mudança para complete:false/true no front-end.

const markComplete = async (index, todo) => {
   const updated = { ...todo, complete: !todo.complete }
   await updateData('http://localhost:5000/todo/update',
      updated)
      .then(data => {
         const updatedList = todos.map((item, id) => {
            if (index !== id) return item;
            return updated;
         });
         updateTodos(updatedList);
      })
}

E por fim, precisamos atualizar a função de click, para então enviar o index e o objeto todo.

...
onClick={() => markComplete(index, todo)}>  
...

Chegou a hora, vamos testar. Seu aplicativo vai estar funcionando como esse que você está vendo no video abaixo.

Conclusão

Como você pode perceber, a programação em Python é bem simples. A combinação entre Python Flask nos permite cria aplicações simples, porém poderosas.

Neste tutorial, nós construimos uma API, para um aplicativo em React. O serviço da API foi implementado usando uma arquitetura baseada em REST.

Espero que tenha gostado, se ficou tiver alguma dúvida, deixe nos comentários, eu respondo 100% dos comentários.

Até a próxima!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

1 Comments

Marcos

Que massa! Gostei muito do tutorial!