strawberry-graphql/strawberry

Way to serialize/deserialize nested items and union type

Opened this issue · 1 comments

Feature Request Type

  • Core functionality
  • Alteration (enhancement/optimization) of existing feature(s)
  • New behavior

Description

I need to store/read data from a redis database (I guess it is a fairly common usecase), and therefore the objects need to be serialized to store them, and un-serialize to recover them later. But I can't find really nice generic way to do that. For now I'm using

def serialize_dataclass(obj, kind):
    if not kind:
        kind = obj.__name__
    return json.dumps({**asdict(obj), "__typename": obj.__name__})

def deserialize_dataclass(json):
    ## TODO: not very secure, see later
    return globals()[json["__typename"]](**{k:v for k,v in data.items() if k != "__typename"})

but this is not great for multiple reasons:

  • the main issue is that I don't think this will work for nested types (e.g. a Person has an age, a name… and aCard, where card is itself another type)
  • secondly, if a type is a union (say type Card = Number | Figure), I need to store in the database which precise sub-type (eg. Figure) the original object is (this is fine), but when I restore it later, I use globals() to go from the name of the type to the type itself… but this is not very secure as I can't really be sure that the new type is indeed a subtype of the original one. For instance if the database was corrupted, I might read __typename = MaliciousFigure, and then this would create a MaliciousFigure instead of a Figure… For safety/debugging purposes, I'd prefer to raise an error if the type is not part of Card, but this seems not trivial to do (at least I just found get_origin and get_args for the typing library, but this is quite low level and require non-negligible of work to use to recover the precise sub-types for more complicated types)

Am I missing something obvious? How are people dealing with this? If there is no easy solution here, I would love to have it in the library by default.

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

Note that using pydantic, we can serialize/deserialize in a better way… but strawberry still does not really conversion from pydantic types for union types (and the recursive translation seems also quite annoying, if at all possible) #3641