Como processar dados de solicitação de entrada no Flask

Introdução

Muitas vezes, os aplicativos Web necessitam do processamento dos dados de solicitação da entrada de usuários. Essa carga pode existir na forma de strings de consulta, dados de formulário e objetos JSON. O Flask, assim como qualquer outro framework Web, permite acessar os dados de solicitação.

Neste tutorial, será construído um aplicativo Flask com três rotas que aceitam strings de consulta, dados de formulário ou objetos JSON.

Pré-requisitos

Para completar este tutorial, você precisará de:

  • Este projeto exigirá o Python instalado em um ambiente local.
  • Este projeto usará o Pipenv, uma ferramenta pronta para a produção que visa trazer o melhor de todos os mundos do empacotamento ao mundo do Python. Ele tira proveito do Pipfile, pip e o virtualenv em um único comando.
  • Baixar e instalar uma ferramenta como o Postman será necessário para testar os pontos de extremidade da API.

Este tutorial foi verificado com o Pipenv v2020.11.15, Python v3.9.0 e o Flask v1.1.2.

Configurando o projeto

Para demonstrar as diferentes formas de usar solicitações, será necessário criar um aplicativo Flask. Embora o aplicativo de exemplo use uma estrutura simplificada para as funções de visualização e rotas, o que você aprenderá neste tutorial pode ser aplicado a qualquer método para organizar suas visualizações, como as visualizações baseadas em classe, blueprints, ou uma extensão como o Flask-Via.

Primeiramente, será necessário criar um diretório de projeto. Abra seu terminal e execute o seguinte comando:

  • mkdir flask_request_example

Em seguida, navegue até o novo diretório:

  • cd flask_request_example

Em seguida, instale o Flask. Abra seu terminal e execute o seguinte comando:

  • pipenv install Flask

O comando pipenv criará um virtualenv para este projeto, um Pipfile, e também instalará o flask e um Pipfile.lock.

Para ativar o virtualenv do projeto, execute o seguinte comando:

  • pipenv shell

Para acessar os dados de entrada no Flask, é necessário usar o objeto request (solicitação). O objeto request contém todos os dados de entrada da solicitação, que inclui o tipomime, referenciador, endereço IP, dados brutos, método HTTP, cabeçalhos, entre outras coisas.

Embora todas as informações contidas no objeto request possam ser úteis, para os fins deste artigo, você se concentrará nos dados que são normalmente fornecidos diretamente pelo chamador do ponto de extremidade.

Para ter acesso ao objeto request no Flask, será necessário importá-lo da biblioteca do Flask:

from flask import request 

Depois disso, você pode usá-lo em qualquer uma das suas funções de visualização.

Use seu editor de código para criar um arquivo app.py. Importe o Flask e o objeto request. Além disso, estabeleça rotas para query-example, form-example e json-example:

app.py

# import main Flask class and request object from flask import Flask, request  # create the Flask app app = Flask(__name__)  @app.route('/query-example') def query_example():     return 'Query String Example'  @app.route('/form-example') def form_example():     return 'Form Data Example'  @app.route('/json-example') def json_example():     return 'JSON Object Example'  if __name__ == '__main__':     # run app in debug mode on port 5000     app.run(debug=True, port=5000) 

Em seguida, abra seu terminal e inicie o aplicativo com o seguinte comando:

  • python app.py

O aplicativo será iniciado na porta 5000. Sendo assim, você pode visualizar cada rota no seu navegador com os seguintes links:

http://127.0.0.1:5000/query-example (or localhost:5000/query-example) http://127.0.0.1:5000/form-example (or localhost:5000/form-example) http://127.0.0.1:5000/json-example (or localhost:5000/json-example) 

O código estabelece três rotas e visitar cada rota exibirá as mensagens de "Query String Example", "Form Data Example" e "JSON Object Example", respectivamente.

Usando argumentos de consulta

Os argumentos de URL que você adiciona a uma string de consulta representam uma maneira comum de passar dados para um aplicativo Web. Enquanto navegava na Web, você provavelmente já se deparou com uma string de consulta antes.

Uma string de consulta se assemelha ao seguinte:

