plangrid / flask-rebar

Flask-Rebar combines flask, marshmallow, and swagger for robust REST services.
MIT License
231 stars 38 forks source link

filter_dump_only crashes with fields that have data_key #270

Closed h3kker closed 2 years ago

h3kker commented 2 years ago

Hi!

I've encountered a problem with flask_rebar 2.2.0 (marshmallow 3.15.0). I've set up a schema that uses data_key for field aliases like this:

class UserSchema(Schema):
  # ...
  is_admin = fields.Boolean(data_key='isAdmin')

But when I return a user object from a flask route that has this schema as return type:

class UserResponseSchema(ResponseSchema):
  data = fields.Nested(UserSchema)

@registry.handles(
  rule='/v1/users/<string:username>',
  method='GET',
  response_body_schema=UserResponseSchema(),
  # ...
)
def get_user(username):
  # ...
  return { 'data': user }

The following exception occurs:

# ... snip
  File "/Users/heinz.ekker/coden/Hinkskalle/backend/venv/lib/python3.9/site-packages/flask/app.py", line 1509, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/Users/heinz.ekker/coden/Hinkskalle/backend/venv/lib/python3.9/site-packages/flask_rebar/rebar.py", line 164, in wrapped
    marshaled = marshal(data=data, schema=schema)
  File "/Users/heinz.ekker/coden/Hinkskalle/backend/venv/lib/python3.9/site-packages/flask_rebar/utils/request_utils.py", line 91, in marshal
    return compat.dump(schema=schema, data=data)
  File "/Users/heinz.ekker/coden/Hinkskalle/backend/venv/lib/python3.9/site-packages/flask_rebar/compat.py", line 53, in dump
    filtered = filter_dump_only(schema, result)
  File "/Users/heinz.ekker/coden/Hinkskalle/backend/venv/lib/python3.9/site-packages/flask_rebar/validation.py", line 66, in filter_dump_only
    field_filtered = filter_dump_only(field_schema, v)
  File "/Users/heinz.ekker/coden/Hinkskalle/backend/venv/lib/python3.9/site-packages/flask_rebar/validation.py", line 54, in filter_dump_only
    field = schema.fields[k]
KeyError: 'isActive'

I think this could be solved by something like that:

--- a/flask_rebar/validation.py
+++ b/flask_rebar/validation.py
@@ -48,8 +48,9 @@ def filter_dump_only(schema, data):

         # construct loadable (a subset of non_dump_only, with recursive filter of nested dump_only fields)
         loadable = dict()
+        rev_map = { (f.data_key if f.data_key is not None else k): k for (k, f) in schema.fields.items()}
         for k, v in non_dump_only.items():
-            field = schema.fields[k]
+            field = schema.fields[rev_map[k]]
             # see if we have a nested schema (using either Nested(many=True) or List(Nested())
             field_schema = None
             if isinstance(field, fields.Nested):
gtmanfred commented 2 years ago

I believe this is fixed by #273

gtmanfred commented 2 years ago

Fixed in v2.2.1