Cómo procesar los datos de solicitud entrantes en Flask

Introducción

Las aplicaciones web requieren con frecuencia el procesamiento de los datos de las solicitudes entrantes de los usuarios. Esta carga útil puede tener la forma de cadenas de consulta, datos de formulario y objetos JSON. Flask, como cualquier otro marco web, le permite acceder a los datos de la solicitud.

En este tutorial, se creará una aplicación Flask con tres rutas que aceptan cadenas de consulta, datos de formulario u objetos JSON.

Requisitos previos

Para completar este tutorial, necesitará lo siguiente:

  • Este proyecto requerirá que Python se instale en un entorno local.
  • Este proyecto usará Pipenv, una herramienta preparada para la producción que pretende traer lo mejor de todos los mundos de empaquetado al mundo de Python. Aprovecha Pipfile, pip, y virtualenv en un solo comando.
  • Se requerirá descargar e instalar una herramienta como Postman para probar los puntos finales de API.

Este tutorial se verificó con Pipenv v2020.11.15, Python v3.9.0 y Flask v1.1.2.

Configuración del proyecto

Para demostrar las diferentes formas de usar solicitudes, deberá crear una aplicación Flask. Aunque la aplicación de ejemplo utiliza una estructura simplificada para las funciones y las rutas de vista, lo que se aprende en este tutorial puede aplicarse a cualquier método de organización de las vistas, como las vistas basadas en clases, los planos o una extensión como Flask-Via.

Primero, deberá crear un directorio de proyecto. Abra su terminal y ejecute el siguiente comando:

  • mkdir flask_request_example

Luego, diríjase al nuevo directorio:

  • cd flask_request_example

Luego, instale Flask. Abra su terminal y ejecute el siguiente comando:

  • pipenv install Flask

El comando pipenv creará un virtualenv para este proyecto, un Pipfile, para instalar flask y un Pipfile.lock.

Para activar el virtualenv del proyecto, ejecute el siguiente comando:

  • pipenv shell

Para acceder a los datos entrantes en Flask, tiene que usar el objeto request. El objeto request contiene todos los datos entrantes de la solicitud, que incluye el mimetype, recomendante, dirección IP, datos sin procesar, HTTP y encabezados, entre otras cosas.

Aunque toda la información que contiene el objeto de solicitud puede ser útil, para los propósitos de este artículo, se centrará en los datos que normalmente son suministrados directamente por la persona que llama al punto final.

Para obtener acceso al objeto de solicitud en Flask, deberá importarlo desde la biblioteca Flask:

from flask import request 

Luego, podrá usarlo en cualquiera de sus funciones de vista.

Utilice su editor de código para crear un archivo app.py. Importe Flask y el objeto request. Y también establezca rutas para query-example, form-example, y 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) 

Luego, abra su terminal e inicie la aplicación con el siguiente comando:

  • python app.py

La aplicación se iniciará en el puerto 5000, por lo que puede ver cada ruta en su navegador con los siguientes enlaces:

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) 

El código establece tres rutas y visitar cada una de ellas mostrará los mensajes de "Query String Example", "Form Data Example" y "JSON Object Example", respectivamente.

Uso de argumentos Query

Los argumentos de URL que se añaden a una cadena de consulta son una forma común de pasar los datos a una aplicación web. Al navegar por la web, es probable que haya encontrado alguna vez una cadena de consulta.

Una cadena de consulta se parece a lo siguiente:

example.com?arg1=value1&arg2=value2 

La cadena de consulta comienza después del carácter de signo de interrogación (?) :

example.com?arg1=value1&arg2=value2 

Y tiene pares clave-valor separados por un carácter de “y” comercial (&):

example.com?arg1=value1&arg2=value2 

Para cada par, la clave va seguida por un signo de igualdad (=) y, a continuación, el valor.

arg1 : value1 arg2 : value2 

Las cadenas de consulta son útiles para pasar datos que no requieren que el usuario realice ninguna acción. Puede generar una cadena de consulta en algún lugar de su aplicación y añadirla a una URL para que cuando un usuario realice una solicitud, los datos se pasen automáticamente para ellos. Una cadena de consulta también puede generarse a través de formularios que tienen GET como método.

