Flask-RESTful API: 複数の複雑なエンドポイント 質問する

Flask-RESTful API: 複数の複雑なエンドポイント 質問する

Flask-RESTful API に、users と cities という 2 つのオブジェクトがあるとします。これは 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')

ご覧のとおり、非常に基本的な機能を実装するために必要なことはすべて実行できます。両方のオブジェクトに対して GET、POST、PUT、および DELETE を実行できます。ただし、私の目標は 2 つあります。

(1) 都市IDだけでなく都市名などの他のパラメータでリクエストできるようにします。次のようになります。
api.add_resource(CityAPI, '/api/city/<string:name>', endpoint='city')
ただし、このエラーは発生しません。

AssertionError: ビュー関数マッピングが既存のエンドポイント関数を上書きしています

(2) リクエストで 2 つのリソースを組み合わせることができるようにします。ある都市に関連付けられたすべてのユーザーを取得したいとします。REST URL では、次のようになります。
/api/cities/<int:id>/users

Flask でそれをどうやって行うのでしょうか? どのエンドポイントにマップするのでしょうか?

基本的に、私は API を基本的なものから便利なものにする方法を探しています。

ベストアンサー1

あなたは2つの間違いを犯しています。

まず、Flask-RESTful では、リソースが 1 つの URL で実装されていると考えてしまいます。実際には、同じタイプのリソースを返すさまざまな URL が存在する可能性があります。Flask-RESTful では、ResourceURL ごとに異なるサブクラスを作成する必要がありますが、概念的にはそれらの URL は同じリソースに属します。実際には、リストと個々のリクエストを処理するために、リソースごとに 2 つのインスタンスが既に作成されていることに注意してください。

2 つ目の間違いは、クライアントが API 内のすべての URL を知っていると想定していることです。これは API を構築する良い方法ではありません。理想的には、クライアントはトップレベルの URL をいくつか知っていて、残りはトップレベルの URL からの応答のデータから検出します。

API では、 と をトップレベル API として公開したい場合があります/api/users/api/cities個々の都市とユーザーへの URL が応答に含まれます。たとえば、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、定義したとおり です。

都市名でも都市を検索する必要がある場合は、「都市」エンドポイントを拡張してそれを実行できます。たとえば、フォーム内の URL で、/api/cities/<name>として指定された検索語に一致する都市のリストを返すことができます<name>

ResourceFlask-RESTful では、次のような新しいサブクラスを定義する必要があります。

    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')

これが役に立つことを願っています!

おすすめ記事