Restful API规范

restful api是用于前端和后台进行通信的一套规范。使用这个规范可以让前后端开发变得更加轻松。

协议

  采用http或者https

数据传输格式

  数据之间传输的格式应该都使用json,而不是xml

url链接

  url链接中,不能有动词,只能有名词。并且对于一些名词,如果出现复数,那么应该在后面加s

  比如: 获取文章列表,应该使用/articles/, 而不应该使用/get_article/

HTTP请求方法

  GET: 从服务器上获取资源  (常用)

  POST:在服务器上新创建一个资源  (常用)

  PUT:在服务器上更新资源。(客户端提供所有改变后的数据)

  PATCH:在服务器上更新资源。(客户端只提供需要改变的属性)

  DELETE: 从服务器上删除资源

状态码

状态码 原生描述 描述
200 OK 服务器成功响应客户端的请求
400 INVALID REQUEST 用户发出的请求有错误,服务器没有进行新建或修改数据的操作
401 Unauthorized 用户没有权限访问这个请求
403 Forbidden 因为某些原因禁止访问这个请求
404 NOT FOUND 用户发送的请求的url不存在
406 NOT Accept 用户请求不被服务器接收(比如服务器期望客户端发送某个字段,但没有发送)
500 Internal server error 服务器内部错误,比如出现了bug

Flask-Restful插件的基本使用

安装flask-restful插件

pip install flask-restful

定义Restful视图

如果使用flask-restful,那么定义视图函数的时候,就要继承自flask_restful.Resource类,然后再根据当前请求的method来定义相应的方法。比如期望客户端使用get方法发送请求,那么就定义一个get方法,期望客户端使用post方法发送请求,就定义一个post方法。类似于MethodView.

因为我们只定义了post方法,如果直接用浏览器去访问http://127.0.0.1:5000/login/(get方法),得不到我们想要的结果

这个时候我们就可以用一些测试工具,我这里使用的是Insomnia,同类的软件还有postman

url中也可以传递参数

url也可以是多个

参数验证

Flask-Restful插件提供了类似WTForm来验证提交的数据是否合法的包,叫做reqparse。以下是基本用法

parser = reqparse.RequestParser()
parser.add_argument('username', type=str, required=True, help='用户名验证错误')
args = parser.parse_args()

add_argument可以指定这个字段的名字,这个字段的数据类型等

default:默认值,如果这个参数没有值,那么将使用这个参数指定的值。
required:是否必须。默认为False,如果设置为True,那么这个参数就必须提交上来。
type:这个参数的数据类型,如果指定,那么将使用指定的数据类型来强制转换提交上来的值。
choices:选项。提交上来的值只有满足这个选项中的值才符合验证通过,否则验证不通过。
help:错误信息。如果验证失败后,将会使用这个参数指定的值作为错误信息。
trim:是否要去掉前后的空格。

其中的type,可以使用python自带的一些数据类型,也可以使用flask_restful.inputs下的一些特定的数据类型来强制转换。比如一些常用的:

url:会判断这个参数的值是否是一个url,如果不是,那么就会抛出异常。
regex:正则表达式。
date:将这个字符串转换为datetime.date数据类型。如果转换不成功,则会抛出一个异常。

操作演示

因为username字段添加了参数required=True,为必填项,因此如果客户端不传此字段,就会提示错误,这个错误提示就是我们自定的help--->"用户名验证错误"

