En este tutorial de programación con Python aprenderás a crear una API REST usando Flask, SQLite 3 (para los datos) y JSON para la comunicación de datos.
Al final tendrás una API que puedes consumir desde cualquier cliente, ya sea una aplicación para Android, un navegador con JavaScript o incluso otro lenguaje de servidor.
Te mostraré cómo crear una API que se comunica usando JSON y guarda los datos en SQLite 3. La API estará creada con Flask, y usaremos el lenguaje de programación Python para manejar todos los datos.
Vamos a usar los 4 verbos HTTP más usados: GET, POST, PUT y DELETE, mismos que estarán relacionados con el CRUD de la base de datos.
Lo que vamos a gestionar será una base de datos de juegos, mismos que tienen nombre, precio y calificación. También tendremos varias operaciones que vamos a exponer a través de la API creada con Flask:
Primero vamos a crear el CRUD que se relaciona con la base de datos usando Python, y más tarde vamos a exponer todas estas funciones con Flask, ya en la API, codificando como JSON.
La estructura de la base de datos queda como se ve a continuación. Es una única tabla, aunque a partir de este tutorial podemos crear más tablas, relaciones, etcétera.
CREATE TABLE IF NOT EXISTS games(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL,
rate INTEGER NOT NULL
)
Después vemos el archivo de conexión a la base de datos:
import sqlite3
DATABASE_NAME = "games.db"
def get_db():
conn = sqlite3.connect(DATABASE_NAME)
return conn
def create_tables():
tables = [
"""CREATE TABLE IF NOT EXISTS games(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL,
rate INTEGER NOT NULL
)
"""
]
db = get_db()
cursor = db.cursor()
for table in tables:
cursor.execute(table)
En este archivo de conexión SQLite3 con Python observamos que la base de datos se llamará games.db. Además, contamos con dos funciones: una de ellas es para obtener la base de datos, y la otra (create_tables
) es para crear las tablas dentro de la base de datos solo en caso de que no existan.
Fíjate bien en estas funciones, pues las vamos a importar desde otros archivos. Ahora que ya tenemos definida la base de datos veamos el CRUD de juegos con la base de datos SQLite3.
Antes de exponer la base de datos en la API, vamos a crear un controlador de juegos que se va a encargar de todas las operaciones para guardar, actualizar, eliminar y obtener los datos de los juegos.
Todas estas funciones se encuentran dentro de un archivo llamado game_controller.py y se ve así:
from db import get_db
def insert_game(name, price, rate):
db = get_db()
cursor = db.cursor()
statement = "INSERT INTO games(name, price, rate) VALUES (?, ?, ?)"
cursor.execute(statement, [name, price, rate])
db.commit()
return True
def update_game(id, name, price, rate):
db = get_db()
cursor = db.cursor()
statement = "UPDATE games SET name = ?, price = ?, rate = ? WHERE id = ?"
cursor.execute(statement, [name, price, rate, id])
db.commit()
return True
def delete_game(id):
db = get_db()
cursor = db.cursor()
statement = "DELETE FROM games WHERE id = ?"
cursor.execute(statement, [id])
db.commit()
return True
def get_by_id(id):
db = get_db()
cursor = db.cursor()
statement = "SELECT id, name, price, rate FROM games WHERE id = ?"
cursor.execute(statement, [id])
return cursor.fetchone()
def get_games():
db = get_db()
cursor = db.cursor()
query = "SELECT id, name, price, rate FROM games"
cursor.execute(query)
return cursor.fetchall()
En el archivo vemos varias funciones. La función insert_game
recibe los datos del juego y los inserta en la base de datos (INSERT); todo esto usando sentencias preparadas para evitar inyecciones SQL en esta API que estamos creando con Python y Flask.
También vemos otros métodos como update_game
que realiza la operación UPDATE para actualizar un juego, delete_game
que elimina un juego (DELETE) a partir de su id, get_by_id
que regresa un juego a partir de su id (usando la operación SELECT).
Finalmente observamos la función get_games
que devuelve todos los juegos existentes.
Fíjate en que todas las funciones usan la base de datos y un cursor para realizar todas las operaciones.
Ahora que ya tenemos el CRUD de las operaciones con la base de datos es momento de exponer todo en la API con Flask.
Lo primero que hacemos en la API es crear la app de Flask e importar el controlador de los juegos. También importamos una función de la base de datos porque necesitamos crear las tablas al iniciar la aplicación:
from flask import Flask, jsonify, request
import game_controller
from db import create_tables
app = Flask(__name__)
Ahora definimos las rutas con los verbos GET, PUT, POST y DELETE:
@app.route('/games', methods=["GET"])
def get_games():
games = game_controller.get_games()
return jsonify(games)
@app.route("/game", methods=["POST"])
def insert_game():
game_details = request.get_json()
name = game_details["name"]
price = game_details["price"]
rate = game_details["rate"]
result = game_controller.insert_game(name, price, rate)
return jsonify(result)
@app.route("/game", methods=["PUT"])
def update_game():
game_details = request.get_json()
id = game_details["id"]
name = game_details["name"]
price = game_details["price"]
rate = game_details["rate"]
result = game_controller.update_game(id, name, price, rate)
return jsonify(result)
@app.route("/game/<id>", methods=["DELETE"])
def delete_game(id):
result = game_controller.delete_game(id)
return jsonify(result)
@app.route("/game/<id>", methods=["GET"])
def get_game_by_id(id):
game = game_controller.get_by_id(id)
return jsonify(game)
Cada ruta expone una función del controlador de juegos que vimos anteriormente, que a su vez interactúa con la base de datos de SQLite3. Es importante destacar algunas cosas. Por ejemplo, al actualizar e insertar un juego leemos el JSON de la petición con get_json
y accedemos al diccionario.
En el caso de eliminar o de obtener por ID leemos la variable id desde la ruta como <variable>
y recibiéndola en el método.
También fíjate en que esta API con Python se comunica a través de JSON, por lo que todas las respuestas se hacen de acuerdo a lo que regresa la función jsonify.
Finalmente creamos la app de Flask para iniciar el servidor y escuchar peticiones:
if __name__ == "__main__":
create_tables()
"""
Here you can change debug and port
Remember that, in order to make this API functional, you must set debug in False
"""
app.run(host='0.0.0.0', port=8000, debug=False)
Si vas a consumir esta API desde un dominio distinto al de la misma, necesitas habilitar CORS. Basta con agregar el siguiente fragmento de código en la API (en el repositorio encontrarás el código ya agregado, mismo que puedes remover si quieres):
"""
Enable CORS. Disable it if you don't need CORS
"""
@app.after_request
def after_request(response):
response.headers["Access-Control-Allow-Origin"] = "*" # <- You can change "*" for a domain for example "http://localhost"
response.headers["Access-Control-Allow-Credentials"] = "true"
response.headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS, PUT, DELETE"
response.headers["Access-Control-Allow-Headers"] = "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization"
return response
El código completo de la API queda así:
"""
API REST con Python 3 y SQLite 3
By Parzibyte:
** https://parzibyte.me/blog **
"""
from flask import Flask, jsonify, request
import game_controller
from db import create_tables
app = Flask(__name__)
@app.route('/games', methods=["GET"])
def get_games():
games = game_controller.get_games()
return jsonify(games)
@app.route("/game", methods=["POST"])
def insert_game():
game_details = request.get_json()
name = game_details["name"]
price = game_details["price"]
rate = game_details["rate"]
result = game_controller.insert_game(name, price, rate)
return jsonify(result)
@app.route("/game", methods=["PUT"])
def update_game():
game_details = request.get_json()
id = game_details["id"]
name = game_details["name"]
price = game_details["price"]
rate = game_details["rate"]
result = game_controller.update_game(id, name, price, rate)
return jsonify(result)
@app.route("/game/<id>", methods=["DELETE"])
def delete_game(id):
result = game_controller.delete_game(id)
return jsonify(result)
@app.route("/game/<id>", methods=["GET"])
def get_game_by_id(id):
game = game_controller.get_by_id(id)
return jsonify(game)
if __name__ == "__main__":
create_tables()
"""
Here you can change debug and port
Remember that, in order to make this API functional, you must set debug in False
"""
app.run(host='0.0.0.0', port=8000, debug=False)
Si quieres ver el código de los otros archivos y el repositorio completo, visita mi GitHub. Ahí podrás descargar y probar todo el código open source.
Recuerda que para iniciar el servidor y la API debes ejecutar:
python main.py
O en su defecto:
python3 main.py
Después de clonar y ejecutar el repositorio puedes realizar las pruebas usando Postman o cualquier lenguaje de tu preferencia. Más adelante traeré ejemplos de consumo con Frameworks JavaScript o con JavaScript puro.
Mientras tanto te dejo una captura probando la API:
Si te gusta Python, te invito a leer más contenido de ese tema en mi blog. O aprende más sobre Flask.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.
Ver comentarios
Me arroja un error de metodo invalido 405 Método no Permitido