专栏首页keinYe使用 Flask 创建 RESTful 服务

使用 Flask 创建 RESTful 服务

这篇文章的目标是实现一个通过 API 访问的服务端,主要实现以下功能:

  • 使用 Flask 创建一个服务器
  • 实现通过 RESTful API 访问
  • 实现数据持久化存储
  • 实现用户认证

使用 Flask 创建服务器

在开始之前首先使用 pip 安装 virtualenv。

pip install virtualenv

virtualenv 为你的项目提供了一个独立的python 依赖库,这样既可以保证代码在不同平台上使用相同的依赖环境,同时也不会影响本地的 python 环境。

新建服务器目录,并设置虚拟环境

mkdir servercd servervirtualenv -p /usr/local/bin/python3 .venv

在目录下新建依赖文件 requirements.txt,文件内容如下:

click>=6.7Flask>=1.0.0Flask-Cors>=3.0.7Flask-HTTPAuth>=3.3.0Flask-Login>=0.4Flask-Migrate>=2.0.4Flask-SQLAlchemy>=2.3.2flask-restful>=0.3itsdangerous>=0.24Jinja2>=2.10PyMySQL>=0.9.2pluggy>=0.6.0pytz>=2018.4SQLAlchemy-Utils>=0.33.3Werkzeug>=0.14.1

安装依赖文件中的所有依赖

source .venv/bin/activepip inistall -r requirements.txt

注意在使用 python、pip 等命令前,先激活虚拟环境,文章中默认已激活虚拟环境。

依赖完成以后在 server 目录下再新建一个 server 目录作为项目的主目录,第一级 server 目录作为共用配置文件存储目录。

在第二级 server 目录下新建文件 app.py 和 __init__.py。

app.py 文件内容如下:

# -*- coding:utf-8 -*-
from flask import Flaskfrom flask.views import MethodView
class HelloWorld(MethodView):
    def get(self):        return 'Hello World!'
def create_app(config=None):    app = Flask(        'server', instance_relative_config=True    )
    app.add_url_rule('/', view_func=HelloWorld.as_view('HelloWorld'))
    return app

__init__.py 文件内容如下:

# -*- coding:utf-8 -*-
from .app import create_app

在第一级 server 目录下新建文件 main.py,文件内容如下:

from server import create_app
app = create_app()
if __name__ == '__main__':    app.run()

此时在第一级 server 目录下执行 python main.py 命令,将看到以下信息:

(.venv) ➜  server python main.py * Serving Flask app "server" (lazy loading) * Environment: production   WARNING: This is a development server. Do not use it in a production deployment.   Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

此时你的 Flask 应用已完全运行起来了,在浏览器中输入 http://127.0.0.1:5000/ 将看到 Hello World!文本。

整个文件目录如下:

(.venv) ➜  python tree serverserver├── main.py├── requirements.txt└── server    ├── __init__.py    └── app.py

实现 RESTful API

符合REST设计风格的Web API称为RESTful API。它从以下三个方面资源进行定义:

  • 直观简短的资源地址:URI,比如:http://example.com/resources。
  • 传输的资源:Web服务接受与返回的互联网媒体类型,比如:JSON,XML,YAML等。
  • 对资源的操作:Web服务在该资源上所支持的一系列请求方法(比如:POST,GET,PUT或DELETE)。

RESTful API 是一套成熟的互联网应用程序的 API 设计规范。主要用于客户端和服务器之间无状态、统一接口方式的通讯,我们经常访问的网页既是一个典型的客户端和服务器模型,我们在浏览器中所看到的网页是一个客户端,而为它提供内容的是服务器;另外我们手机中的 APP 也是一个客户端,我们在 APP 中看到的图片信息等都是通过服务器来提供的。

Flask-RESTful 为 Flask 提供了 RESTful API 的扩展,通过 Flask-RESTful 我们可以快速的为 Flask 应用增加 API 接口。

首先,需要新增文件 module.py,用于归集扩展模块的对象。

# -*- coding:utf-8 -*-
from flask_restful import Api
api = Api()

然后,在 app.py 文件中对 Flask-RESTful 进行初始化。

def create_app(config=None):    app = Flask(        'server', instance_relative_config=True    )
    configure_module(app)
    app.add_url_rule('/', view_func=HelloWorld.as_view('HelloWorld'))
    return app
def configure_module(app):    # 初始化 Flask-RESTful    api.init_app(app)

最后,在第二层 server 目录中新建 api 目录,新建文件 api.py 和 __init__.py,内容分别如下:

__init__.py 文件内容

# -*- coding:utf-8 -*-
from server.api import api

api.py 文件内容

