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. ACM International Collegiate Programming Contest, Egyptian Collegiate Programming Contest (ECPC 2015)

    A.Arcade Game(康拓展开) 题意: 给出一个每个数位都不同的数n,进行一场游戏.每次游戏将n个数的每个数位重组.如果重组后的数比原来的数大则继续游戏,否则算输.如果重组后的数是最大的数则算 ...

  2. NOIP2012 洛谷P1084 疫情控制

    Description: H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情 ...

  3. codeforces 1060 A

    https://codeforces.com/contest/1060/problem/A 题意:电话号码是以8开头的11位数,给你n 个数问最多可以有多少个电话号码 题解:min(8的个数,n/11 ...

  4. x:Class, x:Key

    x:Class: 用来创建一个partial的class, 比如默认生成的x:Class="MyTest.MainWindow", 会自动生成一个MainWindow的partia ...

  5. WebComponents四大天王教程

    Shadow Dom: http://www.html5rocks.com/zh/tutorials/webcomponents/shadowdom/ http://www.html5rocks.co ...

  6. [转载]超赞!32款扁平化Photoshop PSD UI工具包(下)

    32款扁平化风格的UI工具包第二弹!上篇为大家分享了16款风格各异的UI Kits,下篇继续为大家呈上16款精美的UI工具包,全部都有Photoshop PSD文件可以下载哦,喜欢就赶紧收藏吧! 17 ...

  7. 【洛谷 P1651】 塔 (差值DP)

    题目链接 题意:\(n\)个木块放到两个塔里,每个木块可放可不放,使得两塔高度相同且高度最大,求最大高度. 这个差值\(DP\)的思维难度还是很大的,没想出来,我就打了一个\(dfs\)骗了好像\(2 ...

  8. ZOJ1003 Crashing Balloon

    Crashing Balloon Time Limit: 2 Seconds      Memory Limit: 65536 KB On every June 1st, the Children's ...

  9. 【bzoj2086】Blocks

    在洛谷上点了个Splay的tag想玩玩,结果看到这题…… #include<bits/stdc++.h> #define N 1000005 using namespace std; ty ...

  10. vijos P1051 送给圣诞夜的极光

    调了好久... #include <cstdio> #include <queue> using namespace std; char a[110*110]; /****** ...