0

API を作成するために Proto Datastore を使い始めたところです。両方が EndpointsModel から継承されている場合、リクエストとレスポンスに異なるクラスを使用できるかどうかを知りたいです。例えば、

class my_request(EndpointsModel):
    #attributes

class my_response(EndpointsModel):
    #different set of attributes

@endpoints.api(name='Blah', version='v1')
    class testAPI(remote.Service):

    @my_request.method(name='myAPImethod', path='blah',
                      http_method='POST')
    def myAPImethod(self, req):
        #do something
        resp = my_response()
        return resp

これはうまくいくようには見えません。誰かがそのようなメソッドを作成する方法を教えてください。私が考えることができる他の唯一の方法は、元の protorpc メソッドに戻り、デコレータの一部としてリクエストとレスポンスの両方のタイプを指定することです。proto-datastore を使用してこれを達成する方法はありますか? 前もって感謝します。

4

2 に答える 2

0

あなたの例では、非常に単純なレイアウトがあり、質問された質問や、私見では、実際に質問したいと思っていることと実際には一致していません。

私は自分でエンドポイント API に取り組んでいますが、これははるかに複雑ですが、2 つの異なるモデルを使用して、API 呼び出しの要求オブジェクトと応答オブジェクトの両方を作成しています。ただし、それらは 1 つ (または複数) が他の中にネストされています。App Engine ログで警告として使用する必要がある方法につながるヒントを見つけました。

Method csapi.user.XXXXX specifies path parameters but you are not using a ResourceContainer. This will fail in future releases; please switch to using ResourceContainer as soon as possible.

注意してください。ResourceContainers は非常にトリッキーでmessages.Message、protorpc からインポートするクラスをオフにする必要があります。ResourceContainers の説明については、このStackOverflow の回答を参照してください。

あなたの例をベースとして使用して、呼び出し先に返したいモデルの内容を複製する ResourceContainers を構築する必要があります。

import endpoints
from protorpc import messages
from protorpc import message_types
from protorpc import remote
from google.appengine.ext import ndb
from google.appengine.ext.ndb import msgprop
from endpoints_proto_datastore.ndb import EndpointsAliasProperty
from endpoints_proto_datastore.ndb import EndpointsModel

class MySubscriptionResponseMessage(messages.Message):
    id = messages.IntegerField(1)
    accountType = messages.EnumField(Account_Type, 2, required=True)
    isActive = messages.BooleanField(3, required=True, default=False)
    thisAcctEmail = messages.StringField(4)
    subscriberSince = message_types.DateTimeField(5)

class MyUserResponseMessage(messages.Message):
    id = messages.IntegerField(1)
    subscriptions = messages.MessageField('SubscriptionReadResponseMessage', 2, repeated=True)

class MySubscription(EndpointsModel):
    accountType = msgprop.EnumProperty(AccountType, choices=set([AccountType.POTENTIAL_LEAD, AccountType.BASIC, AccountType.ADVANCED, AccountType.PREMIUM]), required=True, default=AccountType.POTENTIAL_LEAD)
    isActive = ndb.BooleanProperty(required=True, indexed=True)
    thisAcctId = ndb.StringProperty(repeated=False, indexed=True, required=True)
    subscriberSince = ndb.DateTimeProperty(auto_now_add=True)

