阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

RESTful

265次阅读
没有评论

共计 6999 个字符,预计需要花费 18 分钟才能阅读完成。

一、RESTful Api 设计风格

1、什么是 RESTFul

  • 简介

    REST 即表述性状态传递(英文:Representational State Transfer,简称 REST)是 Roy Fielding 博士在 2000 年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。

    RESTFul 是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。遵循 restful 风格开发出来的应用程序接口,就叫 RESTFul API。

    RESTFul 的接口都是围绕资源以及对资源的各种操作展开

  • 资源

    所谓的资源就是在网络上存在的任意实体,哪怕是一条消息。

  • 操作

    所谓的操作就是对资源的 CURD。在开发者设计良好的前提下,对网络资源的任意的动作都可抽象为对资源的 CURD。RESTFul 对网络资源的操作抽象为 HTTP 的 GET、POST、PUT、DELETE 等请求方法以完成对特定资源的增删改查

2、协议

API 与用户的通信协议总是使用 https 协议

3、域名

应尽量将 API 部署在专用域名下

https://www.xialigang.com

如果确定 API 很简单,不会有进一步扩展,可以放在主域名下

https://www.xialigang.com/api/

4、版本

应该将版本放入 URL

https://www.xialigang.com/api/v1/

可以将版本放入 http 头信息中

5、路径

说明

  • 表示 API 的具体地址

注意

  • 每个网址代表一种资源,所以网址中不能有动词,只能是名词,而且所用的名词往往与数据库中的表名对应

示例

  • 错误示例

    https://127.0.0.1/api/v1/getStudents/
    
  • 正确示例

    https://127.0.0.1/api/v1/students/
    

6、使用正确的 HTTP 请求方式

方法 行为 例子
GET 获取所有资源 http://127.0.0.1:5000/api/source
GET 获取指定资源 http://127.0.0.1:5000/api/source/250
POST 创建新的资源 http://127.0.0.1:5000/api/source
PUT 更新指定资源 http://127.0.0.1:5000/api/source/250
DELETE 删除指定资源 http://127.0.0.1:5000/api/source/250
DELETE 删除所有资源 http://127.0.0.1:5000/api/source/

7、过滤信息

  • 概述
    如果资源较多,服务器不能将所有的数据一次全部返回给客户端,API 提供参数,过滤返回结果

  • 参数

    • limit 获取多少个资源

      GET https://127.0.0.1:5000/api/v1/students/?limit=10

    • offset 偏移多少个资源
      GET https://127.0.0.1:5000/api/v1/students/?offset=10

    • page 要获取哪页的资源

    • per_page 每页有多个资源
      GET https://127.0.0.1:5000/api/v1/students/?page=1&per_page=5

    • sortby 根据哪个属性进行排序

    • orderby 排序的规则

      GET https://127.0.0.1:5000/api/v1/students/?sortby=age&orderby=desc

    • 类名小写_运算符_属性 = 值

      GET https://127.0.0.1:5000/api/v1/students/?student_gt_age=20

8、状态码

状态码 请求方式 说明
200 get OK 服务器成功返回资源
201 post、put、patch Created 用户新建或者修改资源成功
202 * Accepted 表示请求已经进入后台排队
204 delete No Content 用户删除资源成功
400 post、put、patch Bad Request 用户发出的请求有错误
401 * Unauthorized 用户没有权限(令牌、用户名、密码错误)
403 * Forbidden 表示用户得到授权(与 401 相对),但是访问是被禁止的
404 * Not Found 请求针对的是不存在的资源
405 * Method Not Allowed 用户请求的方式不被允许
406 get Not Acceptable 用户请求的格式不可得(比如用户请求 json 格式,但是只有 xml 格式)
410 get Gone 用户请求的资源被永久删除,且不可在得到
422 post、put、patch Unprocessable Entity 创建对象时发生了验证错误
500 * Internal Server Error 服务器发生错误

9、错误处理

