Aplicaciones de una sola página con Vue.js y Flask: API RESTful con Flask

Bienvenido a la cuarta publicación sobre el uso de Vue.js y Flask para el desarrollo web completo. El enfoque de esta publicación será construir una API REST de back-end usando Py...

API RESTful con Flask

Bienvenido a la cuarta publicación sobre el uso de Vue.js y Flask para el desarrollo web completo. El enfoque de esta publicación será la creación de una API REST de back-end utilizando el marco web Flask basado en Python.

El código de esta publicación está en un repositorio en mi cuenta de GitHub en la rama FourthPost.

Contenido de la serie

  1. Configuración y familiarización con VueJS
  2. Navegación por el enrutador Vue
  3. Gestión de estados con Vuex
  4. API RESTful con Flask (usted está aquí)
  5. Integración AJAX con API REST
  6. Autenticación JWT
  7. Implementación en un servidor privado virtual

Breve explicación de Flask

Flask es un micro-marco basado en Python para la creación rápida de prototipos y el desarrollo de aplicaciones web de tamaño pequeño a moderado. Flask ya ha sido cubierto en un par de publicaciones anteriores aquí y aquí en wikihtp, así que no voy a entrar en gran detalle perteneciente a las partes básicas o comunes de Flask. En su lugar, adoptaré un enfoque más pragmático centrándome principalmente en construir una API RESTful para alimentar la interfaz con datos, que cubrí en los artículos previos a este.

Scaffolding out the backend Project Files

Comienzo en el directorio /backend creando un Python3 ambiente virtual e instalando Flask y algunas otras bibliotecas necesarias.

1
2
3
$ python -m venv venv
$ source venv/bin/activate
(venv) $ pip install Flask Flask-SQLAlchemy Flask-Migrate Flask-Script requests