# -*- coding:utf-8 -*-from flask_restful import Resource, reqparsefrom server.module import apifrom flask import jsonify
class HelloWorld(Resource):    def get(self):        return jsonify({            'status': 1,            'message': 'Hello World!'        })
api.add_resource(HelloWorld, '/api/helloworld')

通过 curl 命令来访问 /api/helloworld 的过程如下:

➜  ~ curl http://127.0.0.1:5000/api/helloworld{"message":"Hello World!","status":1}

通过 Postman 访问的结果如下图:

此时整个程序的目录如下:

server├── main.py├── requirements.txt└── server    ├── __init__.py    ├── api    │   ├── __init__.py    │   └── api.py    ├── app.py    └── module.py

增加数据库支持

SQLAlchemy 是当前最流行的 Python 数据库 ORM「对象关系映射」 框架。提供了 Python 类到数据表的映射,将数据表的创建过程大大简化,对数据表的操作进行 python 函数式封装,提高了程序开发的进度及可读性。

Flask-SQLAlchemy 为 Flask 应用提供了 SQLAlchemy 的支持,它提供了大多数的默认值来简化各种操作,使用起来十分简单且有趣。

在 Flask 中添加 SQLAlchemy 的支持需要对现有代码进行一下修改:

首先,在 module.py 文件中增加 SQLAlchemy 的实例,并在 app.py 文件中初始化 SQLAlchemy:

module.py 文件中新增以下内容:

from flask_sqlalchemy import SQLAlchemyfrom sqlalchemy import MetaData
metadata = MetaData(    naming_convention={        "ix": "ix_%(column_0_label)s",        "uq": "uq_%(table_name)s_%(column_0_name)s",        "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",        "pk": "pk_%(table_name)s",    })db = SQLAlchemy(metadata=metadata)

app.py 文件中对 SQLAlchemy 进行初始化,新增代码如下:

def create_app(config=None):    ...    app.config.from_object("server.config.DefaultConfig")    ...
def configure_module(app):    # 初始化 Flask-RESTful    api.init_app(app)
    db.init_app(app)

其次,增加配置文件完成对 SQLAlchemy 数据库的配置,在当前的程序中我们使用 SQLite 数据库来实现,配置文件内容如下:

# -*- coding:utf-8 -*-
import os
class DefaultConfig(object):    basedir = os.path.join(os.path.abspath(os.path.dirname(                               os.path.dirname(__file__))))
    DEBUG=True    #Database    # For SQLite:    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + basedir + '/' + \                                  'test.sqlite'
    # This option will be removed as soon as Flask-SQLAlchemy removes it.    # At the moment it is just used to suppress the super annoying warning    SQLALCHEMY_TRACK_MODIFICATIONS = False    # This will print all SQL statements    SQLALCHEMY_ECHO = False
    SECRET_KEY = '1234567890098765d4321'

在 app.py 文件中新增的 app.config.from_object("server.config.DefaultConfig") 为 Flask 引入了配置文件的内容。

最后,增减用户类,以及在 api.py 文件中增加对数据中 user 表的访问。

新增用户类文件 user.py 的内容如下:

from server.module import db
class CRUDMixin(object):
    def __repr__(self):        return "<{}>".format(self.__class__.__name__)
    @classmethod    def create(cls, **kwargs):        instance = cls(**kwargs)        return instance.save()
    def save(self):        """Saves the object to the database."""        db.session.add(self)        db.session.commit()        return self
    def delete(self):        """Delete the object from the database."""        db.session.delete(self)        db.session.commit()        return self

class User(db.Model, CRUDMixin):    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)    name = db.Column(db.String(200), unique=True, nullable=False)    password = db.Column(db.String(200), nullable=False)
    def to_json(self):        return {            'id': self.id,            'name': self.name,            'password': self.name        }

在 api.py 文件中新增 http://127.0.0.1:5000/api/user 接口,提供 GET 和 POST 方法,分别用来获取数据库中用户信息和向数据库中新增用户信息。新增 http://127.0.0.1:5000/api/create 接口,通过 GET 方法初始化 SQLite 数据库并新建 user 数据表。api.py 文件完成内容如下:

