16

我正在使用 Flask 创建一个用于移动平台的 API,但我也希望应用程序本身消化 API 以呈现 Web 内容。我想知道在 Flask 中访问 API 资源方法的最佳方法是什么?例如,如果我将以下类添加为资源:

class FooAPI(Resource):
    def __init__(self):
        # Do some things
        super(FooAPI, self).__init__()
    def post(self, id):
        #return something
    def get(self):
        #return something

api = Api(app)
api.add_resource(FooAPI, '/api/foo', endpoint = 'foo')

然后在我想要的控制器中:

@app.route("/bar")
def bar():
   #Get return value from post() in FooAPI

如何从 FooAPI 获取 post() 的返回值?我可以通过 api 变量以某种方式做到这一点吗?还是我必须在控制器中创建一个 FooAPI 实例?似乎必须有一种简单的方法来做到这一点,我只是不明白......

4

3 回答 3

14

应用程序使用 API 的明显方式是像任何其他客户端一样调用它。应用程序同时充当服务器和客户端这一事实并不重要,客户端部分可以将请求放入localhost,服务器部分将以与获取外部请求相同的方式获取它们。要生成 HTTP 请求,您可以使用requests或标准库中的 urllib2。

但是,虽然上述方法可以正常工作,但对我来说似乎有点过分了。在我看来,更好的方法是以常规应用程序和 API 都可以调用的方式公开应用程序的通用功能。例如,您可以有一个名为的包FooLib,它实现所有共享逻辑,然后FooAPI成为一个瘦包装器,并调用FooLib两者来完成任务。FooAPIFooAppFooLib

于 2013-11-24T05:29:28.417 回答
5

另一种方法是将应用程序和 API 放在同一个 Flask(-RESTful) 实例中。然后,您可以让应用程序在内部调用 API 方法/函数(不使用 HTTP)。让我们考虑一个管理服务器上文件的简单应用程序:

# API. Returns filename/filesize-pairs of all files in 'path'  
@app.route('/api/files/',methods=['GET'])
def get_files():
    files=[{'name':x,'size':sys.getsizeof(os.path.join(path,x))} for x in os.listdir(path)]
    return jsonify(files)

# app. Gets all files from the API, uses the API data to render a template for the user 
@app.route('/app/files/',methods=['GET'])
def app_get_files():
    response=get_files() # you may verify the status code here before continuing  
    return render_template('files.html',files=response.get_json())

您可以推送所有请求(从 API 到应用程序并返回),而无需将它们包含在您的函数调用中,因为 Flask 的请求对象是global。例如,对于处理文件上传的应用程序资源,您可以简单地调用:

@app.route('/app/files/post',methods=['POST'])
def app_post_file():
   response=post_file()
   flash('Your file was uploaded succesfully') # if status_code==200
   return render_template('home.html')

相关的 API 资源是:

@app.route('/api/files/',methods=['POST'])
def post_file():
   file=request.files['file']
   ....
   ....
   return jsonify({'some info about the file upload'})

但是,对于大量应用程序数据,包装/解包 JSON 的开销使得 Miguel 的第二个解决方案更受欢迎。

在你的情况下,你会想在你的控制器中调用它:

response=FooAPI().post(id)
于 2019-05-04T06:58:51.470 回答
1

我设法实现了这一点,有时 API 变得丑陋,就我而言,我需要递归调用该函数,因为应用程序具有极其递归的性质(一棵树)。递归函数本身非常昂贵,递归 HTTP 请求将是一个内存和 cpu 浪费的世界。

所以这里是片段,检查第三个 for 循环:

class IntentAPI(Resource):
    def get(self, id):
        patterns = [pattern.dict() for pattern in Pattern.query.filter(Pattern.intent_id == id)]
        responses = [response.dict() for response in Response.query.filter(Response.intent_id == id)]
        return jsonify ( { 'patterns' : patterns, 'responses' : responses } )

    def delete(self, id):
        for pattern in Pattern.query.filter(Pattern.intent_id == id):
            db.session.delete(pattern)

        for response in Response.query.filter(Response.intent_id == id):
            db.session.delete(response)

        for intent in Intent.query.filter(Intent.context == Intent.query.get(id).set_context):
            self.delete(intent.id) #or IntentAPI.delete(self, intent.id)

        db.session.delete(Intent.query.get(id))
        db.session.commit()
        return jsonify( { 'result': True } )
于 2017-10-04T02:53:35.247 回答