Una cosa que hace que Flask (y en gran parte todo el ecosistema de Python) sea tan increíble es la gran cantidad de paquetes bien diseñados disponibles en [PyPI] (https://pypi.python.org/pypi). A continuación se muestra una breve explicación de las bibliotecas que instalé y su uso previsto.

  • Frasco: micro marco web
  • Flask-SQLAlchemy: ORM basado en SQLAlchemy con un poco de salsa increíble específica de Flask empaquetada con él
  • Flask-Migrate: biblioteca de migración de base de datos
  • Flask-Script: paquete extremadamente útil para interactuar con una aplicación Flask desde la línea de comandos
  • solicitudes: un paquete útil para realizar solicitudes de red que usaré para probar la API REST

En el directorio /backend creo algunos archivos nuevos llamados manage.py y appserver.py. Además, crearé un nuevo directorio dentro de /backend que se convertirá en mi aplicación Flask "surveyapi". Dentro del directorio de encuestas creo los archivos __init__.py, models.py, application.py y api.py. Esto da como resultado una estructura de directorios que comienza en /backend así (omitiendo el directorio venv).

1
2
3
4
5
6
7
8
├── manage.py
├── appserver.py
└── surveyapi
    ├── __init__.py
    ├── api.py
    ├── application.py
    ├── config.py
    └── models.py

A continuación se muestra una breve descripción de para qué se utilizará cada archivo:

  • manage.py: acceso a la instancia de la aplicación Flask para varios comandos Flask-Script
  • appserver.py: script de inicio para ejecutar la aplicación Surveyapi
  • Surveyapi/: la aplicación Flask backend
  • __init__.py: convierte el directorio de encuestas en un paquete de Python válido
  • api.py: para definir puntos finales de ruta de API REST capaces de consumir y producir solicitudes y respuestas JSON
  • application.py: para crear una instancia de la aplicación Flask
  • config.py: contiene ajustes de configuración para la aplicación Flask
  • models.py: para definir clases que servirán como objetos de datos para la aplicación de encuesta, como Encuesta, Pregunta y Elección

Creación de una fábrica de aplicaciones {#creación de una fábrica de aplicaciones}

Comenzaré a codificar la aplicación Surveyapi definiendo algunas configuraciones dentro de config.py así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
"""
config.py
- settings for the flask application object
"""

class BaseConfig(object):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///survey.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # used for encryption and session management
    SECRET_KEY = 'mysecretkey'

Esta clase de configuración define un URI de conexión de la base de datos de la aplicación SQLALCHEMY_DATABASE_URI a un solo archivo base de datos SQLite llamado encuesta.db. También proporciona la opción de configuración SECRET_KEY que se utiliza para el cifrado.

Dentro de application.py crearé lo que se conoce como una función de fábrica de aplicaciones, que hace exactamente lo que parece, crea una instancia de aplicación Flask. Además de instanciar una instancia de Flask, también genera el objeto BaseConfig y registra el modelo de rutas API que haré a continuación.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
"""
application.py
- creates a Flask app instance and registers the database object
"""

from flask import Flask

def create_app(app_name='SURVEY_API'):
    app = Flask(app_name)
    app.config.from_object('surveyapi.config.BaseConfig')
    from surveyapi.api import api
    app.register_blueprint(api, url_prefix="/api")
    return app

API de modelo

A continuación, pasaré al módulo api.py donde puedo definir un objeto Blueprint llamado api que contiene rutas RESTful. Para simplificar las cosas, comenzaré simplemente definiendo una función de vista simple llamada say_hello() asociada con el punto final /api/hello/<string:name>/. La parte <string:name> de la URL es una variable de cadena dinámica que se pasa a la función de vista say_hello(name) como un parámetro de función que utilizo en el mensaje de respuesta JSON que se devuelve.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
"""
api.py
- provides the API endpoints for consuming and producing
  REST requests and responses
"""

from flask import Blueprint, jsonify, request

api = Blueprint('api', __name__)

@api.route('/hello/<string:name>/')
def say_hello(name):
    response = { 'msg': "Hello {}".format(name) }
    return jsonify(response)

Punto de entrada del servidor de desarrollo y validación de la configuración {#punto de entrada del servidor de desarrollo y validación de la configuración}

Para probar esto, necesito agregar un par de líneas de código en appserver.py para crear una instancia de la aplicación. Esto me permite activar el servidor de desarrollo Flask llamando al método run() en la instancia app.

1
2
3
4
5
6
7
8
9
"""
appserver.py
- creates an application instance and runs the dev server
"""

if __name__ == '__main__':
    from surveyapi.application import create_app
    app = create_app()
    app.run()

Para ejecutar el servidor de desarrollo de Flask, todo lo que necesito hacer es iniciar el intérprete de Python y alimentarlo con el script appserver.py como se muestra a continuación.

1
2
3
4
5
(venv) $ python appserver.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 676-284-544

Ahora, para probar el nuevo punto final, en una nueva terminal con el entorno virtual activado, iniciaré un intérprete de Python y haré una solicitud GET a http://localhost:5000/api/hello/adam/ usando requests paquete.

1
2
3
4
5
(venv) $ python
>>> import requests
>>> response = requests.get('http://localhost:5000/api/hello/adam/')
>>> print(response.json())
{'msg': 'Hello adam'}

Definición de la capa de datos

Ahora que verifiqué que tengo una aplicación Flask en funcionamiento, puedo concentrarme en construir la capa de datos con la ayuda de Flask-SQLAlchemy ORM. La implementación de una capa de datos requerirá escribir algunas clases de datos dentro de models.py, como:

  • Encuesta: este es el objeto de nivel superior que contendrá una o más preguntas junto con sus opciones
  • Pregunta: objetos que pertenecen a un objeto de encuesta y contienen opciones
  • Elección: objetos que pertenecen a una pregunta y representan opciones para la pregunta de la encuesta

Estas clases de datos presentarán campos que en gran parte imitarán los descritos anteriormente en los artículos sobre la creación de la aplicación frontend Vue.js, pero se asignarán a las tablas de la base de datos donde se conservarán sus datos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"""
models.py
- Data classes for the surveyapi application
"""

from datetime import datetime
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Survey(db.Model):
    __tablename__ = 'surveys'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    questions = db.relationship('Question', backref="survey", lazy=False)

    def to_dict(self):
        return dict(id=self.id,
                    name=self.name,
                    created_at=self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
                    questions=[question.to_dict() for question in self.questions])

class Question(db.Model):
    __tablename__ = 'questions'

    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String(500), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    survey_id = db.Column(db.Integer, db.ForeignKey('surveys.id'))
    choices = db.relationship('Choice', backref='question', lazy=False)

    def to_dict(self):
        return dict(id=self.id,
                    text=self.text,
                    created_at=self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
                    survey_id=self.survey_id,
                    choices=[choice.to_dict() for choice in self.choices])

class Choice(db.Model):
    __tablename__ = 'choices'

    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String(100), nullable=False)
    selected = db.Column(db.Integer, default=0)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    question_id = db.Column(db.Integer, db.ForeignKey('questions.id'))

    def to_dict(self):
        return dict(id=self.id,
                    text=self.text,
                    created_at=self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
                    question_id=self.question_id)

Como se mencionó anteriormente, estoy usando la extensión específica de Flask de SQLAlchemy llamada Flask-SQLAlchemy para impulsar el ORM para esta aplicación. Me gusta Flask-SQLAlchemy porque tiene una API bastante Pythonic y proporciona valores predeterminados sensibles para definir y trabajar con clases de datos.

Cada clase hereda de la clase base ‘Modelo’ de SQLAlchemy, que proporciona métodos de utilidad intuitivos y legibles para interactuar con los datos almacenados en la base de datos. Además, cada clase se compone de una serie de campos de clase que se traducen en campos de tabla de base de datos según lo especificado por la clase SQLAlchemy Column y el tipo asociado (es decir, Integer, String, DateTime, Text, ...).

También notará que cada clase tiene un método to_dict() común. Este método será útil para serializar los datos de los modelos en JSON al enviarlos por cable al cliente frontend.

Lo siguiente en la lista es registrar el objeto SQLAlchemy, db, con el objeto de la aplicación Flask en application.py.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
"""
application.py
- creates a Flask app instance and registers the database object
"""

from flask import Flask

def create_app(app_name='SURVEY_API'):
    app = Flask(app_name)
    app.config.from_object('surveyapi.config.BaseConfig')

    from surveyapi.api import api
    app.register_blueprint(api, url_prefix="/api")

    from surveyapi.models import db
    db.init_app(app)

    return app

Lo último que me gustaría hacer es reunir Frasco-Script y [Matraz-Migrar](https://flask-migrate .readthedocs.io/en/latest/) paquetes de extensión dentro del módulo manage.py para habilitar las migraciones. Este práctico módulo, manage.py, reunirá las clases de datos que acabo de definir y las vinculará al contexto de la aplicación junto con la maquinaria Flask-Migrate y Flask-Script.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
"""
manage.py
- provides a command line utility for interacting with the
  application to perform interactive debugging and setup
"""

from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

from surveyapi.application import create_app
from surveyapi.models import db, Survey, Question, Choice

app = create_app()

migrate = Migrate(app, db)
manager = Manager(app)

# provide a migration utility command
manager.add_command('db', MigrateCommand)

# enable python shell with application context
@manager.shell
def shell_ctx():
    return dict(app=app,
                db=db,
                Survey=Survey,
                Question=Question,
                Choice=Choice)

if __name__ == '__main__':
    manager.run()

Estoy logrando dos cosas en este fragmento de código anterior. Primero, estoy creando una instancia del objeto de la aplicación Flask para que proporcione contexto a las instancias Migrate(app, db) y Manage(app). Luego estoy agregando un comando al objeto manager que me permite crear y ejecutar migraciones desde la línea de comandos de la siguiente manera:

1
(venv) $ python manage.py db init
  • Inicialice el directorio de migraciones junto a la aplicación y el archivo de base de datos de encuestas.db
1
(venv) $ python manage.py db migrate
  • Cree un archivo de migración inicial para traducir las clases en models.py a SQL que generará las tablas correspondientes
1
(venv) $ python manage.py db upgrade
  • Ejecute la migración para actualizar la base de datos con las tablas descritas en el paso anterior

Lo último que estoy haciendo en el módulo manage.py es crear otro comando personalizado utilizando @manager.shell para decorar una función shell_ctx() que devuelve palabras clave de asignación de dictados a los objetos app y db junto con las clases de datos Survey, Question y Choice.

Ahora aprovecharé la utilidad de este comando de utilidad de shell para demostrar cómo trabajar con Flask-SQLAlchemy ORM dentro del intérprete de python que produce.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(venv) $ python manage.py shell
(venv) Adams-MacBook-Pro:backend adammcquistan$ python manage.py shell
>>> survey = Survey(name='Dogs')
>>> question = Question(text='What is your favorite dog?')
>>> question.choices = [Choice(text='Beagle'), Choice(text='Rottweiler'), Choice(text='Labrador')]
>>> question2 = Question(text='What is your second favorite dog?')
>>> question2.choices = [Choice(text='Beagle'), Choice(text='Rottweiler'), Choice(text='Labrador')]
>>> survey.questions = [question, question2]
>>> db.session.add(survey)
>>> db.session.commit()
>>> surveys = Survey.query.all()
>>> for s in surveys:
...     print('Survey(id={}, name={})'.format(s.id, s.name))
...     for q in s.questions:
...             print('  Question(id={}, text={})'.format(q.id, q.text))
...             for c in q.choices:
...                     print('    Choice(id={}, text={})'.format(c.id, c.text))
...
Survey(id=1, name=Dogs)
  Question(id=1, text=What is your favorite dog?)
    Choice(id=1, text=Beagle)
    Choice(id=3, text=Labrador)
    Choice(id=2, text=Rottweiler)
  Question(id=2, text=What is your second favorite dog?)
    Choice(id=4, text=Beagle)
    Choice(id=6, text=Labrador)
    Choice(id=5, text=Rottweiler)

Eso es bastante hábil, ¿verdad?

No me refiero solo a la sintaxis elegante y legible del ORM, sino a la capacidad increíblemente poderosa de activar un intérprete de Python que contiene el contexto de la aplicación para realizar pequeños experimentos rápidos con los modelos de su aplicación. No puedo decirle cuánto aumento de productividad me ha proporcionado esto al crear aplicaciones de back-end, y le sugiero seriamente que lo utilice cuando haga lo mismo.

Completando la API RESTful

Ahora que la capa de acceso a datos está construida, puedo centrar mi atención en completar la implementación necesaria para la API RESTful. Esto se encargará de consumir y devolver los recursos de la aplicación, como los datos de encuestas, preguntas y opciones. Los casos de uso requeridos de la API RESTful incluyen lo siguiente:

  • Obtener todas las encuestas junto con sus preguntas y opciones
  • Obtener una sola encuesta junto con sus preguntas y opciones
  • Cree una nueva encuesta junto con sus preguntas y opciones específicas
  • Actualice las opciones de respuesta de una encuesta una vez que se haya realizado una encuesta

Para empezar, seguiré adelante e importaré todas las clases de datos junto con la instancia db de SQLAlchemy para tener acceso a ellas. En la parte superior de api.py agrego las siguientes importaciones:

1
2
3
4
5
6
7
8
"""
api.py
- provides the API endpoints for consuming and producing
  REST requests and responses
"""

from flask import Blueprint, jsonify, request
from .models import db, Survey, Question, Choice

En cuanto a los extremos de los recursos reales, comenzaré codificando la capacidad de obtener todos los recursos de la encuesta. Dentro de api.py, necesito reemplazar el punto final /hello/<string:name>/ con el punto final de la ruta /surveys/ y la función de vista surveys().

1
2
3
4
@api.route('/surveys/')
def surveys():
    surveys = Survey.query.all()
    return jsonify({ 'surveys': [s.to_dict() for s in surveys] })

Si el servidor de desarrollo aún se está ejecutando, una vez que guarde los archivos del proyecto, el servidor debería recargarse automáticamente actualizando todos los cambios. De lo contrario, ejecutar (venv) $ python appserver.py iniciará el servidor. Ahora, en otra terminal con el entorno virtual activado, puedo usar el paquete requests para probar este nuevo punto final. Sin embargo, me gustaría compartir un consejo profesional sobre cómo mostrar las respuestas JSON de una manera más legible mediante el uso de otro increíble paquete de Python llamado pprint.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
(venv) $ pip install pprint
(venv) $ python
>>> import pprint, requests
>>> pp == pprint.PrettyPrinter()
>>> resp = requests.get('http://localhost:5000/api/surveys/')
>>> pp.pprint(resp.json())
{'surveys': [{
     'created_at': '2018-03-06 03:52:44',
     'id': 1,
     'name': 'Dogs',
     'questions': [{
          'choices': [{
               'created_at': '2018-03-06 03:52:44',
               'id': 1,
               'question_id': 1,
               'text': 'Beagle'
              },{
               'created_at': '2018-03-06 03:52:44',
               'id': 3,
               'question_id': 1,
               'text': 'Labrador'
              },{
               'created_at': '2018-03-06 03:52:44',
               'id': 2,
               'question_id': 1,
               'text': 'Rottweiler'}],
            'created_at': '2018-03-06 03:52:44',
            'id': 1,
            'survey_id': 1,
            'text': 'What is your favorite dog?'
         },{
          'choices': [{
              'created_at': '2018-03-06 03:52:44',
              'id': 4,
              'question_id': 2,
              'text': 'Beagle'
             },{
              'created_at': '2018-03-06 03:52:44',
              'id': 6,
              'question_id': 2,
              'text': 'Labrador'
             },{
              'created_at': '2018-03-06 03:52:44',
              'id': 5,
              'question_id': 2,
              'text': 'Rottweiler'}],
          'created_at': '2018-03-06 03:52:44',
          'id': 2,
          'survey_id': 1,
          'text': 'What is your second favorite dog?'}]}
    ]}

A continuación, implementaré la funcionalidad para obtener una sola encuesta por su id con el punto final de la URL /surveys/id/ y ver la función survey(id). Inmediatamente después de la función de visualización de la API surveys(), coloco el siguiente código:

1
2
3
4
@api.route('/surveys/<int:id>/')
def survey(id):
    survey = Survey.query.get(id)
    return jsonify({ 'survey': survey.to_dict() })

De nuevo, guardaré los archivos y probaré el nuevo extremo de la API para asegurarme de que ofrece una respuesta válida.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
>>> resp = requests.get('http://localhost:5000/api/surveys/1/')
>>> pp.pprint(resp.json())
{'survey': {
     'created_at': '2018-03-06 03:52:44',
     'id': 1,
     'name': 'Dogs',
     'questions': [{
          'choices': [{
               'created_at': '2018-03-06 03:52:44',
               'id': 1,
               'question_id': 1,
               'text': 'Beagle'
              },{
               'created_at': '2018-03-06 03:52:44',
               'id': 3,
               'question_id': 1,
               'text': 'Labrador'
              },{
               'created_at': '2018-03-06 03:52:44',
               'id': 2,
               'question_id': 1,
               'text': 'Rottweiler'}],
            'created_at': '2018-03-06 03:52:44',
            'id': 1,
            'survey_id': 1,
            'text': 'What is your favorite dog?'
         },{
          'choices': [{
              'created_at': '2018-03-06 03:52:44',
              'id': 4,
              'question_id': 2,
              'text': 'Beagle'
             },{
              'created_at': '2018-03-06 03:52:44',
              'id': 6,
              'question_id': 2,
              'text': 'Labrador'
             },{
              'created_at': '2018-03-06 03:52:44',
              'id': 5,
              'question_id': 2,
              'text': 'Rottweiler'}],
          'created_at': '2018-03-06 03:52:44',
          'id': 2,
          'survey_id': 1,
          'text': 'What is your second favorite dog?'}]}
    }

Hasta ahora, solo he usado el método de ruta HTTP GET predeterminado adecuado para obtener datos de las API RESTful. Sin embargo, para las dos últimas funciones necesitaré utilizar los métodos HTTP POST y PUT para los extremos /api/surveys/ y /api/surveys/id/, respectivamente. Usaré el método HTTP POST para crear nuevas encuestas y el método HTTP PUT para actualizar una encuesta existente con un nuevo conjunto de opciones de respuesta seleccionadas.

Para la ruta /api/surveys/ necesitaré agregar un parámetro de método a la declaración de la ruta para especificar que acepta los métodos GET y POST, methods=('GET','POST'). Además, modificaré el cuerpo de la función de vista surveys() para diferenciar el tipo de método y agregaré la capacidad de guardar una nueva encuesta en la base de datos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@api.route('/surveys/', methods=('GET', 'POST'))
def fetch_surveys():
    if request.method == 'GET':
        surveys = Survey.query.all()
        return jsonify({ 'surveys': [s.to_dict() for s in surveys] })
    elif request.method == 'POST':
        data = request.get_json()
        survey = Survey(name=data['name'])
        questions = []
        for q in data['questions']:
            question = Question(text=q['text'])
            question.choices = [Choice(text=c['text'])
                                for c in q['choices']]
            questions.append(question)
        survey.questions = questions
        db.session.add(survey)
        db.session.commit()
        return jsonify(survey.to_dict()), 201

Una vez más, querré guardar el proyecto y probarlo para asegurarme de que tengo un recurso para guardar encuestas totalmente funcional.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
>>> import json
>>> survey = {
...   'name': 'Cars',
...   'questions': [{
...     'text': 'What is your favorite car?',
...     'choices': [
...       { 'text': 'Corvette' },
...       { 'text': 'Mustang' },
...       { 'text': 'Camaro' }]
...   }, {
...     'text': 'What is your second favorite car?',
...     'choices': [
...       { 'text': 'Corvette' },
...       { 'text': 'Mustang' },
...       { 'text': 'Camaro' }]
...   }]
... }
>>> headers = {'Content-type': 'application/json'}
>>> resp = requests.post('http://localhost:5000/api/surveys/', headers=headers, data=json.dumps(survey))
>>> resp.status_code
201

La pieza final a implementar es la capacidad de actualizar una encuesta existente con nuevas selecciones de respuesta de encuesta. Nuevamente, necesitaré agregar los métodos GET y PUT a la definición de ruta /api/surveys/id/, methods=('GET', 'PUT'). Luego actualizo la función de vista survey(id) para actualizar las opciones de preguntas de la encuesta asociada especificadas como seleccionadas en el cuerpo JSON de la solicitud PUT.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@api.route('/surveys/<int:id>/', methods=('GET', 'PUT'))
def survey(id):
    if request.method == 'GET':
        survey = Survey.query.get(id)
        return jsonify({ 'survey': survey.to_dict() })
    elif request.method == 'PUT':
        data = request.get_json()
        for q in data['questions']:
            choice = Choice.query.get(q['choice'])
            choice.selected = choice.selected + 1
        db.session.commit()
        survey = Survey.query.get(data['id'])
        return jsonify(survey.to_dict()), 201

Por último, necesito guardar todos mis archivos y hacer una prueba final como esta:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>>> survey_choices = {
...   'id': 1,
...   'name': 'Dogs',
...   'questions': [
...     { 'id': 1, 'choice': 1 },
...     { 'id': 2, 'choice': 5 }]
... }
>>> headers = {'Content-type': 'application/json'}
>>> resp = requests.put('http://localhost:5000/api/surveys/1/', data=json.dumps(survey_choices), headers=headers)
>>> resp.status_code()
201

Recursos

¿Quiere obtener más información sobre Python y la creación de API de back-end? Intente consultar un curso como API REST con Flask y Python para profundizar en el desarrollo web backend con Python.

Conclusión

En este artículo, he cubierto cómo implementar una API RESTful simple, bastante básica, usando Flask de acuerdo con la siguiente tabla:

Funcionalidad del método de ruta


/api/surveys/ GET Recuperar todas las encuestas /api/surveys/ POST Crear una nueva encuesta /api/surveys/id/ GET Recuperar una encuesta por id. /api/surveys/id/ PUT Actualizar las selecciones de elección de una encuesta

En el próximo artículo, demostraré cómo integrar la aplicación frontend Vue.js para que pueda consumir y enviar actualizaciones de datos al backend de Flask.

Como siempre, gracias por leer y no se avergüence de comentar o criticar a continuación. ción.