Вызов флагов, поддерживающих методы ресурса 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)