# -*- coding:utf-8 -*-from flask_restful import Resource, reqparsefrom server.module import apifrom flask import jsonify, requestfrom sqlalchemy import funcfrom server.models.user import Userfrom server.module import dbfrom sqlalchemy_utils import database_exists, create_database
class HelloWorld(Resource):    def get(self):        return jsonify({            'status': 1,            'message': 'Hello World!'        })
class Create(Resource):    def get(self):        if database_exists(db.engine.url):            return jsonify({                'messge': '数据库已存在!'            })        create_database(db.engine.url)        db.create_all(bind=None)        return jsonify({            'messge': '数据库创建完成!'        })
class UserList(Resource):
    def get(self):        users = db.session.query(User).all()        return jsonify({            'users': [x.to_json() for x in users]        })
    def post(self):        json = request.get_json(force=True)        username = json['name']        password = json['password']        user = User.query.filter_by(name=username).first()        if user:            return jsonify({                'message': "用户: " + username + " 已存在!"            })        user = User()        user.name = username        user.password = password        user.save()        return jsonify({            'message': "添加用户: " + username + " 完成!"        })
api.add_resource(HelloWorld, '/api/helloworld')api.add_resource(UserList, '/api/user')api.add_resource(Create, '/api/create')

在命令行中启动 Flask 程序,通过 curl 命令访问各个 api 获取内容如下:

➜  ~ curl http://127.0.0.1:5000/api/create{  "messge": "The database is exists\uff01"}➜  ~ curl http://127.0.0.1:5000/api/create{  "messge": "The database is exists!"}➜  ~ curl http://127.0.0.1:5000/api/create{  "messge": "The database is ready!"}➜  ~ curl http://127.0.0.1:5000/api/user{  "users": []}➜  ~ curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"name": "test","password": "test"}' http://127.0.0.1:5000/api/user{  "message": "Add User: test finish!"}➜  ~ curl http://127.0.0.1:5000/api/user{  "users": [    {      "id": 1,      "name": "test",      "password": "test"    }  ]}➜  ~ curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"name": "1234","password": "1234"}' http://127.0.0.1:5000/api/user{  "message": "Add User: 1234 finish!"}➜  ~ curl http://127.0.0.1:5000/api/user{  "users": [    {      "id": 1,      "name": "test",      "password": "test"    },    {      "id": 2,      "name": "1234",      "password": "1234"    }  ]}

此时整个程序的目录如下:

├── main.py├── requirements.txt├── server│   ├── __init__.py│   ├── api│   │   ├── __init__.py│   │   └── api.py│   ├── app.py│   ├── config.py│   ├── models│   │   └── user.py│   └── module.py└── test.sqlite

增加用户认证

在 Flask 中用于用户认证的扩展主要有 Flask-Login 和 Flask-HTTPAuth。Flask-Login 提供了基于 Cookie 和 session 的用户管理,更多的用在可见视图的应用场景中。而我们所使用的 RESTful API 是无状态的,无法通过 Cookie 或 session 来进行用户认证,不过 Flask-HTTPAuth 提供基于 API 的认证方式。

Flask-HTTPAuth 支持以下认证方式:

  • HTTPBasicAuth
  • HTTPDigestAuth
  • HTTPTokenAuth
  • MultiAuth

本文主要针对 HTTPBasicAuth 认证方式进行介绍。

首先,在 module.py 文件中建立 HTTPBasicAuth 的实例:

auth = HTTPBasicAuth()

其次,在 app.py 文件中增加 HTTPBasicAuth 的密码校验回调函数

@auth.verify_passworddef verify_password(username, password):    g.current_user = None    user = User.query.filter_by(name = username).first()    if not user or not user.password == password:        return False    g.current_user = user    return True

最后,在需要保护的路径上增加 login_required 装饰器。我们在 user 和 create 路径上增加装饰器,保持 hello world 可以正常访问。

class Create(Resource):    decorators = [multi_auth.login_required]    ...
class UserList(Resource):    decorators = [multi_auth.login_required]    ...

通过 curl 命令验证各 api 的增加认证后的访问方式:

➜  ~ curl http://127.0.0.1:5000/api/helloworld{  "message": "Hello World!",  "status": 1}➜  ~ curl http://127.0.0.1:5000/api/createUnauthorized Access%                                                            ➜  ~ curl --base -u test:test http://127.0.0.1:5000/api/createcurl: option --base: is unknowncurl: try 'curl --help' or 'curl --manual' for more information➜  ~ curl --basic -u test:test http://127.0.0.1:5000/api/create{  "messge": "The database is exists!"}➜  ~ curl http://127.0.0.1:5000/api/userUnauthorized Access%                                                            ➜  ~ curl --basic -u test:test http://127.0.0.1:5000/api/user{  "users": [    {      "id": 1,      "name": "test",      "password": "test"    },    {      "id": 2,      "name": "1234",      "password": "1234"    }  ]}

通过验证结果可以看出 user 和 create 路径在访问时需要携带登录用户信息,否则会提示 UnauthorizedAccess

