Skip to content
This repository was archived by the owner on Apr 19, 2026. It is now read-only.
This repository was archived by the owner on Apr 19, 2026. It is now read-only.

DateTime fields cause 500s as query parameters #49

Open

Description

@aetherknight

Endpoints and/or protorpc triggers a 500 error if a DateTime field is used as a query parameter instead of in the body of a request.

Reference Code

import endpoints
from protorpc import message_types, messages, remote


class BodyMessage(messages.Message):
    body_date = message_types.DateTimeField(1)


@endpoints.api(
    name='someapi',
    version='v1',
    allowed_client_ids=[endpoints.API_EXPLORER_CLIENT_ID],
    scopes=[endpoints.EMAIL_SCOPE]
)
class SomeApiService(remote.Service):

    QUERY_RESOURCE = endpoints.ResourceContainer(message_types.VoidMessage, query_date=message_types.DateTimeField(1))

    @endpoints.method(QUERY_RESOURCE, message_types.VoidMessage, path='get', http_method='GET', name='get')
    def get(self, request):
        print request.query_date
        return message_types.VoidMessage()

    @endpoints.method(BodyMessage, message_types.VoidMessage, path='post', http_method='POST', name='post')
    def post(self, request):
        print request.body_date
        return message_types.VoidMessage()


APPLICATION = endpoints.api_server([SomeApiService])

DateTime in a JSON body works as expected

When the post method is called with the date time in the JSON body in an ISO 8601-like format, it works fine:
datetime_body

DateTime as a query parameter generates erroneous APIs Explorer UI that causes 500s

However, when a datetime is in a query parameter, the endpoints API specification tells APIs explorer to show the fields that make up the DateTimeField type instead of a single string field:
datetime_query

If I try to supply what I would think is a valid DateTime in milliseconds since the epoch and timezone offset, I get a 500 error:

ERROR    2017-02-23 15:30:56,505 wsgi.py:279]
Traceback (most recent call last):
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 268, in Handle
    for chunk in result:
  File "/Users/wsorvis/src/datatheorem/endpoints_sample/lib/endpoints/endpoints_dispatcher.py", line 117, in __call__
    yield self.dispatch(request, start_response)
  File "/Users/wsorvis/src/datatheorem/endpoints_sample/lib/endpoints/endpoints_dispatcher.py", line 149, in dispatch
    return self.call_backend(request, start_response)
  File "/Users/wsorvis/src/datatheorem/endpoints_sample/lib/endpoints/endpoints_dispatcher.py", line 350, in call_backend
    body_iter = self._backend(transformed_environ, start_response_proxy.Proxy)
  File "/Users/wsorvis/src/datatheorem/endpoints_sample/lib/endpoints/apiserving.py", line 428, in __call__
    body_iter = self.service_app(environ, start_response_proxy.Proxy)
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/lib/protorpc-1.0/protorpc/wsgi/util.py", line 173, in first_found_app
    response = app(environ, first_found_start_response)
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/lib/protorpc-1.0/protorpc/wsgi/service.py", line 148, in protorpc_service_app
    remote_info.request_type, environ['wsgi.input'].read(content_length))
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/lib/protorpc-1.0/protorpc/remote.py", line 1121, in decode_message
    return self.__protocol.decode_message(message_type, encoded_message)
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/lib/protorpc-1.0/protorpc/protojson.py", line 201, in decode_message
    message = self.__decode_dictionary(message_type, dictionary)
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/lib/protorpc-1.0/protorpc/protojson.py", line 279, in __decode_dictionary
    valid_value.append(self.decode_field(field, item))
  File "/Users/wsorvis/src/datatheorem/endpoints_sample/lib/endpoints/protojson.py", line 106, in decode_field
    return super(EndpointsProtoJson, self).decode_field(field, value)
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/lib/protorpc-1.0/protorpc/protojson.py", line 312, in decode_field
    return util.decode_datetime(value)
  File "/Users/wsorvis/google-cloud-sdk/platform/google_appengine/lib/protorpc-1.0/protorpc/util.py", line 463, in decode_datetime
    time_zone_match = _TIME_ZONE_RE.search(encoded_datetime)
TypeError: expected string or buffer
INFO     2017-02-23 15:30:56,513 module.py:806] default: "GET /_ah/api/someapi/v1/get?query_date.milliseconds=0&query_date.time_zone_offset=0 HTTP/1.1" 500 -

Note: Locally on the dev_appserver and both endpoints 1 and endpoints-2.0.2, if I send the query without using the fields from APIs Explorer, then it works as expected. Eg, the URL http://localhost:8080/_ah/api/someapi/v1/get?query_date=2017-01-01T00:00:00 responds with a 204 (and it prints the supplied date).

When deployed to appengine with endpoints 1, trying to submit a string to the query_date directly causes a 500 that does not show up in my logs. I have not tested endpoints 2 when deployed yet.

Expected Behavior

the endpoints API description provided to APIs Explorer should expose a datetime query parameter as a string field, the same way it does when a datetime field is in the body.

Activity

  1. aetherknight commented on Feb 23, 2017

    @aetherknight
    Author

    To clarify further, there are 2 problems:

    • the endpoints API definition does not describe DateTimes in query parameter fields in a way that the APIs explorer handles nicely
    • When deployed, Endpoints 2 behaves fine if I ignore APIs explorer and send the query parameter as an ISO-8601 string. However, the same request but with Endpoints 1 (when deployed to GAE) 500s and does not give me a stack track trace.
  2. mchalek commented on Apr 19, 2017

    @mchalek

    I ran into the same problem today. I put a log message into protorpc util.py to see what was being passed to the decoded_datetime function, and it's a dictionary with the milliseconds and time_zone_offset arguments as keys. Of course, that method expects a string argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions