美文网首页APIpython
Python API工程:使用Flask开发REST API

Python API工程:使用Flask开发REST API

作者: simoncos | 来源:发表于2016-09-10 20:21 被阅读899次
    Flask

    注:更多关于API设计及部署等内容,可见:Python API工程:REST API、WSGI部署、环境与代码管理

    因工作需要,尝试了使用Flask将一个Python数据分析类项目服务化为REST API。下面将以一个玩具项目的形式分享我目前所掌握的内容。

    需求描述

    • 需求1:访问http://localhost:5000/ ,返回"Hello, World!"
    • 需求2:给出一段文本,输出其经过结巴分词进行分词后的结果。具体需实现如下两种输入输出类型:
      • 需求2.1:通过URL将文本以参数的类型传入,并以str类型返回分出的词及词数
        输入: http://localhost:5000/cut/para/我们中出了一个叛徒/
        输出:包含分出的词和词数的str

      • 需求2.2 通过POST请求,以JSON类型传入文本,并以JSON类型返回分出的词及词数
        输入: 将JSON类型的文本{"content": "我们中出了一个叛徒"}
        POST至http://localhost:5000/cut/json/
        输出:包含分出的词和词数的JSON

    代码实现

    新建一个toy.py写入下面所有代码。

    
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import jieba
    from flask import Flask, request, jsonify
    import requests, json
    
    # business logic part
    
    def cut(content):
        word_list = jieba.lcut(content)
        word_num = len(word_list)
        word_str = ",".join(word_list)
        return word_str, word_num
    
    # flask part
    
    toy = Flask(__name__) # create a Flask instance
    
    @toy.route("/")
    def index():
        return "Hello, World!"
    
    # <string:content>定义输入的内容的类型及变量名,注意":"左右不能有空格,
    @toy.route("/cut/para/<string:content>")
    def paraCut(content):
        word_str, word_num = cut(content)
        return "words: {}; number of words: {}".format(word_str, word_num)
    
    @toy.route("/cut/json/", methods=["POST"]) # methods可以是多个
    def jsonCut():
        if request.method == "POST":
            # 从request请求中提取json内容
            json_dict = request.get_json()
            content = json_dict["content"]
            # 运行业务逻辑
            word_str, word_num = cut(content)
            # 将结果格式化为dict
            data = {"word_str": word_str, "word_num": word_num}
            return json.dumps(data) # 将data序列化为json类型的str    
        else:
            return """<html><body>
            Something went horribly wrong
            </body></html>"""
    
    @toy.route("/test/post/")
    def postTest():
        # 生成一个request请求,其中包含了请求对象、要处理的数据、数据类型
        url = "http://localhost:5000/cut/json/"
        data = {"content": "我们中出了一个叛徒"}
        headers = {"Content-Type" : "application/json"}
        # 使用python自带的requests post方法发送请求
        r = requests.post(url, data=json.dumps(data), headers=headers)
        return r.text
    
    if __name__ == "__main__":
        toy.run(debug=True)
    
    

    运行测试

    测试部分我将基于Ubuntu的terminal环境进行说明,Windows或其他环境下操作可能会有不同。
    首先需要运行业务和测试服务。cd到你放toy.py的目录,接着打开两个terminal,使用本机的5000和5001端口各运行一个toy.py,命令如下:

    # Terminal 1(用于运行API服务)
    $ export FLASK_APP=toy.py
    $ export FLASK_DEBUG=True # 打开debug模式,建议打开
    $ flask run --port=5000 # 设置服务使用的端口并运行
    
    # Terminal 2(用于发送测试请求)
    $ export FLASK_APP=toy.py
    $ export FLASK_DEBUG=True 
    $ flask run --port=5001
    
    测试需求1

    使用浏览器访问:http://localhost:5000/
    页面上将显示:

    Hello, World!
    
    测试需求2.1

    使用浏览器访问:http://localhost:5000/cut/para/我们中出了一个叛徒/
    页面上将显示:

    words: 我们,中出,了,一个,叛徒; number of words: 5
    
    测试需求2.2

    使用浏览器访问:http://localhost:5001/test/post/
    页面上将显示:

    {"word_num": 5, "word_str": "\u6211\u4eec,\u4e2d\u51fa,\u4e86,\u4e00\u4e2a,\u53db\u5f92"} 
    

    {"word_num": 5, "word_str": "我们,中出,了,一个,叛徒"}
    

    注:\uXXXX是UTF8的编码,出现不同的输出结果与浏览器和OS的编码解析设置有关。

    一些补充和看法

    • 发送到两个服务的HTTP请求,其状态都可以在terminal中即时看到;

    • 如果希望从其他机器上发送请求来进行测试,可以在运行2个服务的时候,在命令行中设置host参数为0.0.0.0(格式如下),使服务公开可见(请注意安全性)。然后将url中的localhost替换为你的IP地址即可;

      flask run --port=5001 --host=0.0.0.0
      
    • 可以看到Flask代码和业务逻辑是分离的,这种低耦合使Python的REST API开发和测试都非常容易;

    • 虽然在这样一个玩具项目中无法体现,但相比较而言,JSON类型的输入比字符串更适应于逻辑复杂的需求。对非技术人员来说,测试前者要麻烦一些,但也能使用一些RESTClient的GUI;

    相关文章

      网友评论

        本文标题:Python API工程:使用Flask开发REST API

        本文链接:https://www.haomeiwen.com/subject/idvyettx.html