使用Flask构建简单的RESTful服务

我们现在的一个项目是使用Django来构建,说来也是基于技术扩展的考虑,我对于Django里面大而全的一些组件还是持有保守态度,所以虽然项目用了Django,但是对于很多组件的使用都是尽可能少用或者不用,这样一来虽然前期清苦些,但是从现在来看,由于依赖很低,我可以匹配很多种其他的方案。

当然对我来说我格外喜欢Django的ORM方案,这个我对比了下Flask方向的ORM方案SQLAlchemy,Django的感觉要更好一些。

而在RESTful的方向上,Django自身的第三方实现rest_framework也不错,现在看起来很简单的概念和实现,用了很长一段时间才彻底理解。

而反过来看下Flask的RESTful方案,其实也有一定的借鉴意义。

Flask比Django要简练的多,我们来看一个最简单的Flask例子,比如开启一个web服务,打印出hello world

代码如下:

from flask import Flask

app = Flask(__name__)

@app.route('/')

def hello_world():

return 'Hello World!'

if __name__ == '__main__':

app.run('192.168.56.102')

最后的IP是我的服务器IP,可以根据需要替换。

使用如下的方式来运行,服务即可开启。

[root@dev01 flask]# python hello.py

* Running on http://192.168.56.102:5000/ (Press CTRL+C to quit)

192.168.56.1 - - [19/May/2018 22:29:22] "GET / HTTP/1.1" 200 -

192.168.56.1 - - [19/May/2018 22:29:22] "GET /favicon.ico HTTP/1.1" 404 -

192.168.56.1 - - [19/May/2018 22:29:22] "GET /favicon.ico HTTP/1.1" 404 -

得到的结果如下:

到了这里,如果是做过Python Web开发的同学很可能说,这不是忽悠我呢,Python自身的技术也可以实现,本身Python就实现了一个SimpleHttpServer,可以参见之前的一篇文章:如果理解Python web开发技术

里面的代码看起来更简洁:

#!/usr/bin/env python
#coding:utf-8

from wsgiref.simple_server import make_server
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '<h1>Hello, wsgi!</h1>'

if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()

我们来看看一个相对完整的Flask代码示例,内容参考了:https://www.jianshu.com/p/6ac1cab17929

代码如下:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

# by vellhe 2017/7/9

from flask import Flask, abort, request, jsonify

app = Flask(__name__)

# 测试数据暂时存放

tasks = []

@app.route('/add_task/', methods=['POST'])

def add_task():

#需要自己来维护这个列表结构

if not request.json or 'id' not in request.json or 'info' not in request.json:

abort(400)

task = {

'id': request.json['id'],

'info': request.json['info']

}

tasks.append(task)

return jsonify({'result': 'success'})

@app.route('/get_task/', methods=['GET'])

def get_task():

if not request.args or 'id' not in request.args:

# 没有指定id则返回全部

return jsonify(tasks)

else:

task_id = request.args['id']

task = filter(lambda t: t['id'] == int(task_id), tasks)

return jsonify(task) if task else jsonify({'result': 'not found'})

if __name__ == "__main__":

# 将host设置为192.168.56.102,则外网用户也可以访问到这个服务

app.run(host="192.168.56.102", port=8383, debug=True)

这个程序的一个难点就是如何在浏览器中模拟这个POST请求,当然可以使用postman来做,windows端可以参考这个链接下载:

https://app.getpostman.com/app/download/win64

第二个难点就是对于JSON的处理,里面还是有很多的参考之处。总体感觉虽然可以实现,但是所有的细节都需要自己来控制,比如输入结构,输出结构,信息查找的匹配,还有url和方法的映射。总是感觉有些拖泥带水,拖累太重,you can you up的感觉。

使用RESTful的方式,在Flask里面就是引入这个模块即可,相对来说比较简洁和轻量。

要安装flask_restful的话,一个命令即可。

pip install flask_restful

比如我有个需求,做一个基本的任务管理需求,可以分为两类功能,对任务理和任务列表管理,任务管理包括查看任务,增加,删除任务,都是对应单一的任务。任务列表就是对多个任务信息的查询和添加。

这种需求,其实基本的处理单元是任务,每一层级都可以不断的细化。尽可能对于应用层面来说更加透明,比如我就开放一个url: todos完成任务列表的管理,可以查看任务列表,添加任务信息。

todos/todo1 完成对单一任务的管理,比如添加修改,删除。

这个例子可能听起来不是很清晰,我举一个生活中的例子,比如你去一个游乐园,只有一个服务台,充值,退卡,办卡的需求都是在这一个柜台办理。这个时候需求可能是这几类:

比如你给他100块钱,那就意味着你要办卡,并且充值相应的金额(可能还要扣除工本费)

比如你给他100块钱,并且带卡,那就意味着你要充值

比如你给他一张卡,那就意味着你要退钱。

