在本教程中,我们将学习如何使用 Flask 创建一个简单的 RESTful API,Flask 是一种用于 Python 的轻量级 Web 框架。
我们还将使用 SQLAlchemy,它是一种 ORM(对象关系映射器),它允许我们使用 Python 对象与数据库进行交互。我们将使用 SQLite 作为我们的数据库,但您可以使用 SQLAlchemy 支持的任何其他数据库。
什么是RESTful API?
RESTful API(表述性状态转移)是一种遵循以下原则的 Web 服务:
-
每个资源(例如用户、产品、帖子等)都由唯一的 URI(统一资源标识符)标识,例如/users/1或/products/42。
-
客户端可以使用HTTP方法对资源进行不同的操作,例如GET、POST、PUT、PATCH、DELETE等。例如,要创建一个新用户,客户端可以发送一个POST请求到用户数据/users在请求正文。要更新现有用户,客户端可以将请求/users/1正文中的更新数据发送到 PUT 或 PATCH 请求。要删除用户,客户端可以向 发送 DELETE 请求/users/1。
-
服务器在响应正文中使用适当的状态代码和数据进行响应,通常采用 JSON(JavaScript 对象表示法)格式。例如,如果用户创建成功,服务器可以用 201(已创建)状态代码和响应正文中创建的用户数据进行响应。
如果用户更新成功,服务器可以使用 200 (OK) 状态代码和响应正文中更新的用户数据进行响应。如果用户删除成功,服务器可以响应 204(无内容)状态代码并且没有响应主体。
什么是SQLAlchemy?
SQLAlchemy 是一个 ORM,它允许我们使用 Python 对象来处理数据库。它抽象掉了 SQL 查询的低级细节,并为我们提供了一个高级接口来操作数据。
SQLAlchemy 支持各种数据库,例如 SQLite、PostgreSQL、MySQL、Oracle 等。SQLAlchemy 还为我们提供了使用 Python 类和属性定义数据库模式的声明性模型。
然后我们可以使用这些模型对我们的数据执行 CRUD(创建、读取、更新、删除)操作。
设置我们的项目:
要启动我们的项目,我们需要安装一些依赖项:
-
Python 3:您可以从https://www.python.org/downloads/下载它或使用您喜欢的包管理器。
-
Pip:用于安装 Python 包的工具。它应该默认与 Python 3 一起提供。
-
Virtualenv:用于创建独立 Python 环境的工具。您可以使用pip install virtualenv.
-
Flask:我们的网络框架。您可以使用pip install flask.
-
SQLAlchemy:我们的 ORM。您可以使用pip install sqlalchemy.
-
Flask-SQLAlchemy:将 SQLAlchemy 与 Flask 集成的扩展。您可以使用pip install flask-sqlalchemy.
接下来,我们需要创建我们的项目目录和文件:
-
创建一个名为的目录flask-api并导航到它。
-
venv创建一个名为using的虚拟环境virtualenv venv。
-
source venv/bin/activate在 Linux/Mac 或venv\Scripts\activateWindows 上使用激活虚拟环境。
-
创建一个名为的文件app.py,它将包含我们的主要应用程序代码。
-
创建一个名为的文件models.py,它将包含我们的数据库模型。
-
创建一个名为的文件config.py,它将包含我们的配置设置。
配置我们的应用程序
在我们的config.py文件中,我们需要为我们的应用程序定义一些配置设置:
import os
# Get the absolute path of the current directory
basedir = os.path.abspath(os.path.dirname(__file__))
# Define the SQLALCHEMY_DATABASE_URI variable that tells SQLAlchemy where to find our database
# We will use SQLite for simplicity and store it in a file called app.db in our project directory
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')
# Define the SQLALCHEMY_TRACK_MODIFICATIONS variable that tells SQLAlchemy whether to track changes to the database
# We will set it to False to avoid unnecessary overhead
SQLALCHEMY_TRACK_MODIFICATIONS = False
创建我们的应用程序
在我们的app.py文件中,我们需要创建我们的 Flask 应用程序并使用我们的配置设置对其进行初始化。
要使用 SQLAlchemy 与数据库交互,我们需要创建一个db对象并将其与我们的 Flask 应用程序相关联。这可以通过SQLAlchemy从flask_sqlalchemy模块导入类并db在名为db.py.
下面是创建对象的示例代码片段db:
from flask_sqlalchemy import SQLAlchemy
# Create a SQLAlchemy object
db = SQLAlchemy()
然后,在主应用程序文件中app.py,我们可以创建一个Flask应用程序,并db通过调用对象init_app()的方法将其与对象相关联db。这是一个示例代码片段:
from flask import Flask
from db import db
# Create a Flask application with the name of the current module
app = Flask(__name__)
# Load the configuration settings from the config.py file
app.config.from_pyfile('config.py')
# Initialize the SQLAlchemy object with our application
db.init_app(app)
定义我们的数据库模型
在我们的models.py文件中,使用 SQLAlchemy语法来定义我们的数据库模型。模型是一个 Python 类,代表我们数据库中的一个表,它的属性代表列。我们还需要导入db将用于与数据库交互的对象。
对于本教程,我们将创建一个名为的简单模型User,该模型具有以下属性:
-
id:一个整数,作为表的主键,唯一标识每个用户。
-
name:存储用户名称的字符串。
-
email:存储用户电子邮件地址的字符串。
现在,我们可以定义我们的模型如下:
from db import db
# Define a User model that inherits from db.Model
class User(db.Model):
# Define the id attribute as an integer column that is the primary key
id = db.Column(db.Integer, primary_key=True)
# Define the name attribute as a string column that is not nullable
name = db.Column(db.String(80), nullable=False)
# Define the email attribute as a string column that is unique and not nullable
email = db.Column(db.String(120), unique=True, nullable=False)
# Define a __repr__ method that returns a string representation of the user object
def __repr__(self):
return f'<User {self.name}>'
创建我们的数据库
在定义了我们的数据库模型之后,下一步就是创建实际的数据库及其表。这可以使用 SQLAlchemy 的方法来完成create_all。为此,我们首先需要激活我们的虚拟环境(如果尚未激活),然后创建一个名为create_db.py.
在 内部create_db.py,我们将包含以下代码片段:
from app import app, db
# Create and push an application context
with app.app_context():
# Now you can use the db object
db.create_all()
-
在终端中执行文件。
我们可以通过查看项目目录中的 app.db 文件来验证我们的数据库及其表是否已创建。还可以使用 DB Browser for SQLite ( https://sqlitebrowser.org/ )之类的工具来检查和操作我们的数据库。
-
构建我们的 API
现在我们已经创建了我们的数据库及其模型,可以开始构建 API。我们将使用 Flask 的内置路由系统为我们的 API 定义不同的端点,并处理不同的 HTTP 方法。我们还将使用 Flask 的 request 和 jsonify 函数来解析和返回 JSON 数据。
我们将为我们的 API 实现以下端点:
-
GET /users:返回 JSON 格式的所有用户列表。
-
GET /users/<id>:以 JSON 格式返回具有给定 ID 的单个用户。如果不存在具有该 ID 的用户,则返回 404(未找到)错误。
-
POST /users:使用请求正文中提供的 JSON 格式创建的新用户。使用 201(已创建)状态代码以 JSON 格式返回已创建的用户。
-
PUT /users/<id>:使用 JSON 格式的请求正文中提供的数据更新具有给定 ID 的现有用户。使用 200 (OK) 状态代码以 JSON 格式返回更新后的用户。如果不存在具有该 ID 的用户,则返回 404(未找到)错误。
-
DELETE /users/<id>:删除具有给定 ID 的现有用户。返回 204(无内容)状态代码。如果不存在具有该 ID 的用户,则返回 404(未找到)错误。
我们可以将以下代码添加到我们的 app.py 文件中以实现这些端点:
from flask import Flask, jsonify, request
from db import db
# Create a Flask application with the name of the current module
app = Flask(__name__)
# Load the configuration settings from the config.py file
app.config.from_pyfile('config.py')
# Initialize the SQLAlchemy object with our application
db.init_app(app)
# Import the User model from models.py
from models import User
# Define a route for the GET /users endpoint
@app.route('/users', methods=['GET'])
def get_users():
# Query all users from the database
users = User.query.all()
# Convert each user object to a dictionary
users_dict = [user.__dict__ for user in users]
# Remove the _sa_instance_state attribute from each dictionary
for user_dict in users_dict:
user_dict.pop('_sa_instance_state')
# Return a JSON response with the list of users
return jsonify(users_dict)
# Define a route for the GET /users/<id> endpoint
@app.route('/users/<int:id>', methods=['GET'])
def get_user(id):
# Query a user by id from the database
user = User.query.get(id)
# Check if the user exists
if user is None:
# Return a 404 error if not found
return jsonify({'message': 'User not found'}), 404
else:
# Convert the user object to a dictionary
user_dict = user.__dict__
# Remove the _sa_instance_state attribute from the dictionary
user_dict.pop('_sa_instance_state')
# Return a JSON response with the user data
return jsonify(user_dict)
# Define a route for the POST /users endpoint
@app.route('/users', methods=['POST'])
def create_user():
# Get the data from the request body as a dictionary
data = request.get_json()
# Check if the data is valid
if 'name' not in data or 'email' not in data:
# Return a 400 error if missing name or email
return jsonify({'message': 'Name and email are required'}), 400
else:
# Create a new user object with the data
user = User(name=data['name'], email=data['email'])
# Add and commit the user to the database
db.session.add(user)
db.session.commit()
# Convert the user object to a dictionary
user_dict = user.__dict__
# Remove the _sa_instance_state attribute from the dictionary
user_dict.pop('_sa_instance_state')
# Return a JSON response with the created user data and a 201 status code
return jsonify(user_dict), 201
# Define a route for the PUT /users/<id> endpoint
@app.route('/users/<int:id>', methods=['PUT'])
def update_user(id):
# Query a user by id from the database
user = User.query.get(id)
# Check if the user exists
if user is None:
# Return a 404 error if not found
return jsonify({'message': 'User not found'}), 404
else:
# Get the data from the request body as a dictionary
data = request.get_json()
# Check if the data is valid
if 'name' not in data or 'email' not in data:
# Return a 400 error if missing name or email
return jsonify({'message': 'Name and email are required'}), 400
else:
# Update the user object with the data
user.name = data['name']
user.email = data['email']
# Commit the changes to the database
db.session.commit()
# Convert the user object to a dictionary
user_dict = user.__dict__
# Remove the _sa_instance_state attribute from the dictionary
user_dict.pop('_sa_instance_state')
# Return a JSON response with the updated user data and a 200 status code
return jsonify(user_dict), 200
# Define a route for the DELETE /users/<id> endpoint
@app.route('/users/<int:id>', methods=['DELETE'])
def delete_user(id):
# Query a user by id from the database
user = User.query.get(id)
# Check if the user exists
if user is None:
# Return a 404 error if not found
return jsonify({'message': 'User not found'}), 404
else:
# Delete the user from the database
db.session.delete(user)
db.session.commit()
# Return a 204 status code with no response body
return '', 204
if __name__ == '__main__':
app.run()
测试API
现在我们已经实现了我们的 API 端点,我们可以使用像 Postman ( https://www.postman.com/ ) 或 curl ( https://curl.se/ )这样的工具来测试它们。使用这些工具向我们的 API 发送不同的 HTTP 请求并检查响应。
要测试我们的 API,我们需要执行以下步骤:
-
使用 运行我们的 Flask 应用程序python app.py。
-
打开 Postman 或 curl 并将不同的请求发送到我们的 API 端点。
-
检查每个请求的状态码和响应体。
首先让我们users使用 POST 方法创建新的:
-
POST /users:使用请求正文中提供的 JSON 格式数据创建新用户。使用 201(已创建)状态代码以 JSON 格式返回已创建的用户。
要求:
#User 1:
curl -X POST -H "Content-Type: application/json" -d '{"name": "Alice","email":"alice@example.com"}' http://127.0.0.1:5000/users
回复:
{}
用户 2:
curl -X POST -H "Content-Type: application/json" -d '{"name": "Bob", "email": "bob@example.com"}' http://127.0.0.1:5000/users
用户 3:
curl -X POST -H "Content-Type: application/json" -d '{"name": "Charlie","email": "charlie@example.com"}' http://127.0.0.1:5000/users
现在我们将使用 GET 方法返回 JSON 格式的用户列表。
-
获取
/users
:
要求:
curl http://127.0.0.1:5000/users
回复:
[
{
"id": 1,
"name": "Alice",
"email": "alice@example.com"
},
{
"id": 2,
"name": "Bob",
"email": "bob@example.com"
},
{
"id": 3,
"name": "Charlie",
"email": "charlie@example.com"
}
]
-
GET
/users/<id>
:以 JSON 格式返回给定 ID 的单个用户。如果具有该 ID 的用户不存在,则返回 404(未找到)错误。
要求:
curl http://localhost:5000/users/1
回复:
{
"id": 1,
"name": "Alice",
"email": "alice@example.com"
}
要求:
curl http://localhost:5000/users/4
回复:
{
"message": "User not found"
}
-
PUT
/users/<id>
:使用 JSON 格式的请求给定 ID 的现有用户。使用 200 (OK) 状态代码以 JSON 格式返回更新后的用户。如果具有该 ID 的用户不存在,则返回 404(未找到)错误。
要求:
curl -X PUT -H "Content-Type: application/json" -d '{"name": "Alice", "email": "alice@new.com"}' http://localhost:5000/users/1
回复:
{}
使用 GET 查看用户更新后的详细信息
curl http://localhost:5000/users/1
回复:
{
"id": 1,
"name": "Alice",
"email": "alice@new.com"
}
要求:
curl -X PUT -H "Content-Type: application/json" -d '{"name": "Eve", "email": "eve@example.com"}' http://localhost:5000/users/4
回复:
{
"message": "User not found"
}
-
DELETE
/users/<id>
:删除具有给定 ID 的现有用户。返回 204(无内容)状态代码。如果不存在具有该 ID 的用户,则返回 404(未找到)错误。
要求:
curl -X DELETE http://localhost:5000/users/2
回复:
无响应正文。
要求:
curl -X DELETE http://localhost:5000/users/5
回复:
{
"message": "User not found"
}
Flask 和 Flask-RESTful 为构建 REST API 提供了许多高级功能和选项,例如使用 连接到数据库flask_sqlalchemy、使用 对数据进行序列化和反序列化flask_marshmallow、使用 添加身份验证和授权flask_jwt_extended以及使用 为 API 生成交互式文档flask_swagger_ui。