Python Falcon - 后缀响应器



为了理解后缀响应器的概念和必要性,让我们定义一个StudentResource类。它包含一个on_get()响应器,该响应器将学生列表(dict对象)转换为JSON并作为响应返回。

让我们再添加一个on_post()响应器,它读取来自传入请求的数据,并在列表中添加一个新的dict对象。

import falcon
import json
from waitress import serve
students = [
   {"id": 1, "name": "Ravi", "percent": 75.50},
   {"id": 2, "name": "Mona", "percent": 80.00},
   {"id": 3, "name": "Mathews", "percent": 65.25},
]
class StudentResource:
   def on_get(self, req, resp):
      resp.text = json.dumps(students)
      resp.status = falcon.HTTP_OK
      resp.content_type = falcon.MEDIA_JSON
   def on_post(self, req, resp):
      student = json.load(req.bounded_stream)
      students.append(student)
      resp.text = "Student added successfully."
      resp.status = falcon.HTTP_OK
      resp.content_type = falcon.MEDIA_TEXT

使用Falcon的App对象的add_route()函数,我们添加了/students路由。

app = falcon.App()
app.add_route("/students", StudentResource())

启动服务器后,我们可以从HTTPie命令行测试GET和POST请求。

http GET localhost:8000/students
HTTP/1.1 200 OK
Content-Length: 187
Content-Type: application/json
Date: Mon, 18 Apr 2022 06:21:02 GMT
Server: waitress
[
   {
      "id": 1,
      "name": "Ravi",
      "percent": 75.5
   },
   {
      "id": 2,
      "name": "Mona",
      "percent": 80.0
   },
   {
      "id": 3,
      "name": "Mathews",
      "percent": 65.25
   }
]
http POST localhost:8000/students id=4 name="Prachi"
percent=59.90
HTTP/1.1 200 OK
Content-Length: 27
Content-Type: text/plain; charset=utf-8
Date: Mon, 18 Apr 2022 06:20:51 GMT
Server: waitress
Student added successfully.

再次调用on_get()确认了新学生资源的添加。

http GET localhost:8000/students
HTTP/1.1 200 OK
Content-Length: 187
Content-Type: application/json
Date: Mon, 18 Apr 2022 06:21:02 GMT
Server: waitress
[
   {
      "id": 1,
      "name": "Ravi",
      "percent": 75.5
   },
   {
      "id": 2,
      "name": "Mona",
      "percent": 80.0
   },
   {
      "id": 3,
      "name": "Mathews",
      "percent": 65.25
   },
   {
      "id": "4",
      "name": "Prachi",
      "percent": "59.90"
   }
]

在此阶段,我们希望在StudentResource类中有一个GET响应器方法,该方法从URL中读取id参数并检索列表中相应的dict对象。

换句话说,格式为/student/{id}的URL应该与资源类中的GET方法关联。但显然,一个类不能有两个同名的方法。因此,我们定义使用add_route()方法的suffix参数来区分on_get()响应器的两个定义。

通过指定suffix ='student',将带有id参数的路由添加到Application对象。

app.add_route("/students/{id:int}", StudentResource(), suffix='student')

现在,我们可以使用此后缀添加另一个on_get()方法的定义,以便此响应器的名称为on_get_student(),如下所示:

def on_get_student(self, req, resp, id):
   resp.text = json.dumps(students[id-1])
   resp.status = falcon.HTTP_OK
   resp.content_type = falcon.MEDIA_JSON

添加新路由和on_get_student()响应器后,启动Waitress服务器并测试以下URL:

http GET localhost:8000/students/2
HTTP/1.1 200 OK
Content-Length: 42
Content-Type: application/json
Date: Mon, 18 Apr 2022 06:21:05 GMTy
Server: waitress
{
   "id": 2,
   "name": "Mona",
   "percent": 80.0
}

请注意,当客户端使用适当的请求头请求URL路由/students/{id:int}时,on_put()响应器(更新资源)和on_delete()响应器(删除资源)也将被调用。

我们已经使用student作为后缀添加了此路由。因此,on_put_student()方法将路径参数解析为一个整型变量。获取给定id的项目的JSON表示形式,并使用PUT请求中提供的数据进行更新。

def on_put_student(self, req, resp, id):
   student=students[id-1]
   data = json.load(req.bounded_stream)

   student.update(data)
   resp.text = json.dumps(student)
   resp.status = falcon.HTTP_OK
   resp.content_type = falcon.MEDIA_JSON

on_delete_student()响应器仅删除DELETE请求中指定的id对应的项目。返回剩余资源的列表。

def on_delete_student(self, req, resp, id):
   students.pop(id-1)
   resp.text = json.dumps(students)
   resp.status = falcon.HTTP_OK
   resp.content_type = falcon.MEDIA_JSON

我们可以使用HTTPie命令测试API的PUT和DELETE操作:

http PUT localhost:8000/students/2 id=3 name="Mathews"
percent=55
HTTP/1.1 200 OK
Content-Length: 46
Content-Type: application/json
Date: Sat, 18 Apr 2022 10:13:00 GMT
Server: waitress
{
   "id": "3",
   "name": "Mathews",
   "percent": "55"
}
http DELETE localhost:8000/students/2
HTTP/1.1 200 OK
Content-Length: 92
Content-Type: application/json
Date: Sat, 18 Apr 2022 10:18:00 GMT
Server: waitress
[
   {
      "id": 1,
      "name": "Ravi",
      "percent": 75.5
   },
   {
      "id": 3,
      "name": "Mathews",
      "percent": 65.25
   }
]

此API(studentapi.py)的完整代码如下:

import falcon
import json
from waitress import serve
students = [
   {"id": 1, "name": "Ravi", "percent": 75.50},
   {"id": 2, "name": "Mona", "percent": 80.00},
   {"id": 3, "name": "Mathews", "percent": 65.25},
]
class StudentResource:
   def on_get(self, req, resp):
      resp.text = json.dumps(students)
      resp.status = falcon.HTTP_OK
      resp.content_type = falcon.MEDIA_JSON
   def on_post(self, req, resp):
      student = json.load(req.bounded_stream)
      students.append(student)
      resp.text = "Student added successfully."
      resp.status = falcon.HTTP_OK
      resp.content_type = falcon.MEDIA_TEXT
   def on_get_student(self, req, resp, id):
      resp.text = json.dumps(students[id-1])
      resp.status = falcon.HTTP_OK
      resp.content_type = falcon.MEDIA_JSON
   def on_put_student(self, req, resp, id):
      student=students[id-1]
      data = json.load(req.bounded_stream)

      student.update(data)

      resp.text = json.dumps(student)
      resp.status = falcon.HTTP_OK
      resp.content_type = falcon.MEDIA_JSON
   def on_delete_student(self, req, resp, id):
      students.pop(id-1)
      print (students)
      resp.text = json.dumps(students)
      resp.status = falcon.HTTP_OK
      resp.content_type = falcon.MEDIA_JSON
app = falcon.App()
app.add_route("/students", StudentResource())
app.add_route("/students/{id:int}", StudentResource(), suffix='student')
if __name__ == '__main__':
   serve(app, host='0.0.0.0', port=8000)
广告