本文通过 Flask 做框架,在使用 Flask-RESTful、Flask-SQLAlchemy 和 Flask-HTTPAuth 等扩展的情况下,实现一个支持数据库持久化存储和用户认证的 RESTful API 服务端,总体来说完成了预期所要完成的目标。

本文分享自微信公众号 - keinYe(keinYe_zh),作者:keinYe

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用Flask构建简单的RESTful服务

    我们现在的一个项目是使用Django来构建,说来也是基于技术扩展的考虑,我对于Django里面大而全的一些组件还是持有保守态度,所以虽然项目用了Djan...

    jeanron100
  • golang 创建 restful 服务

    修改代码后我们需要重新 build 后再次启动服务。 然后可以 Postman 开测试一下我们的接口是否好用

    李海彬
  • Flask 学习篇一: 搭建Python虚拟环境,安装flask,并设计RESTful API。

    前些日子,老师给我看了这本书,于是便开始了Flask的学习 ? GitHub上的大神,于是我也在GitHub上建了一个Flask的项目。 有兴趣可以看看: ht...

    ShenduCC
  • 外行学 Python 爬虫 第九篇 读取数据库中的数据

    前面的一至八篇我们一直在研究如何从网站上快速、方便的获取数据,并将获取到的数据存储在数据库中。但是将数据存储在数据中并不是我们的目的,获取和存储数据的目的是为了...

    keinYe
  • 如何使用Flask编写Python Web API【Programming(Python)】

    在此快速教程中,使用Flask(增长最快的Python框架之一)从服务器获取数据。

    Potato
  • 教你 10 分钟构建一套 RESTful API 服务( Flask篇 )

    上一篇文章,介绍了使用 Java + Spring Boot + MyBatis 构建 RESTful API 的详细步骤;很多小伙伴表示,更愿意用 Pytho...

    AirPython
  • 教你 10 分钟构建一套 RESTful API 服务( 中 )

    上一篇文章,介绍了使用 Java + Spring Boot + MyBatis 构建 RESTful API 的详细步骤;很多小伙伴表示,更愿意用 Pytho...

    AirPython
  • python实现RESTful服务(基于flask)

    上一篇文章讲到如何用java实现RESTful服务,这就来讲讲怎么用python来实现吧,因为要搭建一套java和python互调的服务,两者都不能少啊。

    vell001
  • 使用 Spring 构建 RESTful Web 服务

    本指南将引导您完成使用 Spring 创建“Hello, World”RESTful Web 服务的过程。

    IT胶囊
  • 使用RESTful 创建文件接收 API

    文件「文本、文档、图片等等」是一个服务器不可缺少的部分,在 使用 Flask 创建 RESTful 服务 介绍了如何使用 Flask 创建一个支持 RESTfu...

    keinYe
  • Python restful框架接口开发实现

    2.cmd输入:pip install flask-restful,安装flask-restful

    砸漏
  • 使用Flask和Vue.js开发一个单页面应用程序(一)

    首先,我会使用Vue CLI搭建一个新的Vue应用程序,然后通过Python和Flask支持的后端RESTful API执行基本的CRUD操作。

    TalkPython
  • 从头完成一个restful API 服务

    “ 昨天搭建了一个HTTPS的服务器,放在那里不用简直是浪费了,今天来部署一个RESTFul API服务”

    周萝卜
  • 接口测试 | 21 基于flask弄个restful API服务出来

    概述 上篇我们很简单的分享了如何基于flask搞一个支持http GET\POST\HEAD\DELETE方法的服务,大家可以根据这个简单的实例进行扩展。 下面...

    苦叶子
  • 害怕部署机器学习模型?这里有一篇手把手教程

    阅读本文后,你将能够部署机器学习模型,并用你想要的编程语言进行预测。没错,你可以坚持使用 Python,也可以通过 Java 或 Kotlin 直接在你的 An...

    AI研习社
  • Python的Flask框架开发RESTful API

    运行python app.py,Flask自带的Server在端口5000上监听:

    测试开发社区
  • Python Web - Flask笔记8

    CSRF(Cross Site Request Forgery)跨站域请求伪造是一种网络攻击方式。

    YingJoy_
  • AutoLine源码分析之如何构建restful API

    在autoline开源平台中我们采用了blueprint来统计管理路由,使用flask-restful插件来实现restful API

    苦叶子
  • 带有 Python REST Web 服务示例的 REST API 快速入门指南

    它是一种架构风格,一组用于标准化 Web 的规则,以保持全球 Web 应用程序的一致性。它旨在增强 Web 应用程序的可维护性、可扩展性、可靠性和可移植性。

    玖柒的小窝

扫码关注云+社区

领取腾讯云代金券