Flask RESTful API multiple and complex endpoints
在我的Flask-RESTful API中,假设我有两个对象,用户和城市。这是一对多关系。现在,当我创建我的API并向其中添加资源时,我似乎可以做的就是将非常简单的通用URL映射到它们。这是代码(不包括无用的东西):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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)能够使用其他参数(例如城市名称)进行请求,而不仅仅是
城市编号。它看起来像:
除非它不会抛出此错误:
AssertionError: View function mapping is overwriting an existing
endpoint function
(2)能够将两个资源合并到一个请求中。说我想得到所有
与某个城市关联的用户。在REST URL中,它应类似于:
如何用Flask做到这一点?我将其映射到哪个端点?
基本上,我正在寻找使API从基本变为可用的方法。感谢您的任何想法/建议
您犯了两个错误。
首先,Flask-RESTful使您认为资源是通过单个URL实施的。实际上,您可以有许多不同的URL返回相同类型的资源。在Flask-RESTful中,您将需要为每个URL创建一个不同的
您犯的第二个错误是您希望客户端知道您API中的所有URL。这不是构建API的好方法,理想情况下,客户端只知道几个顶级URL,然后从顶级响应中的数据中发现其余的URL。
在您的API中,您可能希望将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { "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为
如果您还需要按城市名称搜索城市,则可以扩展"城市"端点来进行。例如,您可能以
使用Flask-RESTful,您将需要为此定义一个新的
1 2 3 4 5 6 7 | class CitiesByNameAPI(Resource): def __init__(self): # ... def get(self, name): # ... api.add_resource(CitiesByNameAPI, '/api/cities/<name>', endpoint = 'cities_by_name') |
获取属于一个城市的所有用户
当客户要求一个城市时,它应该得到一个包含URL的响应,以使用户进入该城市。例如,假设在上面的
1 2 3 4 5 | { "url":"http://example.com/api/city/35", "name":"San Francisco", "users":"http://example/com/api/city/35/users" } |
现在我有了城市,这给了我一个URL,我可以使用它来获取该城市中的所有用户。
请注意,您的URL丑陋或难以构建都没关系,因为客户端不需要从头开始构建大多数URL,它只是从服务器获取它们。这也使您将来可以更改URL的格式。
要实现按城市吸引用户的URL,您可以添加另一个
1 2 3 4 5 6 7 | 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的事情而无需复制资源:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
不知道是否有任何负面影响。