example.com?arg1=value1&arg2=value2 

A string de consulta começa após o caractere de ponto de interrogação (?):

example.com?arg1=value1&arg2=value2 

E possui pares de chave-valor separados por um caractere de E comercial (&):

example.com?arg1=value1&arg2=value2 

Para cada par, a chave é seguida de um caractere de sinal igual (=) e então o valor.

arg1 : value1 arg2 : value2 

As strings de consulta são úteis para passar dados que não exigem que o usuário tome nenhuma ação. Se quiser, é possível gerar uma string de consulta em algum lugar do seu aplicativo e adicioná-la a uma URL para que quando um usuário fizer uma solicitação, os dados sejam automaticamente passados a eles. Uma string de consulta também pode ser gerada por formulários que têm o GET como método.

Vamos adicionar uma string de consulta à rota query-example. Neste exemplo hipotético, você adicionará o nome de uma linguagem de programação que será exibido na tela. Crie uma chave "language" e um valor de "Python":

http://127.0.0.1:5000/query-example?language=Python 

Se executar o aplicativo e navegar até essa URL, você verá que ele ainda exibe uma mensagem de "Query String Example".

Será necessário programar a parte que lida com os argumentos de consulta. Esse código lerá a chave language usando o request.args.get('language') ou request.args['language'].

Se chamarmos o request.args.get('language'), o aplicativo continuará em execução se a chave language não existir na URL. Neste caso, o resultado do método será None.

Se chamarmos o request.args['language'], o aplicativo retornará um erro 400 se a chave language não existir na URL.

Ao lidar com strings de consulta, é recomendável usar o request.args.get() para evitar que o aplicativo falhe.

Vamos ler a chave language e exibi-la como um resultado.

Modifique a rota query-example no app.py com o seguinte código:

app.py

@app.route('/query-example') def query_example():     # if key doesn't exist, returns None     language = request.args.get('language')      return '''<h1>The language value is: {}</h1>'''.format(language) 

Em seguida, execute o aplicativo e navegue até a URL:

http://127.0.0.1:5000/query-example?language=Python 

O navegador exibirá a seguinte mensagem:

OutputThe language value is: Python 

O argumento da URL é atribuído à variável language e então é retornado ao navegador.

Para adicionar mais parâmetros à string de consulta, adicione caracteres & e os novos pares de chave-valor no final da URL. Crie uma chave “framework” e um valor de ”Flask”:

http://127.0.0.1:5000/query-example?language=Python&framework=Flask 

E se quiser ainda mais, continue adicionando caracteres & e pares de chave-valor. Crie uma chave “website” e um valor de ”DigitalOcean”:

http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean 

Para ter acesso a esses valores, você ainda usará o request.args.get() ou request.args[]. Vamos usar ambos para demonstrar o que acontece quando uma chave estiver faltando. Modifique a rota query_example para atribuir o valor dos resultados às variáveis e então exibi-las:

@app.route('/query-example') def query_example():     # if key doesn't exist, returns None     language = request.args.get('language')      # if key doesn't exist, returns a 400, bad request error     framework = request.args['framework']      # if key doesn't exist, returns None     website = request.args.get('website')      return '''               <h1>The language value is: {}</h1>               <h1>The framework value is: {}</h1>               <h1>The website value is: {}'''.format(language, framework, website) 

Em seguida, execute o aplicativo e navegue até a URL:

http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean 

O navegador exibirá a seguinte mensagem:

OutputThe language value is: Python The framework value is: Flask The website value is: DigitalOcean 

Remova a chave language da URL:

http://127.0.0.1:5000/query-example?framework=Flask&website=DigitalOcean 

O navegador exibirá a mensagem a seguir. O valor None é utilizado se um valor não for fornecido para language:

OutputThe language value is: None The framework value is: Flask The website value is: DigitalOcean 

Remova a chave framework da URL:

http://127.0.0.1:5000/query-example?language=Python&website=DigitalOcean 

O navegador deve encontrar um erro porque está esperando um valor para framework:

Outputwerkzeug.exceptions.BadRequestKeyError werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. KeyError: 'framework' 