如果状态码是 4xx,就应该向用户返回错误信息,一般返回内容中以 error 作为键,错误信息作为值返回

{"error": "参数有误"
}

10、链接相关的资源

  • 说明

    返回的结果中提供了链接,链向其他 API 方法啊,需要让用户不查看文档(项目文档)就知道下一步该干什么

  • 实例

    地址

    GET /students/<id>/

    {"name": "lucky",
    "age": 50,
    "link": "https://127.0.0.1/api/v1/test/"
    }

    restful 风格

    {"name": "lucky",
    "age": 50,
    "link": {"rel": "collection 127.0.0.1:5000"
    "href": "127.0.0.1/api/v1/test/"
    "title": "测试界面"
    "type": "application/json"
    }
    }

    • rel 表示这个 API 与当前网址的关系
    • href 表示 API 的路径
    • title 表示 API 的标题
    • type 表示返回数据的类型

11、工具

  • 说明

    postman 是一款非常好用的 API 开发测试工具,可以非常方便的模拟各种请求

  • 提示

    下载安装包,一路 NEXT 完成安装

    网址:https://www.postman.com/

二、原生实现 RESTful

1、准备数据

# 测试数据
posts = [
{'id': 1,
'title': 'Python 语法',
'content': '别人都说 python 语法很简单,但是每次问题都出在语法上'
},
{'id': 2,
'title': 'HTML',
'content': '不就是几个标签的问题嘛,但是最好细心点'
}
]

2、获取资源

  • 获取所有资源

    # 获取资源列表
    @app.route('/posts')
    def get_posts_list():
    return jsonify({'posts': posts})
  • 获取指定资源

    # 获取指定资源
    @app.route('/posts/<int:pid>')
    def get_posts(pid):
    p = list(filter(lambda p: p['id'] == pid, posts))
    if len(p) == 0:
    abort(404)
    return jsonify({'posts': p[0]})

3、添加新的资源

# 添加新的资源
@app.route('/posts', methods=['POST'])
def create_posts():
if not request.json or 'title' not in request.json or 'content' not in request.json:
abort(400)
# 创建新资源
p = {'id': posts[-1]['id'] + 1,
'title': request.json['title'],
'content': request.json['content']
}
# 保存资源
posts.append(p)
return jsonify({'posts': p}), 201

4、更新指定的资源

# 修改指定资源
@app.route('/posts/<int:pid>', methods=['PUT'])
def update_posts(pid):
p = list(filter(lambda p: p['id'] == pid, posts))
if len(p) == 0:
abort(404)
if 'title' in request.json:
p[0]['title'] = request.json['title']
if 'content' in request.json:
p[0]['content'] = request.json['content']
return jsonify({'posts': p[0]}), 201

5、删除指定资源

# 删除指定资源
@app.route('/posts/<int:pid>', methods=['DELETE'])
def delete_posts(pid):
p = list(filter(lambda p: p['id'] == pid, posts))
if len(p) == 0:
abort(404)
posts.remove(p[0])
return jsonify({'result': '数据已删除'}), 204

6、删除所有资源

# 删除所有资源
@app.route('/posts', methods=['DELETE'])
def delete_posts(pid):
posts.clear()
return jsonify({'result': '数据已删除'}), 204

7、错误定制

@app.errorhandler(404)
def page_not_found(e):
return jsonify({'error': 'page not found'}), 404
@app.errorhandler(400)
def bad_request(e):
return jsonify({'error': 'bad request'}), 400

三、flask-restful

1、安装

pip install flask-restful

2、创建

from flask_restful import Api
api = Api()
from .ext_api import api

3、加载

from exts import api
api.init_app(app)

4、视图类

