neo4j-graphacademy / app-python

https://graphacademy.neo4j.com/courses/app-python
58 stars 99 forks source link

JSON serialization error in 12-movie-details solution #10

Closed MrFlick closed 1 year ago

MrFlick commented 2 years ago

When working on the "Project Backlog" section, specifically the "Movie Details" task, I get an error when running the solution provided in the 12-movie-details branch. When you go to a page like http://localhost:3000/movies/9772. An error will appear in the flask log

raceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2091, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2076, in wsgi_app
    response = self.handle_exception(e)
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/workspaces/neo-py-tutorial/api/routes/movies.py", line 42, in get_movie_details
    return jsonify(movie)
  File "/usr/local/lib/python3.9/site-packages/flask/json/__init__.py", line 355, in jsonify
    f"{dumps(data, indent=indent, separators=separators)}\n",
  File "/usr/local/lib/python3.9/site-packages/flask/json/__init__.py", line 133, in dumps
    rv = _json.dumps(obj, **kwargs)
  File "/usr/local/lib/python3.9/json/__init__.py", line 234, in dumps
    return cls(
  File "/usr/local/lib/python3.9/json/encoder.py", line 201, in encode
    chunks = list(chunks)
  File "/usr/local/lib/python3.9/json/encoder.py", line 431, in _iterencode
    yield from _iterencode_dict(o, _current_indent_level)
  File "/usr/local/lib/python3.9/json/encoder.py", line 405, in _iterencode_dict
    yield from chunks
  File "/usr/local/lib/python3.9/json/encoder.py", line 325, in _iterencode_list
    yield from chunks
  File "/usr/local/lib/python3.9/json/encoder.py", line 405, in _iterencode_dict
    yield from chunks
  File "/usr/local/lib/python3.9/json/encoder.py", line 438, in _iterencode
    o = _default(o)
  File "/usr/local/lib/python3.9/site-packages/flask/json/__init__.py", line 57, in default
    return super().default(o)
  File "/usr/local/lib/python3.9/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Date is not JSON serializable

The ultimate error "TypeError: Object of type Date is not JSON serializable" seems to be coming from the "born" property of the Actor nodes which are returned to python as objects like neo4j.time.Date(1986, 10, 14) and those are not properly serialized by the flask.jsonify function. The full cypher query used for that task is

  MATCH (m:Movie {tmdbId: $id})
  RETURN m {
      .*,
      actors: [ (a)-[r:ACTED_IN]->(m) | a { .*, role: r.role } ],
      directors: [ (d)-[:DIRECTED]->(m) | d { .* } ],
      genres: [ (m)-[:IN_GENRE]->(g) | g { .name }],
      favorite: m.tmdbId IN $favorites
  } AS movie
  LIMIT 1

Is there a recommended work around? Does the code in api/routes/movies.py need to change to so as to not use jsonify? Or is there an easy way to convert those neo4j.time.Date objects into strings in the cypher query itself?

This occurs running Python 3.9.12 with Flask 2.0.2 and neo4j 4.4.0 using the sample Recommendations graph database.

parkhe commented 2 years ago

Hello,

Or is there an easy way to convert those neo4j.time.Date objects into strings in the cypher query itself?

I just did as suggested and it worked. Thank you for your insight!

Part of the Cypher query was rewritten, like this: actors: [ (a)-[r:ACTED_IN]->(m) | a { .*, born: toString(a.born), died: toString(a.died), role: r.role } ], As well as for directors.

The webpage displays correctly for me now.

adam-cowley commented 2 years ago

This is probably the easiest suggestion. The more complicated route would be to do this manually in the transaction function write a python function that detects datetime types and calls str() on them.

alg commented 10 months ago

It would be nice if the course had fixed queries or official suggestions on how to deal with this kind of transformations. At the moment the code crashes.