-
Couldn't load subscription status.
- Fork 17
Description
Discovered while attempting to modify the EchoApi example code from https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/standard/endpoints-frameworks-v2/echo to support multiple api classes.
I don't know if this is officially supported yet or not, but #27 seems to imply that it should work.
# [START imports]
import endpoints
from protorpc import message_types
from protorpc import messages
from protorpc import remote
# [END imports]
# [START messages]
class EchoRequest(messages.Message):
content = messages.StringField(1)
class EchoResponse(messages.Message):
"""A proto Message that contains a simple string field."""
content = messages.StringField(1)
ECHO_RESOURCE = endpoints.ResourceContainer(
EchoRequest,
n=messages.IntegerField(2, default=1))
# [END messages]
# [START echo_api]
api_collection = endpoints.api(
name='library',
version='v1')
@api_collection.api_class(resource_name='echo')
class Echo(remote.Service):
@endpoints.method(
# This method takes a ResourceContainer defined above.
ECHO_RESOURCE,
# This method returns an Echo message.
EchoResponse,
path='echo',
http_method='POST',
name='echo')
def echo(self, request):
output_content = ' '.join([request.content] * request.n)
return EchoResponse(content=output_content)
@endpoints.method(
# This method takes a ResourceContainer defined above.
ECHO_RESOURCE,
# This method returns an Echo message.
EchoResponse,
path='echo/{n}',
http_method='POST',
name='echo_path_parameter')
def echo_path_parameter(self, request):
output_content = ' '.join([request.content] * request.n)
return EchoResponse(content=output_content)
@endpoints.method(
# This method takes a ResourceContainer defined above.
message_types.VoidMessage,
# This method returns an Echo message.
EchoResponse,
path='echo/getApiKey',
http_method='GET',
name='echo_api_key')
def echo_api_key(self, request):
return EchoResponse(content=request.get_unrecognized_field_info('key'))
@endpoints.method(
# This method takes an empty request body.
message_types.VoidMessage,
# This method returns an Echo message.
EchoResponse,
path='echo/getUserEmail',
http_method='GET',
# Require auth tokens to have the following scopes to access this API.
scopes=[endpoints.EMAIL_SCOPE],
# OAuth2 audiences allowed in incoming tokens.
audiences=['your-oauth-client-id.com'])
def get_user_email(self, request):
user = endpoints.get_current_user()
# If there's no user defined, the request was unauthenticated, so we
# raise 401 Unauthorized.
if not user:
raise endpoints.UnauthorizedException
return EchoResponse(content=user.email())
# [END echo_api]
# [START api_server]
api = endpoints.api_server([api_collection])
# [END api_server]Running the endpointscfg.py script results in an AttributeError:
Traceback (most recent call last):
File "thirdparty/endpoints/endpointscfg.py", line 625, in <module>
main(sys.argv)
File "thirdparty/endpoints/endpointscfg.py", line 621, in main
args.callback(args)
File "thirdparty/endpoints/endpointscfg.py", line 479, in _GenOpenApiSpecCallback
application_path=args.application)
File "thirdparty/endpoints/endpointscfg.py", line 324, in _GenOpenApiSpec
application_path=application_path)
File "thirdparty/endpoints/endpointscfg.py", line 181, in GenApiConfig
module = __import__(module_name, fromlist=base_service_class_name)
File "/Users/matt/PycharmProjects/gff-api/main.py", line 113, in <module>
api = endpoints.api_server([api_collection])
File "/Users/matt/PycharmProjects/gff-api/thirdparty/endpoints/apiserving.py", line 485, in api_server
apis_app = _ApiServer(api_services, **kwargs)
File "/Users/matt/PycharmProjects/gff-api/thirdparty/endpoints/apiserving.py", line 241, in __init__
self.base_paths.add(entry.base_path)
AttributeError: '_ApiDecorator' object has no attribute 'base_path'I played around with the _ApiServer.__init__ method in endpoints/apiserving.py so that it checks the _ApiDecorator__common_info if it can't fetch base_path directly:
def __init__(self, api_services, **kwargs):
self.base_paths = set()
for entry in api_services[:]:
# pylint: disable=protected-access
if isinstance(entry, api_config._ApiDecorator):
api_services.remove(entry)
api_services.extend(entry.get_api_classes())
try:
self.base_paths.add(entry.base_path)
except AttributeError:
self.base_paths.add(entry._ApiDecorator__common_info.base_path)
# Record the API services for quick discovery doc generation
self.api_services = api_services
...This gets further through the process but results in a new error:
No handlers could be found for logger "endpoints.apiserving"
Traceback (most recent call last):
File "thirdparty/endpoints/endpointscfg.py", line 625, in <module>
main(sys.argv)
File "thirdparty/endpoints/endpointscfg.py", line 621, in main
args.callback(args)
File "thirdparty/endpoints/endpointscfg.py", line 479, in _GenOpenApiSpecCallback
application_path=args.application)
File "thirdparty/endpoints/endpointscfg.py", line 324, in _GenOpenApiSpec
application_path=application_path)
File "thirdparty/endpoints/endpointscfg.py", line 184, in GenApiConfig
raise TypeError('%s is not a ProtoRPC service' % service_class_name)
TypeError: main.api_collection is not a ProtoRPC service
I decided not to follow the rabbit hole any further -- it doesn't seem like a small job to fix. Any ideas?