Vamos a añadir una cadena de consulta a la ruta query-example. En este ejemplo hipotético, se proporcionará el nombre de un lenguaje de programación que se mostrará en la pantalla. Cree una clave de "language" y un valor de "Python":

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

Si ejecuta la aplicación y navega a esa URL, verá que sigue mostrando un mensaje de "Query String Example".

Tendrá que programar la parte que maneja los argumentos de la consulta. Este código leerá la clave de language usando request.args.get('language') o request.args['language'].

Al invocar request.args.get('language'), la aplicación continuará ejecutándose si la clave de language no existe en la URL. En ese caso, el resultado del método será None.

Al invocar request.args['language'], la aplicación mostrará un error 400 si la clave de language no existe en la URL.

Cuando se trata de cadenas de consulta, se recomienda usar request.args.get() para evitar que la aplicación falle.

Vamos a leer la clave language y mostrarla como resultado.

Modifique la ruta query-example en app.py con el siguiente 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) 

Luego, ejecute la aplicación y diríjase a la URL:

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

El navegador debe mostrar el siguiente mensaje:

OutputThe language value is: Python 

El argumento de la URL se asigna a la variable language y luego se devuelve al navegador.

Para añadir más parámetros de cadena de consulta, puede añadir ampersands y los nuevos pares clave-valor al final de la URL. Cree una clave de "framework" y un valor de "Flask":

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

Y si desea más, continúe añadiendo ampersands y pares clave-valor. Cree una clave de "website" y un valor de "DigitalOcean":

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

Para obtener acceso a esos valores, seguirá usando request.args.get() o request.args[]. Vamos a usar ambos para demostrar lo que sucede cuando falta una clave. Modifique la ruta query_example para asignar el valor de los resultados a variables y luego mostrarlos:

@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) 

Luego, ejecute la aplicación y diríjase a la URL:

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

El navegador debe mostrar el siguiente mensaje:

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

Elimine la clave de language de la URL:

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

El navegador debe mostrar el siguiente mensaje con None cuando no se proporciona un valor para language:

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

Elimine la clave de framework de la URL:

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

El navegador debería encontrar un error porque está esperando un 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' 

Ahora, ya comprende cómo se manejan las cadenas de consulta. Continuemos con el siguiente tipo de datos entrantes.

Uso de datos de formulario

Los datos de formulario provienen de un formulario que ha sido enviado como solicitud POST a una ruta. Por lo tanto, en lugar de ver los datos en la URL (excepto en los casos en que el formulario se envía con una solicitud GET), los datos del formulario pasarán a la aplicación entre bastidores. Aunque no se pueden ver fácilmente los datos del formulario que se pasan, su aplicación puede leerlos.

Para demostrarlo, modifique la ruta de form-example en app.py para aceptar las solicitudes GET y POST, y devolver un formulario:

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>''' 

Luego, ejecute la aplicación y diríjase a la URL:

http://127.0.0.1:5000/form-example 

El navegador debe mostrar un formulario con dos campos de entrada, uno para language y otro para framework, así como para un botón de envío.

Lo más importante que hay que saber sobre este formulario es que realiza una solicitud POST a la misma ruta que generó el formulario. Las claves que se leerán en la aplicación provienen de los atributos de nombre de las entradas de nuestro formulario. En este caso, language y framework son los nombres de las entradas, por lo que tendrá acceso a ellos en la aplicación.

Dentro de la función de vista, deberá verificar si el método de solicitud es GET o POST. Si es una solicitud GET, puede mostrar el formulario. De lo contrario, si se trata de una solicitud POST, entonces querrá procesar los datos entrantes.

Modifique la ruta de form-example en app.py con el siguiente 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>''' 

Luego, ejecute la aplicación y diríjase a la URL:

http://127.0.0.1:5000/form-example 

Complete el campo de language con el valor de Python y el campo de framework con el valor de Flask. Luego, presione Submit (Enviar).