所以上述的需求,输入可能很简单,但是对应的业务场景可能截然不同。所以上述的代码要实现这个需求,逻辑还是比较复杂,而且不够清晰。

RESTful里面的一个优势就是可以基于class来构建不同的需求接口,可能对外开放的url是一个统一入口,但是可以在这个基础上进行细化。比如url: /todos和/todos/todo1

写一个程序脚本来实现:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

from flask import Flask

from flask_restful import reqparse, abort, Api, Resource

app = Flask(__name__)

api = Api(app)

TODOS = {

'todo1': {'task': 'test1'},

'todo2': {'task': 'test2'},

'todo3': {'task': 'test3'},

}

def abort_if_todo_doesnt_exist(todo_id):

if todo_id not in TODOS:

abort(404, message="Todo {} doesn't exist".format(todo_id))

parser = reqparse.RequestParser()

parser.add_argument('task')

# Todo

# shows a single todo item and lets you delete a todo item

class Todo(Resource):

def get(self, todo_id):

abort_if_todo_doesnt_exist(todo_id)

return TODOS[todo_id]

def delete(self, todo_id):

abort_if_todo_doesnt_exist(todo_id)

del TODOS[todo_id]

return '', 204

def put(self, todo_id):

args = parser.parse_args()

task = {'task': args['task']}

TODOS[todo_id] = task

return task, 201

# TodoList

# shows a list of all todos, and lets you POST to add new tasks

class TodoList(Resource):

def get(self):

return TODOS

def post(self):

args = parser.parse_args()

todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1

todo_id = 'todo%i' % todo_id

TODOS[todo_id] = {'task': args['task']}

return TODOS[todo_id], 201

##

## Actually setup the Api resource routing here

##

api.add_resource(TodoList, '/todos')

api.add_resource(Todo, '/todos/<todo_id>')

if __name__ == '__main__':

app.run('192.168.56.102',debug=True)

调用情况如下:

如果是查看某一个task的信息,可以直接输入即可匹配。

看一下代码其实会发现,这里注册了两个API,这里和上面程序的不同就在于里面使用了Resource做了封装,如果我要添加一个逻辑,其实也是很方便的。不需要堆砌一大堆的if-else

原文发布于微信公众号 - 杨建荣的学习笔记(jianrong-notes)

原文发表时间:2018-05-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Hans362 's Lab

在NuoDB上运行Asterisk

您可能已经熟悉Asterisk,一个广泛部署的开源Telephony框架。如果你不太熟悉,你应该适当了解一下。这是一个非常酷的软件。可以部署Asterisk的低...

25420
来自专栏EAWorld

微服务之服务调用与安全控制

近年来,大多数企业IT软件均在向微服务架构转型,由于微服务架构采用了更细粒度的分布式拆分,对于服务调用安全方面的问题更复杂,更需要重视,需要整体的系统化解决方案...

23330
来自专栏高性能服务器开发

(八)高性能服务器架构设计总结1——以flamigo服务器代码为例

这篇文章算是对这个系列的一个系统性地总结。我们将介绍服务器的开发,并从多个方面探究如何开发一款高性能高并发的服务器程序。

19320
来自专栏北京马哥教育

实战精华 | 搭建服务器的之后总结的一些个人经验

最近帮实验室装了两台服务器,计算用的服务器放在内网,通过一台堡垒机与外界相连。碰到很多小问题,在这里记录一下。 组建内网 这一部分没有太多好说的,堡垒机需要有两...

32840
来自专栏逸鹏说道

Web Api 入门实战 (快速入门+工具使用+不依赖IIS)

平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html 屁话我也就不多说了,...

36850
来自专栏磨磨谈

如何避免Cephfs被完全毁掉

一套系统的最低要求是可恢复,也就是数据不丢失,但是在各种各样的原因下,整套系统都有被毁掉的可能,一直以来有个观点就是存储是需要两套的,一般情况下很难实现,但是如...

31010
来自专栏CodingToDie

分布式事务解决方案

Spring Cloud 分布式事务管理 在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及...

68750
来自专栏琯琯博客

awesome-sysadmin-cn资源

系统管理员 资源列表,内容包括:备份/克隆软件、云计算/云存储、协作软件、配置管理、日志管理、监控、项目管理 备份 备份软件 Amanda:客户端-服务器模型备...

744120
来自专栏不会写文章的程序员不是好厨师

日志那些事儿——由一次bug引发的思考-client jar应该如何输出日志

前面几篇“日志那些事儿”讲解了日志的重要性和相关使用。以slf4j+logback的使用为例,我们的步骤为:

13140
来自专栏疯狂的小程序

ASP获取微信小程序的OpenID服务器端代码

尝试一下新鲜事物“微信小程序”,其中有一个业务场景,通过微信登陆小程序,这样需要获取小程序的用户ID(也就是openid)。微信小程序从安全角度考虑,不提供直接...

88780

扫码关注云+社区

领取腾讯云代金券