JSON是http请求和响应使用的传输格式, 那么Web服务就应该实现以下两个功能:
- 把资源转换成json数据——发送给客户端
- 把json数据转换成资源——把客户端发送过来的json数据转换成资源存储在数据库中
一. 把资源转换成json数据
1) app/models.py class Post(db.Model): #... def to_json(self): json_post = { 'url': url_for('api.get_post', id = self.id, _external=True), 'body': self.body, 'body_html': self.body_html, 'timestamp': self.timestamp, 'author': url_for('api.get_user', id=self.author_id, _external=True), 'comments': url_for('api.get_post_comments', self.id, _external=True), 'comment_count': self.comments.count() } return json_post #_external参数是为了生成完整的url, 在客户端只能使用完整的url #上面的代码还说明了生成json数据时可以使用虚构的属性(ps:comment_count) class User(db.Model): #... def to_json(self): json_user = { 'url': url_for('api.get_user', id=self.id, _external=True), 'username': self.username, 'member_since': self.member_since, 'last_seen': self.last_seen, 'posts': url_for('api.get_user_posts', self.id, _external=True), 'followed_posts': url_for('api.get_user_followed_posts', self.id, _external=True), 'post_count': self.posts.count() } return json_user #为了保护隐私, 用户的某些属性没有加入响应, 比如email和role等 #这说明提供给客户端的资源没有必要和数据库模型内部完全一致
二. 把json转换成资源
1)app/models.py
from app.exceptions import ValidationError class Post(db.Model): #... @staticmethod def from_json(json_post): body = json_post.get('body') if body is None or body == '': raise ValidationError('post dose not have a body') return Post(body=body) #我们创建Post实例时只用了json中的body字段 #不需要body_html字段, because我们之前为数据库的Post表的body字段设置了事件监听, 一旦实例的body属性被修改就会自动修改body_html #不需要timestamp字段, because timestamp有默认值, 即创建时间 #不需要author, because author的值不是客户端确定的, author的值是通过认证的用户 #不需要url, because url的值也不是客户端确定的, 是数据库分配id后决定的
当body值不存在的时候, 引发ValidationError, 由调用函数的上层函数处理这个错误。
为了不再视图函数中捕获该错误, 我们在api蓝本全局中处理该错误:
2) app/api__1_0/errors.py
@api.errorhandler(ValidationError) der validation_error(e): return bad_request(e.args[0]) #只要在api注册的路由中遇到ValidationError的错误, 就会由该函数处理返回响应。
这样的话视图函数就会简洁一些:
3)app/api_1_0/posts.py
@api.route('/posts', method=['POST']) def new_post(): post = Post.from_json(request.json) post.author = g.current_user db.session.add(post) db.session.commit() return jsonify(post.to_json()) #当用户编辑完文章点击提交按钮时, 客户端对文章内容进行json编码, 并把内容提交到响应url #由于该url是api注册的, 要先进行认证, 认证通过后, g.current_user存储当前用户 #执行该视图函数, 先从请求对象中获取json_post, 转换成资源post #post.author就是g.current_user