Servicio REST simple en Flask

Holas, el día de hoy les voy a explicar cómo hacer un pequeño servicio REST en Flask usando una variable interna para guardar nuestros datos, dicho proyecto no es más que un CRUD simple de ToDo's

Estructura del Proyecto

Debido a que flask es muy flexible podemos organizar nuestro proyecto de diferentes maneras como la siguiente: http://exploreflask.com/en/latest/organizing.html

run.py # Archivo que inicia el servicio
requirements.txt # Archivo de requerimientos
app/
    __init_.py # Permite sabe que es un paquete de Python
    utils/
        __init__.py
        json_utils.py # Una pequeña utilidad para saber si un request recibido tiene un JSON
    views/
        __init__.py
        todo.py # Las rutas del Servicio junto con sus funciones

Inicio

El archivo run.py nos permite correr nuestro servicio, en él importamos el paquete app y procedemos a poner el host y el puerto que queramos usar para su ejecución

import os
from app import app

app.debug = True
# Host es 0.0.0.0 para permitir accesos desde otras computadoras,
# de lo contrario sólo nuestra computadora local podrá acceder al servicio
host = os.environ.get('IP', '0.0.0.0')
port = int(os.environ.get('PORT', 8085))

app.run(host=host, port=port)

Al importar nuestro paquete app veremos que el archivo init.py tiene algo de código en su interior, este código se ejecutará la primera vez que importemos el paquete

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app) # Cors nos permite usar el servicio REST con un frontend como Angular, VueJS, etc

from app.views import todo # Importamos las vistas de nuestro Servicio

Vistas

En este servicio dentro del paquete views tenemos el archivo todo.py que es donde se encuetran todas las rutas que posee el servicio así como las funciones asociadas a los mismos

import json

from flask import abort
from flask import request

from app import app
from ..utils import json_utils

todo_list = [] # Dentro de este array se van a guardar todos nuestros ToDo's

# La ruta para obtener todos los ToDo's es /
@app.route("/", methods=['GET'])
def get_all_todos():
    # Retornamos una lista con los JSON guardados, 
    # si no hay nada retornará una lista vacía
    return json.dumps([json.loads(each_todo) for each_todo in todo_list])

# Ruta para retornar un ToDo específico mediante su ID
@app.route("/" + '<string:todo_id>', methods=['GET'])
def get_todo(todo_id):
    selected_todo = None
    # Buscamos en la lista el ToDo que contenga el ID especificado
    for element in todo_list:
        if str(json.loads(element)['id']) == todo_id:
            selected_todo = element
    # Revisamos si existe el ToDo, caso contrario retornamos 404 -> NotFound
    if selected_todo is None:
        abort(404)
    return selected_todo

# Ruta para guardar un nuevo ToDo
@app.route("/", methods=['POST'])
def post_todo():
    # Revisamos si el request es un JSON válido
    json_utils.is_not_json_request(request)
    id_list = []
    # Recorremos la lista de ToDo's y lo agregamos a 
    # una lista que contiene solo ID's
    for element in todo_list:
        id_list.append(json.loads(element)['id'])
    # Ordenamos la lista de ID's
    id_list.sort()
    # Añadimos un ID nuevo a nuestro request
    request.json['id'] = id_list[-1] + 1 if len(id_list) > 0 else 1
    # Añadimos el JSON a nuestra lista
    todo_list.append(str(json.dumps(request.json)))
    return json.dumps(request.json)

# Ruta para actualizar un ToDo mediante su ID
@app.route("/" + '<string:todo_id>', methods=['PUT'])
def put_todo(todo_id):
    # Revisamos si el request es un JSON válido
    json_utils.is_not_json_request(request)
    selected_todo = None
    for element in todo_list:
        if str(json.loads(element)['id']) == todo_id:
            selected_todo = element
    # Revisamos si existe el ToDo, caso contrario retornamos 404 -> NotFound
    if selected_todo is None:
        abort(404)
    # Borramos el ToDo de la lista
    todo_list.pop(todo_list.index(selected_todo))
    request.json['id'] = int(todo_id)
    # Añadimos el ToDo a nuestra lista con el ID al que pertenecía
    todo_list.append(str(json.dumps(request.json)))
    return json.dumps(request.json)

# Ruta para borrar un ToDo mediante su ID
@app.route("/" + '<string:todo_id>', methods=['DELETE'])
def delete_todo(todo_id):
    selected_todo = None
    # Buscamos en la lista el ToDo que contenga el ID especificado
    for element in todo_list:
        if str(json.loads(element)['id']) == todo_id:
            selected_todo = element
    # Revisamos si existe el ToDo, caso contrario retornamos 404 -> NotFound
    if selected_todo is None:
        abort(404)
    # Borramos el ToDo de la lista
    todo_list.pop(todo_list.index(selected_todo))
    return ""

Utilitarios

Este servicio REST contiene un pequeño utilitario para controlar que un request sea un JSON válido

from flask import abort

# Revisamos que el request sea un JSON válido
# caso contrario retornamos un error 400 -> BadRequest
def is_not_json_request(request):
    if not request.json:
        abort(400)

Correr el servicio

Para correr este servicio necesitamos que nuestro Entorno Virtual de Python tenga las dependencias instaladas, para ello hacemos lo siguiente dentro de nuestro entorno virtual:

pip install -r requirements.txt

El archivo de requirements contiene las dependencias necesarias para poder correr este proyecto

Para correr el proyecto nos basta con:

python run.py

No olvidar que debemos correrlo con nuestro entorno virtual

Uso de la aplicación

Para probarlo podemos usar Insomnia REST Client, Postman, CURL, etc. Personalmente uso Insomnia, es opensource y muy bueno para trabajo con servicios REST

GET ToDo's -> Retornar una lista de ToDo's

URL: http://127.0.0.1:8085

Respuesta:

[
  {
    "title": "Nuevo ToDo",
    "description": "Descripcion de ToDo",
    "id": 1
  }
]

GET ToDo especificado -> Retornar un ToDO por su ID

URL: http://127.0.0.1:8085/{id} -> Reemplazar {id} por el id que queremos, en este caso 1

Respuesta:

{
    "title": "Nuevo ToDo",
    "description": "Descripcion de ToDo",
    "id": 1
}

POST ToDo -> Guardar

URL: http://127.0.0.1:8085

Respuesta:

{
    "title": "Nuevo ToDo 1",
    "description": "Descripcion de ToDo 1"
}

PUT ToDo -> Actualizar

URL: http://127.0.0.1:8085/{id} -> Reemplazar {id} por el id que queremos, en este caso 1

Respuesta:

{
    "title": "Nuevo ToDo Actualizado",
    "description": "Descripcion de ToDo Actualizada"
}

DELETE ToDo -> Borrar

URL: http://127.0.0.1:8085/{id} -> Reemplazar {id} por el id que queremos, en este caso 1

Respuesta: Vacía con código 200

La URL del proyecto se encuentra en: https://github.com/nano-bytes/flask/tree/master/simple-todo

Esto ha sido todo por hoy.

Happy Hacking!!

You may also like...