23Oct

Cómo desarrollar rápidamente una API RESTful con Flask y SQLAlchemy como ORM

Necesitamos tener instalada la librería Python en nuestro ordenador. En los ejemplos usaremos la versión de Python 2.7.12. Y también necesitamos tener instalada la librería de Python Flask…

Requisitos

Necesitamos tener instalada la librería Python en nuestro ordenador. En los ejemplos usaremos la versión de Python 2.7.12. Y también necesitamos tener instalada la librería de Python Flask.

Para instalar la librería Flask una vez tengamos Python en nuestro sistema, podemos usar pip para el proceso de instalación con el siguiente comando:

pip install Flask

Creando un servidor en Flask

Para comprobar el funcionamiento de la librería Flask, creamos el archivo server.py en nuestro servidor con el siguiente código que ejecutará el servidor en modo desarrollo:

server.py

from flask import Flask, jsonify
app = Flask(__name__)

@app.route("/")
def server_info():
    return jsonify({
        "server": "My API"
    })

if __name__ == "__main__":
    app.run(port=3000, host="0.0.0.0")

Y ejecutamos el fichero de servidor con el comando:

python server.py

Si accedemos a la dirección url de nuestro navegador http://127.0.0.1:3000, veremos la siguiente respuesta:

{
  server": "My API"
}

Ya tenemos el servidor funcionando con una respuesta en JSON!.

Instalando SQLAlchemy

Para instalar el ORM SQLAlchemy, solo tenemos que ejecutar el siguiente comando sobre pip para tener la librería accesible desde nuestro servidor Flask.

pip install SQLAlchemy

Y para instalar la extensión de Flask:

pip install  Flask-SQLAlchemy

Creando los modelos

Para las primeras pruebas usaremos una base de datos SQLite, Python por defecto viene con el conector para esta base de datos.

Necesitamos guardar el archivo dentro de nuestro sistema de archivos, usaremos /tmp/cuentas.db para el ejemplo.

Añadimos en las primeras líneas de server.py la importación de las librerías:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/cuentas.db'
db = SQLAlchemy(app)
# ...

Y añadimos la definición de modelo de cuenta de usuario: Cuenta :

server.py

class Cuenta(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(96), unique=True)
    email = db.Column(db.String(96), unique=True)

El archivo server.py quedará como sigue:

from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/cuentas.db'
db = SQLAlchemy(app)

class Cuenta(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(96), unique=True)
    email = db.Column(db.String(96), unique=True)

@app.route("/")
def server_info():
    return jsonify({
        "server": "My API"
    })

if __name__ == "__main__":
    db.create_all() # Creamos todas las tablas de la base de datos
    app.run(port=3000, host="0.0.0.0")

Creación de una cuenta por POST

Vamos a crear una nueva ruta en nuestro servidor de Flask para aceptar la creación de nuevas cuentas en la ruta /cuentas/. Después de nuestra definición de ruta «/», creamos el nuevo punto de entrada:

server.py

# ...
@app.route("/")
def server_info():
    return jsonify({
        "server": "My API"
    })

@app.route("/cuentas/", endpoint="nueva_cuenta", methods=["POST"])
def new_account():
    from flask import request
    json = request.get_json()
    email = json.get("email")
    name = json.get("name")
    new_user = Cuenta()
    new_user.name = name
    new_user.email = email
    
    db.session.add(new_user)
    db.session.commit()

    return jsonify({"id": new_user.id}), 201
# ...

Ejecutamos el servidor de Flask con python server.py y en otra terminal con el siguiente CURL podemos probar el punto de entrada para añadir un par de usuarios:

curl -XPOST -H "Content-type: application/json" \
    -d '{"email":"urodoz@gmail.com", "name": "Albert Lacarta"}' \
    'http://127.0.0.1:3000/cuentas/'

curl -XPOST -H "Content-type: application/json" \
    -d '{"email":"raquel@gmail.com", "name": "Raquel Pol"}' \
    'http://127.0.0.1:3000/cuentas/'

Listado de usuarios

Ahora que tenemos los usuarios creados en nuestra base de datos, podemos listar esos usuarios en el punto de entrada /cuentas/ pero con el método HTTP GET.

Para conseguir este objetivo, creamos un nuevo punto de entrada en nuestro fichero server.py para devolver un objeto JSON con todos los elementos de base de datos.

El siguiente bloque de código define la acción de listado de usuarios:

@app.route("/cuentas/", endpoint="lista_cuentas", methods=["GET"])
def list_cuentas():
    cuentas = Cuenta.query.order_by(Cuenta.id).all()

    return jsonify({
        "items": [{"id": x.id, "name": x.name, "email": x.email} for x in cuentas]
    })

Para probar el listado podemos realizar un CURL sobre el punto de entrada:

curl -XGET -H "Content-type: application/json" 'http://127.0.0.1:3000/cuentas/'

Obtenemos la siguiente respuesta JSON:

{
  "items": [
    {
      "email": "urodoz@gmail.com", 
      "id": 1, 
      "name": "Albert Lacarta"
    }, 
    {
      "email": "raquel@gmail.com", 
      "id": 2, 
      "name": "Raquel Pol"
    }
  ]
}

Aplicando límite al listado

En esta sección añadiremos un límite al listado por parámetro en la url del tipo: ?limite.

Modificamos la acción de vista para obtener el límite de los parámetros de la url, y en caso de no tener ningún valor disponible usar 10 como límite de resultados.

@app.route("/cuentas/", endpoint="lista_cuentas", methods=["GET"])
def list_cuentas():
    from flask import request
    limite = int(request.args.get("limit", 10))
    cuentas = Cuenta.query.order_by(Cuenta.id).limit(limite).all()

    return jsonify({
        "items": [{"id": x.id, "name": x.name, "email": x.email} for x in cuentas]
    })

Para probar el listado limitado, y como solo tenemos 2 cuentas añadidas, usaremos un CURL con limite de 1:

curl -XGET -H "Content-type: application/json" 'http://127.0.0.1:3000/cuentas/?limit=1'

Vemos como en el listado resultado sólo obtenemos una cuenta ya que hemos limitado la salida a un elemento por parámetro de url.

A partir de este punto se pueden ir creando diferentes puntos de entrada en nuestro servidor Flask e ir completando una RESTful API para tener un CRUD completo, borrar datos, actualizar datos, etc…

Hemos comprobado como la inserción de puntos de entrada para realizar operaciones básicas sobre los modelos de base de datos es sencilla, únicamente hay que crear el punto de entrada en el servidor de Flask y crear la acción sobre la base de datos con la abstracción que nos permite SQLAlchemy sobre múltiples bases de datos.

Extensión SQLAlchemy de Flask: http://flask-sqlalchemy.pocoo.org/2.1/

Librería SQLAlchemy: http://www.sqlalchemy.org/

Microframework Flask: http://flask.pocoo.org/

Leave a comment