HTTP GET API 使用相同端点但在 Flask 中使用请求参数提供过滤结果的设计

HTTP GET API Design which uses same endpoint but with provides filtered results with request parameters in Flask

我正在使用 flask-restplus 创建一个 RESTful API,它连接到 MongoDB 集合并根据调用的 API 提供信息。

API 设计

HTTP 获取

api/hashdoc/<str:product_id>

功能: 为数据库中给定的product_id提供所有list的相关信息。

示例响应:

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

HTTP 获取

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

函数应该提供JSON使用from和[=22=过滤信息的响应] 数据库中的值

示例响应:


   {
    "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?是否需要单独实施它们?

是否必须检查 fromto 是否不在同一资源 None 中 class 然后执行查询?

The Flask app still queries the api/hashdoc/ABC and provides me the list and not the filtered document here.

您使用相同的路由 url 创建了两个资源 类。所以它使用它首先看到的那个(在你的例子中是 HashDocListResource)。

How does one manage such API with request parameters? Does one need to implement them separately?

不,您不会为查询参数创建单独的资源类。

Does one have to perform a check if the from and to are not None in the same resource class and then perform the query?

是的。

我不确定为什么您在 HashDocListResource 中使用 find 而在 HashDocResource 中使用 find_one。是不是给定时间范围内只能有一个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.'})