使用 Python 和 Flask 设计 RESTful API

本文转载自设计RESTful
但是本文对其中的几个错误进行修改
且原博中用curl来测试,本文中使用postman测试

任务

请搭建一个web服务器,编写以下API:

  • 添加一条新的待办事项。
  • 将一条待办事项设置为已完成。
  • 查看所有事项。
  • 删除一条事项。

一条事项至少需要以下几种属性:

  • 事项id
  • 事项内容
  • 事项完成状态
  • 事项添加时间
  • 事项截止时间

要求:

  • 设置合理的路径,能从路径看出所实现的功能。
  • 接口尽量满足RESTful API规范。
  • 返回数据使用JSON格式。

基础

我们 web service 的客户端需要添加、删除以及修改任务的服务,因此显然我们需要一种方式来存储任务。最直接的方式就是建立一个小型的数据库,但是数据库并不是本文的主体。学习在 Flask 中使用合适的数据库,我强烈建议阅读 Mega-Tutorial。

这里我们直接把任务列表存储在内存中,因此这些任务列表只会在 web 服务器运行中工作,在结束的时候就失效。 这种方式只是适用我们自己开发的 web 服务器,不适用于生产环境的 web 服务器, 这种情况一个合适的数据库的搭建是必须的。

from flask import Flask, jsonify

app = Flask(__name__)

tasks = [
    {
        'id': 1,
        'title': u'Buy groceries',
        'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
        'done': False
    },
    {
        'id': 2,
        'title': u'Learn Python',
        'description': u'Need to find a good Python tutorial on the web',
        'done': False
    }
]

if __name__ == '__main__':
    app.run(debug=True)

正如你所见,没有多大的变化。我们创建一个任务的内存数据库,这里无非就是一个字典和数组。数组中的每一个元素都具有上述定义的任务的属性。

查看所有事项。

我们现在来实现 web service 的第一个入口:

@app.route('/todo/api/v1.0/tasks', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})

我们现在拥有一个 get_tasks 的函数,访问的 URI 为 /todo/api/v1.0/tasks,并且只允许 GET 的 HTTP 方法。

这个函数的响应不是文本,我们使用 JSON 数据格式来响应,Flask 的 jsonify 函数从我们的数据结构中生成。

使用网页浏览器来测试我们的 web service 不是一个最好的注意,因为网页浏览器上不能轻易地模拟所有的 HTTP 请求的方法。我们使用postman来模拟。
在这里插入图片描述
我们已经成功地调用我们的 RESTful service 的一个函数!

添加一条新的待办事项。

接下来就是 POST 方法,我们用来在我们的任务数据库中插入一个新的任务:

from flask import request

@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
    if not request.json or not 'title' in request.json or\
            not 'add_time' in request.json or not 'end_time' in request.json:
        abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'done': False,
        'add_time': request.json['add_time'],
        'end_time': request.json['end_time']
    }
    tasks.append(task)
    return jsonify({'task': task}), 201

添加一个新的任务也是相当容易地。只有当请求以 JSON 格式形式,request.json 才会有请求的数据。如果没有数据,或者存在数据但是缺少 title/end_time/add_time 项,我们将会返回 400,这是表示请求无效。

接着我们会创建一个新的任务字典,使用最后一个任务的 id + 1 作为该任务的 id。我们假设 done 字段设置成 False。

我们把新的任务添加到我们的任务数组中,并且把新添加的任务和状态 201 响应给客户端。
在postman中使用如下命令来测试这个新的函数:
在这里插入图片描述
当然在完成这个请求后,我们可以得到任务的更新列表:

将一条待办事项设置为已完成。(原博中就是这项中有个小问题)

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
#原博中直接task = filter(lambda t: t['id'] == task_id, tasks)
#这样子是不行的,因为我们需要的是list类型
#所以此处的修改是用list函数修饰
    task = list(filter(lambda t: t['id'] == task_id, tasks))
    if len(task) == 0:
        abort(404)
    if not request.json:
        abort(400)
    if 'done' in request.json and type(request.json['done']) is not bool:
        abort(400)
    task[0]['title'] = request.json.get('title', task[0]['title'])
    task[0]['add_time'] = request.json.get('add_time', task[0]['add_time'])
    task[0]['end_time'] = request.json.get('end_time', task[0]['end_time'])
    task[0]['done'] = request.json.get('done', task[0]['done'])
    return jsonify({'task': task[0]})

对于 update_task 函数,我们需要严格地检查输入的参数以防止可能的问题。我们需要确保在我们把它更新到数据库之前,任何客户端提供我们的是预期的格式。

删除一条事项。

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    task = list(filter(lambda t: t['id'] == task_id, tasks))
    if len(task) == 0:
        abort(404)
    tasks.remove(task[0])
    return jsonify({'result': True})

全部代码

from flask import Flask, jsonify
from flask import abort
from flask import make_response
from flask import request
app = Flask(__name__)

tasks = [
    {
        'id': 1,
        'title': u'Buy groceries',
        'done': False,
        'add_time': '2021.02.28 21:00',
        'end_time': '2021.02.28 24:00'
    },
    {
        'id': 2,
        'title': u'Learn Python',
        'done': False,
        'add_time': '2021.02.28 08:00',
        'end_time': '2021.02.28 24:00'
    }
]
#查看所有事项
@app.route('/todo/api/v1.0/tasks', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})


#添加一条新的代办事项
@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
    if not request.json or not 'title' in request.json or\
            not 'add_time' in request.json or not 'end_time' in request.json:
        abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'done': False,
        'add_time': request.json['add_time'],
        'end_time': request.json['end_time']
    }
    tasks.append(task)
    return jsonify({'task': task}), 201
#将一条待办事项设置为已完成
@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
    task = list(filter(lambda t: t['id'] == task_id, tasks))
    if len(task) == 0:
        abort(404)
    if not request.json:
        abort(400)
    if 'done' in request.json and type(request.json['done']) is not bool:
        abort(400)
    task[0]['title'] = request.json.get('title', task[0]['title'])
    task[0]['add_time'] = request.json.get('add_time', task[0]['add_time'])
    task[0]['end_time'] = request.json.get('end_time', task[0]['end_time'])
    task[0]['done'] = request.json.get('done', task[0]['done'])
    return jsonify({'task': task[0]})
#删除一条事项
@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    task = list(filter(lambda t: t['id'] == task_id, tasks))
    if len(task) == 0:
        abort(404)
    tasks.remove(task[0])
    return jsonify({'result': True})

if __name__ == '__main__':
    app.run(debug=True)

本次分享到此结束,喜欢的记得点赞收藏。
如有错误请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值