Search code examples
pythonjsongoogle-app-engineserializationwebapp2

Google App Engine - JSON Serialization of GeoPt data


I am trying to create an API for my web app but I keep getting an error when trying to load GeoPtProperty to JSON. I tried converting GeoPt data into JSON object but it didn't work.

class Post(ndb.Model):
    content = ndb.StringProperty(required = True)
    user = ndb.StringProperty()
    coords = ndb.GeoPtProperty()

    def render(self):
        self._render_text = self.content.replace('\n', '<br>')
        params = dict(p = self)

        return render_str("post.html", **params)

    def as_dict(self):
        d = {'content': self.content,
             'user': self.user,
             'coords': self.coords}

        return d

class Handler(webapp2.RequestHandler): 
    def write(self, *a, **kw):
        self.response.out.write(*a, **kw)

    def render_json(self, d):
        json_txt = json.dumps(d)
        self.response.headers['Content-Type'] = 'application/json; charset=UTF-8'
        self.write(json_txt)

class MainPage(Handler):        
    def get(self):
        posts = Post.query(ancestor=post_key()).order(-Post.created)

    if self.format == 'json':
        self.response.headers['Access-Control-Allow-Origin'] = '*'
        return self.render_json([p.as_dict() for p in posts])

Below is the traceback

Traceback (most recent call last):
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in __call__
    rv = self.handle_exception(request, response, e)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1529, in __call__
    rv = self.router.dispatch(request, response)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
    return route.handler_adapter(request, response)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1102, in __call__
    return handler.dispatch()
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 572, in dispatch
    return self.handle_exception(e, self.app.debug)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 570, in dispatch
    return method(*args, **kwargs)
  File "/base/data/home/apps/s~website/1.396738651304801066/main.py", line 121, in get
    return self.render_json([p.as_dict() for p in posts])
  File "/base/data/home/apps/s~website/1.396738651304801066/main.py", line 45, in render_json
    json_txt = json.dumps(d)
  File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/json/__init__.py", line 243, in dumps
    return _default_encoder.encode(obj)
  File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datastore_types.GeoPt(37.636003000000002, 127.216528) is not JSON serializable

How can I properly receive data in JSON?


Solution

  • I finally figured it out and will answer my own question. GeoPt data cannot be serialized so it has to be converted into JSON object. When storing GeoPT, you can simply use the below code.

            if coords:
                coords = ndb.GeoPt(lat, lon)
                p.coords = coords
            p.put()
    

    The ndb datastore entity looks like this:

    class Post(ndb.Model):
        coords = ndb.GeoPtProperty()
    

    I was able to fetch lat and lon, and convert them into JSON object.

    coords = self.coords.lat, self.coords.lon
    lat, lon = coords[0], coords[1]
    coords = {'latitude': lat, 'longitude': lon}
    

    This did the trick and my app is no longer throwing an error.