Agora, você sabe como manusear strings de consulta. Vamos continuar para o próximo tipo de dados de entrada.

Usando dados de formulários

Os dados de formulário vêm de um formulário que foi enviado como uma solicitação POST para uma rota. Assim, ao invés de ver os dados na URL (exceto para casos quando o formulário for enviado com uma solicitação GET), os dados do formulário serão passados para o aplicativo em segundo plano. Embora os dados de formulário que são passados não possam ser facilmente vistos, seu aplicativo ainda pode lê-los.

Para demonstrar isso, modifique a rota form-example no app.py para aceitar tanto as solicitações GET quanto POST e retornar um formulário:

app.py

# allow both GET and POST requests @app.route('/form-example', methods=['GET', 'POST']) def form_example():     return '''               <form method="POST">                   <div><label>Language: <input type="text" name="language"></label></div>                   <div><label>Framework: <input type="text" name="framework"></label></div>                   <input type="submit" value="Submit">               </form>''' 

Em seguida, execute o aplicativo e navegue até a URL:

http://127.0.0.1:5000/form-example 

O navegador exibirá um formulário com dois campos de entrada — um para language e um para framework — e um para o botão de enviar.

A coisa mais importante para saber sobre este formulário é que ele executa uma solicitação POST na mesma rota que gerou o formulário. Todas as chaves que serão lidas no aplicativo vêm dos atributos name em nossas entradas de formulários. Neste caso, language e framework são os nomes das entradas. Sendo assim, você terá acesso a eles no aplicativo.

Dentro da função de visualização, será necessário verificar se o método de solicitação é o GET ou POST. Se for uma solicitação GET, você pode exibir o formulário. Caso contrário, se for uma solicitação POST, então será preciso processar os dados de entrada.

Modifique a rota form-example no app.py com o seguinte código:

app.py

# allow both GET and POST requests @app.route('/form-example', methods=['GET', 'POST']) def form_example():     # handle the POST request     if request.method == 'POST':         language = request.form.get('language')         framework = request.form.get('framework')         return '''                   <h1>The language value is: {}</h1>                   <h1>The framework value is: {}</h1>'''.format(language, framework)      # otherwise handle the GET request     return '''            <form method="POST">                <div><label>Language: <input type="text" name="language"></label></div>                <div><label>Framework: <input type="text" name="framework"></label></div>                <input type="submit" value="Submit">            </form>''' 

Em seguida, execute o aplicativo e navegue até a URL:

http://127.0.0.1:5000/form-example 

Preencha o campo language com o valor de Python e o campo framework com o valor de Flask. Em seguida, pressione Submit.

O navegador exibirá a seguinte mensagem:

OutputThe language value is: Python The framework value is: Flask 

Agora, você sabe como manusear dados de formulários. Vamos continuar para o próximo tipo de dados de entrada.

Usando dados de JSON

Os dados de JSON são normalmente construídos por um processo que chama a rota.

Um objeto JSON de exemplo se parece com este:

{   "language": "Python",   "framework": "Flask",   "website": "Scotch",   "version_info": {     "python": "3.9.0",     "flask": "1.1.2"   },   "examples": ["query", "form", "json"],   "boolean_test": true } 

Essa estrutura permite que dados muito mais complicados sejam passados se comparada a strings de consulta e dados de formulários. No exemplo, podemos ver objetos JSON aninhados e uma matriz de itens. O Flask é capaz de manipular este formato de dados.

Modifique a rota form-example no app.py para aceitar solicitações POST e ignorar outras solicitações, como GET:

app.py

@app.route('/json-example', methods=['POST']) def json_example():     return 'JSON Object Example' 

Diferentemente do navegador Web usado para strings de consulta e dados de formulários, para os fins deste artigo, um Postman será usado para enviar solicitações personalizadas para URLs de forma a enviar um objeto JSON.

Nota: se precisar de ajuda para navegar pela interface do Postman para as solicitações, consulte a documentação oficial.

No Postman, adicione a URL e altere o tipo para POST. Na guia de corpo, mude para raw e selecione JSON na lista suspensa.

Essas configurações são necessárias para que o Postman consiga enviar dados de JSON corretamente e para que seu aplicativo Flask compreenda que está recebendo JSON:

