[英]Flask RESTful API multiple and complex endpoints
在我的Flask-RESTful API中,假设我有两个对象,用户和城市。 这是1对多的关系。 现在,当我创建API并向其添加资源时,我似乎只能将非常简单的常规URL映射到它们。 这是代码(没有包含无用的东西):
class UserAPI(Resource): # The API class that handles a single user
def __init__(self):
# Initialize
def get(self, id):
# GET requests
def put(self, id):
# PUT requests
def delete(self, id):
# DELETE requests
class UserListAPI(Resource): # The API class that handles the whole group of Users
def __init__(self):
def get(self):
def post(self):
api.add_resource(UserAPI, '/api/user/<int:id>', endpoint='user')
api.add_resource(UserListAPI, '/api/users/', endpoint='users')
class CityAPI(Resource):
def __init__(self):
def get(self, id):
def put(self, id):
def delete(self, id):
class CityListAPI(Resource):
def __init__(self):
def get(self):
def post(self):
api.add_resource(CityListAPI, '/api/cities/', endpoint='cities')
api.add_resource(CityAPI, '/api/city/<int:id>', endpoint='city')
如您所见,我可以做我想要实现的所有基本功能。 我可以获取,发布,放置和删除这两个对象。 但是,我的目标是双重的:
(1)能够请求城市名称等其他参数,而不仅仅是城市ID。 它看起来像:
api.add_resource(CityAPI, '/api/city/<string:name>', endpoint='city')
除了它不会给我这个错误:
AssertionError:视图函数映射正在覆盖现有的端点函数
(2)能够在请求中组合两个资源。 假设我想让所有用户与某个城市相关联。 在REST URL中,它应该类似于:
/api/cities/<int:id>/users
我如何使用Flask做到这一点? 我将它映射到哪个端点?
基本上,我正在寻找将API从基本应用到可用的方法。 感谢您的任何想法/建议
你犯了两个错误。
首先,Flask-RESTful会让您认为资源是使用单个URL实现的。 实际上,您可以使用许多不同的URL来返回相同类型的资源。 在Flask-RESTful中,您需要为每个URL创建不同的Resource
子类,但从概念上讲,这些URL属于同一资源。 请注意,事实上,您已经为每个资源创建了两个实例来处理列表和各个请求。
您所犯的第二个错误是您希望客户端知道API中的所有网址。 这不是构建API的好方法,理想情况下,客户端只知道一些顶级URL,然后从顶级URL的响应中发现其余的数据。
在您的API中,您可能希望将/api/users
和/api/cities
作为顶级API公开。 各个城市和用户的网址将包含在回复中。 例如,如果我调用http://example.com/api/users
获取用户列表,我可能会收到此响应:
{
"users": [
{
"url": "http://example.com/api/user/1",
"name": "John Smith",
"city": "http://example.com/api/city/35"
},
{
"url": "http://example.com/api/user/2",
"name": "Susan Jones",
"city": "http://example.com/api/city/2"
}
]
}
请注意,用户的JSON表示包括该用户的URL以及该城市的URL。 客户端不需要知道如何构建这些,因为它们是给予它的。
城市的URL是/api/city/<id>
,获取完整城市列表的URL是/api/cities
,因为您已经定义了它。
如果您还需要按名称搜索城市,则可以扩展“城市”端点以执行此操作。 例如,您可以使用/api/cities/<name>
形式的网址返回与<name>
指定的搜索字词匹配的城市列表。
使用Flask-RESTful,您需要为此定义新的Resource
子类,例如:
class CitiesByNameAPI(Resource):
def __init__(self):
# ...
def get(self, name):
# ...
api.add_resource(CitiesByNameAPI, '/api/cities/<name>', endpoint = 'cities_by_name')
当客户要求一个城市时,它应该得到一个响应,其中包含一个URL以获取该城市的用户。 例如,假设从上面的/api/users
响应中我想了解第一个用户的城市。 所以现在我向http://example/api/city/35
发送请求,然后我收到以下JSON响应:
{
"url": "http://example.com/api/city/35",
"name": "San Francisco",
"users": "http://example/com/api/city/35/users"
}
现在我有了这个城市,这给了我一个URL,我可以使用它来获取该城市的所有用户。
请注意,您的URL难以构建或难以构建,因为客户端永远不需要从头开始构建大部分URL,它只是从服务器获取它们。 这也使您可以在将来更改URL的格式。
要实现按城市获取用户的URL,您需要添加另一个Resource
子类:
class UsersByCityAPI(Resource):
def __init__(self):
# ...
def get(self, id):
# ...
api.add_resource(UsersByCityAPI, '/api/cities/<int:id>/users', endpoint = 'users_by_city')
我希望这有帮助!
您可以在不重复资源的情况下执行id / name事务:
api.add_resource(CitiesByNameAPI, '/api/cities/<name_or_id>', endpoint = 'cities_by_name')
class CitiesByNameAPI(Resource):
def get(self, name_or_id):
if name_or_id.isdigit():
city = CityModel.find_by_id(name_or_id)
else:
city = CityModel.find_by_name(name_or_id)
if city:
return city.to_json(), 200
return {'error': 'not found'}, 404
不确定是否有任何负面影响。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.