Restful Api 总结

# RESTful API开发

### 什么是REST?

- 简介

  ```
  REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。
  RESTful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
  RESTful API,就是符合REST风格开发出来的应用程序接口。
  ```

- 资源

  ```
  RESTful接口是围绕网络资源及对网络资源的动作展开的。所谓的资源就是网络上存在的实体,哪怕是一条数据。
  ```

- 动作

  ```
  所谓的动作就是对数据的CURD。在开发者设计良好的前提下,任何网络操作都可以抽象为对资源的CURD动作。RESTful对网络资源的操作抽象为HTTP的GET、POST、PUT、DELETE等请求方法,具体对照如下:
  ```

  | 方法     | 行为     | 示例                               |
  | ------ | ------ | -------------------------------- |
  | GET    | 获取资源信息 | http://127.0.0.1:5000/source     |
  | GET    | 获取指定资源 | http://127.0.0.1:5000/source/250 |
  | POST   | 创建新的资源 | http://127.0.0.1:5000/source     |
  | PUT    | 修改指定资源 | http://127.0.0.1:5000/source/250 |
  | DELETE | 删除指定资源 | http://127.0.0.1:5000/source/250 |

- 数据

  通常Restful API 风格的数据都采用JSON格式传输。

- 测试工具

  - 说明:postman是一款非常好用的测试工具,能够轻松模拟各种请求
  - 安装:下载完安装包,一路next即可。

### 原生实现

- 准备数据(放在内存)

  ```python
  posts = [
      {
          'id': 1,
          'title': 'Python基础',
          'content': '人生苦短,我用python'
      },
      {
          'id': 2,
          'title': 'HTML',
          'content': '几个标签的故事'
      }
  ]
  ```

- 获取资源列表

  ```python
  @app.route('/posts/')
  def get_posts_list():
      return jsonify({'posts': posts})
  ```

- 获取指定资源

  ```python
  @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]})
  ```

- 添加新的资源

  ```python
  @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
  ```

- 修改指定资源

  ```python
  @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]})
  ```

- 删除指定资源

  ```python
  @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': '数据已删除'})
  ```

- 错误页面定制

  ```python
  # 定制400错误显示
  @app.errorhandler(400)
  def bad_request(e):
      return jsonify({'error': 'bad request'}), 400

  # 定制404错误显示
  @app.errorhandler(404)
  def page_not_found(e):
      return jsonify({'error': 'page not found'}), 404
  ```

### flask-httpauth

- 说明:专门进行身份认证的扩展库,使用非常方便。

- 安装:`pip install flask-httpauth`

- 使用:

  ```python
  # 导入类库
  from flask_httpauth import HTTPBasicAuth

  # 创建认证对象
  auth = HTTPBasicAuth()

  # 认证的回调函数
  @auth.verify_password
  def verify_password(username, password):
      if username == 'Jerry' and password == '123456':
          return True
      return False

  # 认证错误定制
  @auth.error_handler
  def unauthorized():
      return jsonify({'error': 'Unauthorized Access'}), 403
  ```


- 保护指定路由

  ```python
  @app.route('/posts/<int:pid>', methods=['DELETE'])
  # 需要认证才能访问
  @auth.login_required
  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': '数据已删除'}) 
  ```

### flask-restful

- 说明:是一个快速实现restful api开发的扩展库,使用比较方便。

- 安装:`pip install flask-restful`

- 使用:

  ```python
  from flask_restful import Api, Resource

  # 创建资源管理对象
  api = Api()

  class UserAPI(Resource):
      # 保护类中所有的函数
      decorators = [auth.login_required]

      def get(self, uid):
          return {'User': '获取'}

      def put(self, uid):
          return {'User': '修改'}

      # 可以单独保护
      # @auth.login_required
      def delete(self, uid):
          return {'User': '删除'}

  class UserListAPI(Resource):
      def get(self):
          return {'UserList': '获取列表'}

      def post(self):
          return {'UserList': '添加资源'}

  # 添加资源
  api.add_resource(UserAPI, '/users/<int:uid>')
  # 可以添加多个路由
  api.add_resource(UserListAPI, '/users/', '/u/')
  # 若创建与初始化分开, 那么一定要将初始化放在添加资源之后
  api.init_app(app)
  ```

### 基于token的身份认证

- 说明:移动APP的身份标识,使用cookie比较麻烦,使用用户名和密码有风险,使用token比较合适。

- 使用:

  ```python
  @auth.verify_password
  def verify_password(username_or_token, password):
      if username_or_token == 'Jerry' and password == '123456':
          g.username = username_or_token
          return True
      # 再次尝试token认证
      s = Serializer(app.config['SECRET_KEY'])
      try:
          data = s.loads(username_or_token.encode('utf8'))
          g.username = data['username']
          return True
      except:
          return False

  # 生成token
  @app.route('/get_token/')
  @auth.login_required
  def generate_token():
      s = Serializer(app.config['SECRET_KEY'], expires_in=3600)
      token = s.dumps({'username': g.username})
      return jsonify({'token': token.decode('utf8'), 'expires': 3600})
  ```

  ​

 

posted @ 2019-01-04 19:17  青春叛逆者  阅读(176)  评论(0编辑  收藏  举报