POST http://127.0.0.1:5000/json-example Body raw JSON 

Em seguida, copie o exemplo de JSON anterior na entrada de texto.

Envie a solicitação e você deve obter uma resposta “JSON Object Example”. Isso pode ser um tanto decepcionante, mas é de se esperar, porque o código para manusear a resposta dos dados de JSON ainda não está escrito.

Para ler os dados, é necessário entender como o Flask traduz dados de JSON para estruturas de dados do Python:

  • Qualquer coisa que seja um objeto é convertida para um dict do Python. {“key” : ”value”} em JSON corresponde a somedict['key'], que retorna um valor em Python.
  • Uma matriz em JSON é convertida para uma lista no Python. Como a sintaxe é a mesma, aqui está uma lista de exemplo: [1,2,3,4,5]
  • Os valores dentro de aspas no objeto JSON se tornam strings no Python.
  • Os booleanos true e false se tornam True e False no Python.
  • Por fim, os números sem aspas em sua volta se tornam números no Python.

Agora, vamos trabalhar com o código para que leia os dados de JSON de entrada.

Primeiramente, vamos atribuir tudo do objeto JSON a uma variável usando o request.get_json().

O request.get_json() converte o objeto JSON para dados do Python. Vamos atribuir os dados de solicitação de entrada às variáveis e retorná-las fazendo as seguintes alterações na rota json-example:

app.py

# GET requests will be blocked @app.route('/json-example', methods=['POST']) def json_example():     request_data = request.get_json()      language = request_data['language']     framework = request_data['framework']      # two keys are needed because of the nested object     python_version = request_data['version_info']['python']      # an index is needed because of the array     example = request_data['examples'][0]      boolean_test = request_data['boolean_test']      return '''            The language value is: {}            The framework value is: {}            The Python version is: {}            The item at index 0 in the example list is: {}            The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test) 

Note como os elementos que não estão no nível superior são acessados. O ['version']['python'] é usado porque você está entrando em um objeto aninhado. E o ['examples'][0] é usado para acessar o índice 0 na matriz de exemplos.

Se o objeto JSON enviado com a solicitação não tiver uma chave que seja acessada na sua função de visualização, então a solicitação falhará. Se não quiser que ela falhe quando uma chave não existir, será necessário verificar se a chave existe antes de tentar acessá-la.

app.py

# GET requests will be blocked @app.route('/json-example', methods=['POST']) def json_example():     request_data = request.get_json()      language = None     framework = None     python_version = None     example = None     boolean_test = None      if request_data:         if 'language' in request_data:             language = request_data['language']          if 'framework' in request_data:             framework = request_data['framework']          if 'version_info' in request_data:             if 'python' in request_data['version_info']:                 python_version = request_data['version_info']['python']          if 'examples' in request_data:             if (type(request_data['examples']) == list) and (len(request_data['examples']) > 0):                 example = request_data['examples'][0]          if 'boolean_test' in request_data:             boolean_test = request_data['boolean_test']      return '''            The language value is: {}            The framework value is: {}            The Python version is: {}            The item at index 0 in the example list is: {}            The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test) 

Execute o aplicativo e envie a solicitação JSON de exemplo usando o Postman. Na resposta, o seguinte resultado será exibido:

OutputThe language value is: Python The framework value is: Flask The Python version is: 3.9 The item at index 0 in the example list is: query The boolean value is: false 

Agora, você sabe como processar objetos JSON.

Conclusão

Neste tutorial, você construiu um aplicativo Flask com três rotas que aceitam strings de consulta, dados de formulário ou objetos JSON.

Além disso, lembre-se de que todas as abordagens precisaram lidar com o fato recorrente de falharem graciosamente quando uma chave está faltando.

Aviso: um tópico que não foi abordado neste artigo é a limpeza das entradas de usuário. A limpeza das entradas de usuário garante que os dados lidos pelo aplicativo não façam com que algo falhe de maneira inesperada ou contorne medidas de segurança.

Se quiser aprender mais sobre o Flask, confira nossa página de tópico do Flask para exercícios e projetos de programação.