Cloud Endpoints with Multiple Services Classes

2019-02-10 11:22发布

I am starting to use Google Cloud Endpoints and I am running in a problem when specifying multiple services classes. Any idea how to get this working?

ApiConfigurationError: Attempting to implement service myservice, version v1, with multiple classes that aren't compatible. See docstring for api() for examples how to implement a multi-class API.

This is how I am creating my endpoint server.

AVAILABLE_SERVICES = [
  FirstService,
  SecondService
]

app = endpoints.api_server(AVAILABLE_SERVICES)

and for every service class I am doing this:

@endpoints.api(name='myservice', version='v1', description='MyService API')
class FirstService(remote.Service):
...

@endpoints.api(name='myservice', version='v1', description='MyService API')
class SecondService(remote.Service):
...

Each one of these work perfectly separately, but I am not sure how to get them working when combining them.

Thanks a lot.

5条回答
smile是对你的礼貌
2楼-- · 2019-02-10 11:55

For local development I'm using a temporary workaround, which is to disable the exception (I know I know...)

In my sdk in google_appengine/google/appengine/ext/endpoints/api_backend_service.py around line 97:

        elif service_class != method_class:
          pass
#          raise api_config.ApiConfigurationError(
#              'SPI registered with multiple classes within one '
#              'configuration (%s and %s).  Each call to register_spi should '
#              'only contain the methods from a single class.  Call '
#              'repeatedly for multiple classes.' % (service_class,
#                                                    method_class))
    if service_class is not None:

In combination with that I'm using the construct:

application = endpoints.api_server([FirstService, SecondService, ...])

Again, this won't work in production, you'll get the same exception there. Hopefully this answer will be obsoleted by a future fix.

Confirmed it's now obsolete (tested against 1.8.2).

查看更多
够拽才男人
3楼-- · 2019-02-10 12:12

The correct way is to create an api object and use the collection

api_root = endpoints.api(name='myservice', version='v1', description='MyService API')

@api_root.collection(resource_name='first')
class FirstService(remote.Service):
  ...


@api_root.collection(resource_name='second')
class SecondService(remote.Service):
  ...

where resource name would be inserted in front of method names so that you could use

  @endpoints.method(name='method', ...)
  def MyMethod(self, request):
    ...

instead of

  @endpoints.method(name='first.method', ...)
  def MyMethod(self, request):
    ...

Putting this in the API server:

The api_root object is equivalent to a remote.Service class decorated with endpoints.api, so you can simply include it in the endpoints.api_server list. For example:

application = endpoints.api_server([api_root, ...])
查看更多
Ridiculous、
4楼-- · 2019-02-10 12:12

If I'm not mistaken, you should give different names to each service, so you'll be able to access both, each one with the specific "address".

@endpoints.api(name='myservice_one', version='v1', description='MyService One API')
class FirstService(remote.Service):
...

@endpoints.api(name='myservice_two', version='v1', description='MyService Two API')
class SecondService(remote.Service):
...
查看更多
劳资没心,怎么记你
5楼-- · 2019-02-10 12:12

If it was Java ...

https://developers.google.com/appengine/docs/java/endpoints/multiclass

cloudn't be easier.

查看更多
爷、活的狠高调
6楼-- · 2019-02-10 12:14

I've managed to successfuly deploy single api implemented in two classes. You can try using following snippet (almost directly from google documentation):

an_api = endpoints.api(name='library', version='v1.0')

@an_api.api_class(resource_name='shelves')
class Shelves(remote.Service):
...

@an_api.api_class(resource_name='books', path='books')
class Books(remote.Service):
...

APPLICATION = endpoints.api_server([an_api],
                               restricted=False)
查看更多
登录 后发表回答