Вызов флагов, поддерживающих методы ресурса API

Я создаю API с Flask, который используется для мобильной платформы, но я также хочу, чтобы приложение само переваривало API, чтобы отображать веб-контент. Мне интересно, что лучший способ получить доступ к API-ресурсам внутри Flask? Например, если у меня есть следующий класс, добавленный в качестве ресурса:

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

Как получить возвращаемое значение post() из FooAPI? Могу ли я сделать это через переменную api? Или мне нужно создать экземпляр FooAPI в контроллере? Кажется, должен быть простой способ сделать это, что я просто не понимаю...

Ответы

Ответ 1

Очевидным способом использования вашего приложения API является его вызов, как и любой другой клиент. Тот факт, что приложение будет действовать как сервер и клиент одновременно, не имеет значения, клиентская часть может размещать запросы в localhost, а часть сервера будет получать их так же, как и внешние запросы. Для генерации HTTP-запросов вы можете использовать requests или urllib2 из стандартной библиотеки.

Но в то время как вышеупомянутый метод будет работать отлично, мне кажется, что это слишком сложно. На мой взгляд, лучший подход заключается в том, чтобы разоблачить общую функциональность вашего приложения таким образом, что и обычное приложение, и API могут вызывать. Например, у вас может быть пакет с именем FooLib, который реализует всю общую логику, тогда FooAPI становится тонкой оболочкой вокруг FooLib, и оба FooAPI и FooApp вызывают FooLib, чтобы все было сделано.

Ответ 2

Мне удалось добиться этого, иногда API становится уродливым, в моем случае мне нужно рекурсивно вызывать функцию, поскольку приложение имеет чрезвычайно рекурсивный характер (дерево). Рекурсивные функции сами по себе довольно дороги, рекурсивные HTTP-запросы были бы миром памяти и потери процессора.

Итак, вот фрагмент, проверьте третий цикл:

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 } )

Ответ 3

Другой подход заключается в том, чтобы приложение и 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 является глобальным. Например, для ресурса приложения, который обрабатывает загрузку файла, вы можете просто вызвать:

@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)