HTTP GET API Design, который использует ту же конечную точку, но предоставляет отфильтрованные результаты с параметрами запроса во Flask - PullRequest
0 голосов
/ 12 ноября 2019

Я использую flask-restplus для создания RESTful API, который подключается к коллекции MongoDB и предоставляет информацию в соответствии с вызываемым API.

API Design

HTTP GET

api/hashdoc/<str:product_id>

функция : предоставляет все list соответствующей информации для данного product_id в базе данных.

пример ответа :

[
  {
    "product_id": "ABC",
    "metadata": {
        ...
    },
    "time_info": {
       ....
    }
  },
  {
    "product_id": "ABC",
    "metadata": {
       ...
    },
    "time_info": {
        ...
     }
  }
]

HTTP GET

api/hashdoc/<str:product_id>?from=<str:ISO8601_timestamp>&to=<str:ISO8601_timestamp>

function : Должен Предоставить JSONответ информации, отфильтрованной с использованием значений from и to в базе данных

пример ответа :


   {
    "product_id": "ABC",
    "metadata": {
     ...
    },
    "time_info": {
        ...
    }
   }

Текущая реализация

В моемhashdoc.py У меня есть следующий код:


from flask import request, abort
from flask_restplus import Namespace, Resource, fields, reqparse
from databases.documentdb import mongo

# API
api = Namespace('hashdoc', description='Hash Document Operations')


# REQUEST PARSER HERE
event_duration_parser = reqparse.RequestParser()

event_duration_parser.add_argument('from', type=str, required=True, help='ISO8601 UTC Timestamp (ms precision)')
event_duration_parser.add_argument('to', type=str, required=True, help='ISO8601 UTC Timestamp (ms precision)')

## hash_doc = api.model(....) removed for brewity

@api.route('/<product_id>')
@api.param('product_id', 'EPC Product ID')
@api.response(404, 'No Values Exist for given Product ID.')
class HashDocListResource(Resource):
    @api.marshal_list_with(hash_doc)
    def get(self, product_id):
        '''Fetch Hash Documents for given Product ID'''
        print(product_id)
        product_hash_doc = mongo.db['HashData'].find({'product_id': product_id}, {'_id': 0})
        list_product_hashdoc = list(product_hash_doc)
        if len(list_product_hashdoc):
            return list_product_hashdoc, 200
        else:
            abort(404, {'error': 'No Values Exist for given Product ID.'})


@api.route('/<product_id>')
@api.param('product_id', 'EPC Product ID')
@api.response(404, 'No Values Exist for given Product ID & Time Range')
class HashDocResource(Resource):
    @api.expect(event_duration_parser)
    @api.marshal_with(hash_doc)
    def get(self, product_id):
        args = event_duration_parser.parse_args()
        from_time = args.get('from')
        to_time = args.get('to')

        product_hash_doc_for_time_range = mongo.db['HashData'].find_one(
                        {'product_id': product_id, 
                         # Filtering based on TIMESTAMPS HERE
                        {'_id': 0})

        if product_hash_doc_for_time_range:
            return product_hash_doc_for_time_range, 200
        else:
            abort(404, 'No Values Exist for given Product ID & Time Range')

Тесты

с curl Я выполняю следующее:

curl -XGET http://localhost:5000/api/hashdoc/ABC

, что дает мне listхеш документов и поведение корректное. Однако, когда я делаю следующее:

curl -XGET http://localhost:5000/api/hashdoc/ABC?from\="2019-11-05T14:32:31.830000Z"\&to\="2019-11-05T14:46:00.444000Z"

Приложение Flask по-прежнему запрашивает api/hashdoc/ABC и предоставляет мне список, а не отфильтрованный документ.

Как управлять таким API с помощьюпараметры запроса? Нужно ли реализовывать их отдельно?

Нужно ли выполнять проверку, если from и to не являются None в одном классе ресурсов, а затем выполнить запрос?

1 Ответ

1 голос
/ 12 ноября 2019

Приложение Flask по-прежнему запрашивает api / hashdoc / ABC и предоставляет мне список, а не отфильтрованный документ.

Вы создали два класса ресурсов с одинаковым URL-адресом маршрута. Таким образом, он использует тот, который видит первым (в вашем случае это HashDocListResource).

Как можно управлять таким API с параметрами запроса? Нужно ли реализовывать их отдельно?

Нет, вы не создаете отдельные классы ресурсов только для параметров запроса.

Нужно ли выполнять проверку, еслиfrom и to не являются None в одном классе ресурсов и затем выполняют запрос?

Да.

Я не уверен, почему вы используете find в HashDocListResource, но find_one в HashDocResource. Неужели в данном временном диапазоне может быть только один HashDoc?

Пример того же самого.

from flask import request, abort
from flask_restplus import Namespace, Resource, fields, reqparse
from databases.documentdb import mongo

# API
api = Namespace('hashdoc', description='Hash Document Operations')


# REQUEST PARSER HERE
event_duration_parser = reqparse.RequestParser()

event_duration_parser.add_argument('from', type=str, required=True, help='ISO8601 UTC Timestamp (ms precision)')
event_duration_parser.add_argument('to', type=str, required=True, help='ISO8601 UTC Timestamp (ms precision)')

## hash_doc = api.model(....) removed for brewity

@api.route('/<product_id>')
@api.param('product_id', 'EPC Product ID')
@api.response(404, 'No Values Exist for given Product ID.')
class HashDocListResource(Resource):
    @api.expect(event_duration_parser)
    @api.marshal_list_with(hash_doc)
    def get(self, product_id):
        '''Fetch Hash Documents for given Product ID'''
        args = event_duration_parser.parse_args()
        from_time = args.get('from')
        to_time = args.get('to')

        query = {
            'product_id': product_id,
        }
        if from_time and to_time:
            query['your_time_stamp_field'] = {
                '$lte': to_time
            }
            query['your_time_stamp_field'] = {
                '$gte': from_time
            }
        projection = {'_id': 0}
        product_hash_docs = mongo.db['HashData'].find(query, projection)
        list_product_hashdoc = list(product_hash_docs)
        if len(list_product_hashdoc):
            return list_product_hashdoc, 200
        else:
            abort(404, {'error': 'No Values Exist for given Product ID.'})

...