The Flask ecosystem has no shortage of great libraries for building REST APIs from the ground up. What has been missing is a tool for generating the common CRUD (create, read, update, delete) endpoints that often make up the majority of a REST API.
Flask-Muck solves this problem while coexisting with the non-standard endpoints that are inevitable in any production-scale codebase. Flask-Muck sits on top of a Flask/SQLAlchemy tech stack and uses a declarative and modular approach to replace huge amounts of boilerplate code by generating a full-featured set of standard CRUD endpoints for a resource in as little as 9 lines of code.
class MyModelApiView(FlaskMuckApiView):
api_name = "my-model"
session = db.session
Model = MyModel
ResponseSchema = MyModelSchema
CreateSchema = MyModelSchema
PatchSchema = MyModelSchema
UpdateSchema = MyModelSchema
searchable_columns = [MyModel.name]
blueprint = Blueprint("api", __name__, url_prefix="/api/v1")
MyModelApiView.add_rules_to_blueprint(blueprint)
# Available Endpoints:
# CREATE | curl -X POST "/api/v1/my-model" -H "Content-Type: application/json" \-d "{\"name\": \"Ayla\"}"
# LIST ALL | curl -X GET "/api/v1/my-model" -d "Accept: application/json"
# LIST ALL PAGINATED | curl -X GET "/api/v1/my-model?limit=100&offset=50" -d "Accept: application/json"
# SEARCH | curl -X GET "/api/v1/my-model?search=ayla" -d "Accept: application/json"
# FILTER | curl -X GET "/api/v1/my-model?filter={\"name\": \"Ayla\"}" -d "Accept: application/json"
# SORT | curl -X GET "/api/v1/my-model?sort=name" -d "Accept: application/json"
# FETCH | curl -X GET "/api/v1/my-model/1" -d "Accept: application/json"
# UPDATE | curl -X PUT "/api/v1/my-model" -H "Content-Type: application/json" \-d "{\"name\": \"Ayla\"}"
# PATCH | curl -X PATCH "/api/v1/my-model" -H "Content-Type: application/json" \-d "{\"name\": \"Ayla\"}"
# DELETE | curl -X DELETE "/api/v1/my-model/1"
This article guides you through building a complete Flask app that hosts a REST API for a hypothetical todo list application. Perfect for beginners in web development or those new to Flask, this walkthrough provides step-by-step instructions.
Seasoned Flask developers can skip the tutorial below and head straight to the Flask-Muck repo for links to documentation and example apps:
dtiesling / flask-muck
𧚠Flask REST framework for generating CRUD APIs and OpenAPI specs in the SQLAlchemy, Marshmallow/Pydantic application stack.
With Flask-Muck you don't have to worry about the CRUD.
Flask-Muck is a declarative framework for automatically generating RESTful APIs with Create, Read Update and Delete (CRUD) endpoints in a Flask, SqlAlchemy, Marshmallow/Pydantic application stack in as little as 9 lines of code. Below is example code you might find in a Flask app. Please see the docs for full working examples
from flask import Blueprint, Flask
from flask_muck import FlaskMuckApiView, FlaskMuck
import marshmallow as ma
from marshmallow import fields as mf
from myapp import db
class MyModel(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
class MyModelSchema(ma.Schema):
id = mf.Integer(dump_only=True)
name = mf.String()
class MyModelApiView(
âŚProject Setup
Before you begin ensure you have the following prerequisites
- Python 3.9 or higher installed
- Bash shell or similar
- Basic understanding of REST APIs.
1. Create Project Files
Start by creating the required file structure:
mkdir sample_api
cd sample_api
touch app.py
Now, your project directory should have a single Python file:
sample_api/
ââ app.py
Important: Make sure you are in the sample_api directory in your shell. The subsequent tutorial assumes this is the current working directory for all commands.
2. Install Dependencies
For a clean start with dependencies, weâll use Pipenv. If you prefer another tool for managing environments, feel free to use it. Run the following command to install Pipenv:
pip install --user pipenv
Next, install all the dependencies needed for the project in the virtual environment:
pipenv install flask SQLAlchemy flask-sqlalchemy marshmallow flask-muck
Your project is set up, now youâre ready to write some code.
Write the codes
In the following section youâll be writing all of the Python code to create the Flask REST API. All code snippets should be appended to the app.py file. For demonstration purposes module imports will be added as needed throughout the code, feel free to group them at the top of the file if youâd prefer to adhere to Pep8 style guidelines.
1. Create a Basic Flask App
In this step, we setup the most fundamental Flask app. Weâre keeping it basic for this example, but you can explore more comprehensive configurations for Flask apps in numerous well-documented articles tailored for production setups.
from flask import Flask
app = Flask(__name__)
2. Configure SqlAlchemy And Add Database Models
Earlier we installed the dependencies Flask-SQLAlchemy and SQLAlchemy.
SQLAlchemy is a SQL toolkit and ORM commonly used in conjunction with Flask to create database-backed applications. Weâll be using it to define our database tables and interact with them.
Flask-SQLAlchemy is an extension that simplifies using SQLAlchemy with Flask by setting up common objects and patterns for using those objects, such as a session tied to each web request, models, and engines.
Configure SQLAlchemy
Start by updating the appâs config with a database URI for SQLAlchemy. In this example we will point to a local sqlite file. In production Flask should be configured to use a production-ready database such as MySQL or PostgreSQL.
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.db"
Establish a base class for all database models by inheriting from DeclarativeBase:
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
Create a SQLAlchemy extension instance and then initialize the Flask app for use with extension.
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(model_class=Base)
db.init_app(app)
At this point, you now have a fully functional Flask app, and the db object is ready to manage database interactions within the application.
3. Implement a Database Model
Now that weâve configured the application, itâs time to define the database structure. Our initial step is to create a SQLAlchemy model representing a table dedicated to todo items in the database â this is where your applicationâs information will be persisted.
class TodoModel(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
text = db.Column(db.String, nullable=False)
The TodoModel tracks todo items in the database. It generates a database table with two columns, id and text. id is a unique identifier for the resource and text is the description of the todo item.
4. Implement a Schema
Schemas play a crucial role in defining the structure of request and response payloads for your API. Letâs create a Marshmallow schema responsible for validating request JSON and serializing results.
import marshmallow as ma
from marshmallow import fields as mf
class TodoSchema(ma.Schema):
id = mf.Integer(required=True, dump_only=True)
text = mf.String(required=True)
Take note of the dump_only keyword argument applied to the id field. This signifies that the field exclusively serves serialization purposes for objects returned in the response. When validating requests (loading), only the text field will be validated.
For a deeper understanding of Marshmallow and schema functionality, you can explore additional details in the Marshmallow documentation.
5. Create Flask-Muck API Views
In Flask views are code components that handle http requests made to your application. Flask offers a convenient tool for organizing view code, and before we dive into creating views, letâs lay the groundwork by establishing a blueprint to streamline our API endpoints.
from flask import Blueprint
api_blueprint = Blueprint("v1_api", __name__, url_prefix="/api/v1/")
All views added to this blueprint will be appended to the /api/v1 url route.
Now, armed with a blueprint for organized views, letâs create them. For this demonstration, weâll leverage Flask-Muck to dynamically generate standard CRUD endpoints for our todo items. Flask-Muck offers class-based views that can be inherited from to generate CRUD endpoints.
from flask_muck import FlaskMuckApiView
class TodoApiView(FlaskMuckApiView):
session = db.session
api_name = "todos"
Model = TodoModel
ResponseSchema = TodoSchema
CreateSchema = TodoSchema
PatchSchema = TodoSchema
UpdateSchema = TodoSchema
searchable_columns = [TodoModel.text]
# Add all url rules to the blueprint.
TodoApiView.add_rules_to_blueprint(api_blueprint)
By defining a new FlaskMuckApiView and calling the add_rules_to_blueprint method, the following routes are added to the Flask application.
GET /api/todos/ List all todo items
POST /api/todos/ Create a todo item
GET /api/todos/ Fetch a single todo item
PUT /api/todos/ Update a single todo item
PATCH /api/todos/ Patch a single todo item
DELETE /api/todos/ Delete a single todo item
6. Define Script Behavior
In the final step we define the behavior of app.py when it is run as a script.
if __name__ == "__main__":
with app.app_context():
db.create_all()
app.run(debug=True)
This code orchestrates the creation of database tables and initiates the Flask development server.
The final app.py file should look similar to this:
import marshmallow as ma
from flask import Flask, Blueprint
from flask_muck import FlaskMuckApiView
from flask_sqlalchemy import SQLAlchemy
from marshmallow import fields as mf
from sqlalchemy.orm import DeclarativeBase
app = Flask(__name__)
class Base(DeclarativeBase):
pass
db = SQLAlchemy(model_class=Base)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///todo_example.db"
db.init_app(app)
class TodoModel(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
text = db.Column(db.String, nullable=False)
class TodoSchema(ma.Schema):
id = mf.Integer(required=True, dump_only=True)
text = mf.String(required=True)
api_blueprint = Blueprint("v1_api", __name__, url_prefix="/api/v1/")
class TodoApiView(FlaskMuckApiView):
session = db.session
api_name = "todos"
Model = TodoModel
ResponseSchema = TodoSchema
CreateSchema = TodoSchema
PatchSchema = TodoSchema
UpdateSchema = TodoSchema
searchable_columns = [TodoModel.text]
TodoApiView.add_rules_to_blueprint(api_blueprint)
app.register_blueprint(api_blueprint)
if __name__ == "__main__":
with app.app_context():
db.create_all()
app.run(debug=True)
Interact With Your API
Now that the code is in place, letâs run the app and send some requests.
1. Start the Local Development Server
Start the local development server with the following shell command:
pipenv run python3 app.py
Your server is now active at http://127.0.0.1:5000. Keep in mind that this configuration is not optimized for production. If youâre interested in deploying Flask apps in a production environment, numerous insightful articles cover this topic.
2. Explore the Flask-Muck API
In a new shell, begin making requests to the REST API. Experiment with these cURL commands or use your preferred REST client such as Postman.
Create a ToDo item
curl -X POST --location "http://127.0.0.1:5000/api/v1/todos/" \
-H "Content-Type: application/json" \
-d "{
\"text\": \"take out garbage again\"
}"
List all ToDo items (flat)
curl -X GET --location "http://127.0.0.1:5000/api/v1/todos/" \
-d "Accept: application/json"
List all ToDo items (paginated)
curl -X GET --location "http://127.0.0.1:5000/api/v1/todos/?limit=2&offset=1" \
-d "Accept: application/json"
Search ToDo items
curl -X GET --location "http://127.0.0.1:5000/api/v1/todos/?search=garbage" \
-d "Accept: application/json"
Filter ToDo items
curl -X GET --location "http://127.0.0.1:5000/api/v1/todos/?filters=%7B%22text%22%3A+%22take+out+garbage+again%22%7D" \
-d "Accept: application/json"
querystring urldecodes to filters={"text": "take out garbage again"}
Sort ToDo items
curl -X GET --location "http://127.0.0.1:5000/api/v1/todos/?sort=text" \
-d "Accept: application/json"
Fetch ToDo item
curl -X GET --location "http://127.0.0.1:5000/api/v1/todos/1/" \
-d "Accept: application/json"
Update ToDo item
curl -X PUT --location "http://127.0.0.1:5000/api/v1/todos/1/" \
-H "Content-Type: application/json" \
-d "{
\"text\": \"Updated todo item\"
}"
Patch ToDo item
curl -X PATCH --location "http://127.0.0.1:5000/api/v1/todos/1/" \
-H "Content-Type: application/json" \
-d "{
\"text\": \"Updated todo item\"
}"
Delete ToDo Item
curl -X DELETE --location "http://127.0.0.1:5000/api/v1/todos/1/"
Congratulations on Building Your Functional REST API!
You've successfully built a functional REST API. Now, take the next step by exploring the Flask-Muck documentation and examples. Dig deeper into advanced features like nested resources, one-to-one endpoints, escape hatches and more.
If you enjoy the project follow it on GitHub and keep an eye on the GitHub Discussions for whatâs coming next.
Top comments (0)