在本教程中,我们将学习如何使用 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。