class MyUser(EndpointsModel):
    subscription_key = ndb.KeyProperty(kind="Subscription", repeated=True)
    def IdSet(self, value):
        # By default, the property "id" assumes the "id" will be an integer in a
        # simple key -- e.g. ndb.Key(GSModel, 10) -- which is the default behavior
        # if no key is set. Instead, we wish to use a string value as the "id" here,
        # so first check if the value being set is a string.
        if not isinstance(value, basestring):
            raise TypeError('ID must be a string.')
        # We call UpdateFromKey, which each of EndpointsModel.IdSet and
        # EndpointsModel.EntityKeySet use, to update the current entity using a
        # datastore key. This method sets the key on the current entity, attempts to
        # retrieve a corresponding entity from the datastore and then patch in any
        # missing values if an entity is found in the datastore.
        self.UpdateFromKey(ndb.Key(Csuser, value))

    @EndpointsAliasProperty(setter=IdSet, required=True)
    def id(self):
        # First check if the entity has a key.
        if self.key is not None:
            # If the entity has a key, return only the string_id. The method id()
            # would return any value, string, integer or otherwise, but we have a
            # specific type we wish to use for the entity "id" and that is string.
            return self.key.string_id()

    @EndpointsAliasProperty(repeated=True,property_type=Subscription.ProtoModel())
    def subscriptions(self):
    return ndb.get_multi(self.subscription_key)

@endpoints.api(name='Blah', version='v1')
    class testAPI(remote.Service):

    @my_request.method(
        response_message=MyUserResourceContainer,
        name='myAPImethod', 
        path='blah',
        http_method='POST')
    def myAPImethod(self, req):
        #do something
        this_sub = MySubscription()
        subs = []

        ... how you manipulate this object is up to you ...

        for sub in subs
            sub_msg = MySubscriptionResponseMessage(
                id=this_sub.id, 
                accountType=this_sub.accountType, 
                isActive=this_sub.isActive, 
                thisAcctEmail=this_sub.thisAcctEmail, 
                subscriberSince=this_sub.subscriberSince, 
            subs.append(sub_msg)

        return MyUserResponseMessage(
            id=user1.id, 
            subscriptions=subs)

ご覧のとおり、これは単純な例よりもかなり詳細です。

ボーナス ポイント:パス パラメータの使用

仮想ユーザーの id プロパティ (つまりpath='users/{id}/delete') などのメソッドのパス パラメーターを受け入れたい場合は、それが使用されるメソッド自体の前に次のブロックを追加します。

MY_REQUEST_RESOURCE_PAGE = endpoints.ResourceContainer(
    message_types.VoidMessage,
    id=messages.StringField(1, variant=messages.Variant.STRING),
    accountType=messages.EnumField(Account_Type, 2, required=True)
    isActive=messages.BooleanField(3, required=True),
    thisAcctEmail=messages.StringField(4, variant=messages.Variant.STRING),
    subscriberSince=messages.message_types.DateTimeField(5),
    cursor=messages.StringField(6, variant=messages.Variant.STRING, required=False, default="1"),
    limit=messages.IntegerField(7, variant=messages.Variant.INT32, required=False, default=10)
)

注:追加のプロパティcursorlimitに注意してください。これらにより、何百人ものユーザーがいる場合に返された結果のページネーションが可能になります。これらは、まさにこの目的のために、モデル クエリで頻繁に使用されます。

ここで、パス パラメータを受け入れるための変更を完了するには、上記の例から次の行を置き換えます。

response_message=MyUserResponseMessage,

これで:

MY_REQUEST_RESOURCE_PAGE , MyUserResponseMessage,

最後に、このセットアップでは、パス パラメーターを使用するかどうかに関係なく、モデルに複数のモデルが含まれている場合と同様に、内部に1 つ以上のMySubscriptionResponseMessageアイテムをネストMyUserResponseMessageして、呼び出し先に返すことができます。のネスト項目であるため、API メソッドに何も追加する必要はありません。また、それらの項目を呼び出し先に返す必要がない場合は、応答メッセージでモデルから項目を複製する必要はありません。MyUserMySubscriptionMyUserResponseMessage

于 2015-10-09T21:59:00.800 に答える
0

デコレータでand使用して、一種の入力/出力フィールドフィルタリングをrequest_fields=response_fields=.method()適用できますが、異なる入力メッセージ クラスと出力メッセージ クラスを指定することはできません。

別のオブジェクトを使用する必要がある場合は、標準のエンドポイントと protoRPC クラスおよびデコレーターを使用する必要があります。

于 2015-10-09T14:31:06.453 に答える