from flask_restful import Resource
from myApp.models import User
from flask import request
# 创建用户处理类
class UserApi(Resource):
def get(self, uid):
u = User.query.get(uid)
if u:
return {'code':0, 'error':'','data':{'id':uid, 'uusername':u.uusername, 'uage': u.uage, 'usex': u.usex, 'uinfo': u.uinfo}}
else:
return {'code':1, 'error':'获取失败','data':{}}, 404
def put(self, uid):
u = User.query.get(uid)
if not u:
return {'code':1, 'error':'获取失败','data':{}}, 404
json = request.json
u.uusername = json.get('uusername')
u.uage = json.get('uage')
u.save()
return {'code': 0, 'error': '',
'data': {'id': uid, 'uusername': u.uusername, 'uage': u.uage, 'usex': u.usex, 'uinfo': u.uinfo}}, 201
def delete(self, uid):
u = User.query.get(uid)
if not u:
return {'code': 1, 'error': '获取失败', 'data': {}}, 404
u.delete()
return {'code': 0, 'error': '', 'data': {}}, 204
class UserApiTwo(Resource):
def get(self):
u = User.query.all()
userList = []
for user in u:
userList.append({'id':user.id, 'uusername':user.uusername, 'uage': user.uage, 'usex': user.usex, 'uinfo': user.uinfo})
return {'code': 0, 'error': '', 'data': userList}
def delete(self):
uList = User.query.all()
for u in uList:
u.delete()
return {'code':0, 'error': '', 'data':''}, 204
def post(self):
json = request.json
u = User()
u.uusername = json.get('uusername')
u.uage = json.get('uage')
u.usex = bool(json.get('usex'))
u.uinfo = json.get('uinfo')
print(json)
if u.save():
return {'code': 0, 'error': '',
'data': {'id': u.id, 'uusername': u.uusername, 'uage': u.uage, 'usex': u.usex,'uinfo': u.uinfo}}, 201
return {'code':1 ,'error':'创建失败', 'data':''}, 400

5、配置路由

# 添加资源,可以一个资源指定多个路由地址
api.add_resource(UserAPI, '/users/<int:uid>', '/u/<int:uid>')
api.add_resource(UserListAPI, '/users/')
# 若创建 Api 对象时没有指定 app,那么指定 app 的位置应放在添加资源之后

6、拆分路由和视图

api 目录下一个文件就是一个模型相关的视图类,urls.py 仅做路由的匹配

from myApp.api.api_user import UserApi, UserListAPI
# 配置路由
api.add_resource(UserAPI, '/users/<int:uid>', '/u/<int:uid>')
api.add_resource(UserListAPI, '/users/')

7、添加认证

  • 说明

    Restful API 不保存状态,无法依赖 Cookie 及 Session 来保存用户信息,自然也无法使用 Flask-Login 扩展来实现用户认证。所以这里,我们就要介绍另一个扩展,Flask-HTTPAuth

  • 安装

    pip install flask-httpauth

  • 示例

    from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
    from flask_httpauth import HTTPBasicAuth
    # 创建对象
    auth = HTTPBasicAuth()
    # 认证的回调函数
    @auth.verify_password
    def verify_password(username_or_token, password):
    # 去数据库有中进行查找
    u = User.query.filter(User.uusername == username_or_token, User.upassword == password).first()
    print(username_or_token, '=====>',password)
    if u:
    # if username_or_token == 'lucky' and password == '123456':
    g.username = username_or_token
    return True
    # 验证 token
    s = Serializer(current_app.config['SECRET_KEY'])
    try:
    data = s.loads(username_or_token)
    g.username = data['username']
    return True
    except:
    return False
    # 认证错误定制
    @auth.error_handler
    def unauthorized():
    return jsonify({'error': 'Unauthorized Access'}), 403

    获取 token

    # 获取 token
    @app.route('/get_token')
    @auth.login_required
    def generate_token():
    s = Serializer(app.config['SECRET_KEY'], expires_in=3600)
    return s.dumps({'username': g.username})

    保护指定的视图类

    class UserAPI(Resource):
    # 添加认证
    decorators = [auth.login_required]

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-05-26发表,共计6999字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中