...
from flask_restful import Api, Resource, reqparse, inputs app = Flask(__name__)
app.config.from_object(config)
api = Api(app) class RegisterView(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('username', type=str, required=True, help='用户名字段验证错误')
parser.add_argument('birthday', type=inputs.date, required=True, help='生日字段验证错误')
parser.add_argument('gender', type=str, choices=('male', 'female'), help='性别字段验证错误')
parser.add_argument('money', type=int, trim=True, default=0, help='金额字段验证错误')
parser.add_argument('phone', type=inputs.regex(r'1[3458]\d{9}'), help='手机字段验证错误')
parser.add_argument('blog', type=inputs.url, help='博客地址字段验证错误')
args = parser.parse_args()
print(args)
return 'success' api.add_resource(RegisterView, '/register/', endpoint='register')
...

Flask-Restful标准化返回参数

对于一个视图函数,我们可以指定好一些参数用于返回,在规范中要求:即使这个参数没有值也应该返回,返回一个None回去

...
from flask_restful import Api, Resource, fields, marshal_with api = Api(app) class ArticleView(Resource):
resource_field = { #先定义好返回哪些参数
'name': fields.String, #参数的数据类型
'age': fields.String,
'school': fields.String
} @marshal_with(resource_field) #利用marshal_with装饰器传入定义好的返回参数
def get(self):
return {} 就算这里返回个空字典,也会把定义好的参数返回 api.add_resource(ArticleView, '/article/', endpoint='article')

...
class ArticleView(Resource):
resource_field = {
'name': fields.String,
'age': fields.String,
'school': fields.String
} @marshal_with(resource_field)
def get(self):
return {'name': 'heboan', 'age': 18} ...

当使用ORM模型或者自定义的的模型的时候,它会自动的获取模型中相应的字段,生成json数据,然后返回给客户端

class ProfileView(Resource):
resource_fields = {
'username': fields.String,
'age': fields.Integer,
'school': fields.String
} @marshal_with(resource_fields)
def get(self,user_id):
user = User.query.get(user_id)
return user

在get方法中,返回user的时候,flask_restful会自动的读取user模型上的username, age以及school属性。组装成一个json格式的字符串返回给客户端

重名属性

如果我们想把面向公众的字段名称不用与内部的属性名。使用attribute可以配置这种属性,比如现在想要返回user.school中的值,但是在返回给外面的时候,想以education返回回去,那么可以这样写:

resource_fields = {
'education': fields.String(attribute='school')
}

默认值

在返回一些字段的时候,有时候可能没有值,那么这时候可以在指定fields的时候给定一个默认值,示例代码如下:

resource_fields = {
'age': fields.Integer(default=18)
}

复杂的结构

有时候想要在返回的数据格式中,形成比较复杂的结构。那么可以使用一些特殊的字段来实现。比如要在一个字段中放置一个列表,那么可以使用fields.List,比如在一个字段下面又是一个字典,那么可以使用fields.Nested。以下将讲解下复杂结构的用法:

定义数据库结构:

user表,article表,tag表, 因为article与tag是多对多的关系,因此需要一个中间表来关联article_tag

from exts import db

class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(50), nullable=False) class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(50), nullable=False)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id')) author = db.relationship('User', backref='articles')
tags = db.relationship('Tag', secondary='article_tag') class Tag(db.Model):
__tablename__ = 'tag'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False) article_tag = db.Table(
'article_tag',
db.Column('article_id', db.Integer, db.ForeignKey('article.id')),
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
)

models

插入测试数据

...
from models import User, Article, Tag @app.route('/')
def index():
user = User(username='heboan')
tag_1 = Tag(name='Linux')
tag_2 = Tag(name='Python')
article = Article(title='python自动化运维', content='Life is short, I use python...') article.tags.append(tag_1)
article.tags.append(tag_2)
article.author = user db.session.add(article)
db.session.commit()
return '数据插入成功!'

视图

当我们全部使用field.String

class ArticleView(Resource):
resource_fields = {
'title':fields.String,
'content': fields.String,
'author':fields.String,
'tags':fields.String
} @marshal_with(resource_fields)
def get(self):
article = db.session.query(Article).get(1)
return article api.add_resource(ArticleView, '/article/', endpoint='article')

使用field.Nested、field.List

class ArticleView(Resource):
resource_fields = {
'title':fields.String,
'content': fields.String,
'author':fields.Nested({ #字典里面嵌套字典使用field.Nested
'username': fields.String
}),
'tags':fields.List(fields.Nested({ #tags是列表,使用field_List类型然后嵌套field.Nested
'id': fields.Integer,
'name': fields.String
}))
} @marshal_with(resource_fields)
def get(self):
article = db.session.query(Article).get(1)
print(article.title)
return article api.add_resource(ArticleView, '/article/', endpoint='article')

在蓝图使用使用Flask-Restful

新建一个articles.py

from flask import Blueprint
from flask_restful import Api, Resource, fields, marshal_with
from exts import db
from models import Article article_bp = Blueprint('article', __name__, url_prefix='/article')
api = Api(article_bp) #这里使用article_bp了 class ArticleView(Resource):
resource_fields = {
'title':fields.String,
'content': fields.String,
'author':fields.Nested({
'username': fields.String
}),
'tags':fields.List(fields.Nested({
'id': fields.Integer,
'name': fields.String
}))
} @marshal_with(resource_fields)
def get(self):
article = db.session.query(Article).get(1)
print(article.title)
return article api.add_resource(ArticleView, '/1/', endpoint='article')

主程序注册此蓝图

from article import article_bp
... app.register_blueprint(article_bp)

Flask-Restful渲染模板

先看看直接渲染模板是什么效果

class HelloView(Resource):
def get(self):
return render_template('hello.html') api.add_resource(HelloView, '/hello/', endpoint='hello')

可以发现这样渲染出来的页面并不是我们想要的。要想使用Flask-Restful渲染页面还需要定义一个out_html函数

@api.representation('text/html')
def out_html(data, code, headers):
resp = make_response(data)
return resp class HelloView(Resource):
def get(self):
return render_template('hello.html') api.add_resource(HelloView, '/hello/', endpoint='hello')