El navegador debe mostrar el siguiente mensaje:

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

Ahora, entiende cómo manejar los datos del formulario. Continuaremos con el siguiente tipo de datos entrantes.

Uso de datos JSON

Los datos JSON generalmente se construye a través de un proceso que invoca la ruta.

Un ejemplo de objeto JSON tiene el siguiente aspecto:

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

Esta estructura puede permitir que se pasen datos mucho más complicados en lugar de las cadenas de consulta y los datos del formulario. En el ejemplo, se ve los objetos JSON anidados y una matriz de elementos. Flask puede gestionar este formato de datos.

Modifique la ruta de form-example en app.py para aceptar las solicitudes POST e ignore otras solicitudes como GET:

app.py

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

A diferencia del navegador web que se utiliza para las cadenas de consulta y los datos de formulario, para los fines de este artículo, para enviar un objeto JSON, se utilizará Postman para enviar solicitudes personalizadas a las URL.

Nota: Si necesita ayuda para navegar por la interfaz de Postman para las solicitudes, consulte la documentación oficial.

En Postman, añada la URL y cambie el tipo a POST. En la pestaña de cuerpo, cambie a raw y seleccione JSON en el menú desplegable.

Estos ajustes son necesarios para que Postman pueda enviar datos JSON correctamente, y para que su aplicación Flask comprenda que está recibiendo JSON:

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

Luego, copie el ejemplo JSON anterior en la entrada de texto.

Envíe la solicitud y debería obtener "JSON Object Example" como respuesta. Eso es bastante decepcionante, pero es de esperar porque el código para gestionar la respuesta de los datos JSON aún no se ha escrito.

Para leer los datos, debe entender cómo Flask traduce los datos JSON en las estructuras de datos de Python:

  • Cualquier cosa que sea un objeto se convierte en una dictadura de Python. {"key" : "value"} en JSON corresponde a somedict['key'], que devuelve un valor en Python.
  • Una matriz en JSON se convierte en una lista en Python. Dado que la sintaxis es la misma, aquí hay un ejemplo de una lista: [1,2,3,4,5].
  • Los valores dentro de las comillas en el objeto JSON se convierten en cadenas en Python.
  • Los booleanos true y false se convierten en True y False en Python.
  • Por último, los números sin comillas se convierten en números en Python.

Ahora vamos a trabajar en el código para leer los datos JSON entrantes.

Primero, vamos a asignar todo desde el objeto JSON a una variable usando request.get_json().

request.get_json() convierte el objeto JSON en datos de Python. Asignemos los datos de la solicitud entrante a las variables y devolvámoslos haciendo los siguientes cambios en la ruta 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) 

Tenga en cuenta cómo se accede a los elementos que no están en el nivel superior. Se utiliza ['version']['python'] porque se está entrando en un objeto anidado. Y ['examples'][0] se utiliza para acceder al índice 0 en la matriz de ejemplos.

Si el objeto JSON enviado con la solicitud no tiene una clave a la que se accede en su función de vista, entonces la solicitud fallará. Si no quiere que la solicitud falle cuando no existe una clave, tendrá que verificar si la clave existe antes de intentar ingresarla.

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) 

Ejecute la aplicación y envíe la solicitud JSON de ejemplo usando Postman. En la respuesta, obtendrá el siguiente resultado:

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 

Ahora comprende cómo se manejan los objetos JSON.

Conclusión

En este artículo, se creó una aplicación Flask con tres rutas que aceptan cadenas de consulta, datos de formulario u objetos JSON.

Además, recuerde que todos los enfoques tuvieron que abordar la consideración recurrente de fallar con gracia cuando falta una clave.

Advertencia: Un tema que no se cubrió en este artículo fue cómo desinfectar la entrada de los usuarios. La sanitización de la entrada de lo usuario garantizaría que los datos leídos por la aplicación no causen un fallo inesperado o que se salten las medidas de seguridad.

Si desea obtener más información sobre Flask, consulte nuestra página del tema Flask para consultar ejercicios y proyectos de programación.