其中那个data就是页面的内容

23、Flask实战第23天:Flask-Restful的更多相关文章

  1. Flask实战-留言板-安装虚拟环境、使用包组织代码

    Flask实战 留言板 创建项目目录messageboard,从GreyLi的代码中把Pipfile和Pipfile.lock文件拷贝过来,这两个文件中定义了虚拟环境中需要安装的包的信息和位置,进入m ...

  2. 1、Flask实战第1天:第一个Flask程序

    Flask是流行的python web框架...(* ̄︶ ̄) 零基础到企业级论坛实战,人生苦短,我用python,开启FLask之旅吧... 安装开发环境 下载Python win版安装包 双击运行, ...

  3. 使用Flask设计带认证token的RESTful API接口

    大数据时代 Just a record. 使用Flask设计带认证token的RESTful API接口[翻译] 上一篇文章, 使用python的Flask实现一个RESTful API服务器端  简 ...

  4. [易学易懂系列|rustlang语言|零基础|快速入门|(23)|实战1:猜数字游戏]

    [易学易懂系列|rustlang语言|零基础|快速入门|(23)|实战1:猜数字游戏] 项目实战 实战1:猜数字游戏 我们今天来来开始简单的项目实战. 第一个简单项目是猜数字游戏. 简单来说,系统给了 ...

  5. Flask从入门到精通之flask安装

    使用虚拟环境 安装Flask最简单的方式是使用虚拟环境,虚拟环境是python解释器的一个私有副本,在这个环境中你可以安装私有包,而且不会影响系统中安装的全局的Python解释器.虚拟环境非常有用,可 ...

  6. Python接口测试实战5(下) - RESTful、Web Service及Mock Server

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  7. Flask框架(一)—— Flask简介

    Flask框架(一)—— Flask简介 目录 Flask框架介绍 一.Flask简介 二.flask安装与使用 1.安装 2.使用 3.简单案例——flask实现用户登录 Flask框架介绍 一.F ...

  8. flask tutorial => make a blog :) flask 搭建博客系统从零开始!

    please follow the tutorial from the official site :) http://flask.pocoo.org/docs/ You could download ...

  9. 【Flask】微型web框架flask大概介绍

    Flask Flask是一个基于python的,微型web框架.之所以被称为微型是因为其核心非常简单,同时具有很强的扩展能力.它几乎不给使用者做任何技术决定. 安装flask时应该注意其必须的几个支持 ...

随机推荐

  1. [洛谷P1951]收费站_NOI导刊2009提高(2)

    题目大意:有一张$n$个点$m$条边的图,每个点有一个权值$w_i$,有边权,询问从$S$到$T$的路径中,边权和小于$s$,且$\max\limits_{路径经过k}\{w_i\}$最小,输出这个最 ...

  2. 导致SQL执行慢的原因

    索引对大数据的查询速度的提升是非常大的,Explain可以帮你分析SQL语句是否用到相关索引. 索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左 ...

  3. Codeforces Round #520 (Div. 2) A. A Prank

    A. A Prank time limit per test   1 second memory limit per test    256 megabytes 题目链接:https://codefo ...

  4. 类名.class 类名.this 详解

    我们知道在java中,一个类在被加载的时候虚拟机就会自动的生成一个这个类的一个Class类型的“类对象”,每个类都对应着一个这样的类对象,通过这个Class类型的类对象,我们就能够使用“内省与反射”机 ...

  5. Nginx support TCP Load balance

    1. Install nginx package 2. edit nginx configuration file [root@ip- nginx]# more nginx.conf user ngi ...

  6. 固定width但是有间隔

    <!DOCTYPE > <html> <head> <title></title> <meta name="name&quo ...

  7. uva 11427

    题目大意:每天晚上你都玩纸牌,如果第一次赢了就高高兴兴地去睡觉:如果输了就接着玩,假设每盘游戏获胜的的概率都是p,且各盘游戏相互独立.你是一个固执的完美主义者,因此会一直玩到当晚获胜局数的比例严格大于 ...

  8. 动态规划:LCIS

    先给出状态转移方程: 定义状态 F[i][j]表示以a串的前i个整数与b串的前j个整数且以b[j]为结尾构成的LCIS的长度 状态转移方程: ①F[i][j] = F[i-][j] (a[i] != ...

  9. rest service技术选型

    MySql workbench下载 http://dev.mysql.com/downloads/workbench/ 最好的8个 Java RESTful 框架 http://colobu.com/ ...

  10. CTSC游记

    CTSC游记 day 0 到达帝都. 复习板子 day 1 第一题傻逼题啊 第二题第三题写个暴力 好了120稳了 出来一看第一题基数排序炸了? 51+10+10崩盘 day 2 答辩有意思啊 王选怎么 ...