11

I'm creating a simple web api with flask and sqlalchemy with marshmallow as serializer, and here is UserModel.

class UserModel(db.Model):
    __tablename__ = 'users'

    id            = db.Column(db.Integer, primary_key = True)
    username      = db.Column(db.String(120), unique = True, nullable = False)
    password      = db.Column(db.String(120), nullable = False)
    user_role     = db.Column(db.String(10), nullable = False)
    access_token  = db.Column(db.String(120), unique = True, nullable = True, default='as' )
    refresh_token = db.Column(db.String(120), unique = True, nullable = True, default='as' )

and schema,

class UserSchema(Schema):
    username = fields.Str()
    password = fields.Str()
    user_role = fields.Str()
    access_token = fields.Str()
    refresh_token = fields.Str()

when i tried to create a user entry using post request with postman like this

{
    "username":"test1",
    "password":"test1pswd",
    "user_role":"admin"
}

it returns the following error on console,

marshmallow.exceptions.ValidationError: {'_schema': ['Invalid input type.']}

What am I doing wrong here?

snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
pl-jay
  • 970
  • 1
  • 16
  • 33

1 Answers1

19

You are trying to load json using the Schema.load method.

>>> import json
>>> import marshmallow as mm
>>> class S(mm.Schema):               
...     username = mm.fields.Str()
...     password = mm.fields.Str()
...     user_role = mm.fields.Str()
...     access_token = mm.fields.Str()
...     refresh_token = mm.fields.Str()
... 
>>> d = {'username': 'test1', 'password': 'test1pswd', 'user_role': 'admin'}

>>> S().load(json.dumps(d))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/kdwyer/.virtualenvs/so37/lib/python3.7/site-packages/marshmallow/schema.py", line 681, in load
    data, many=many, partial=partial, unknown=unknown, postprocess=True
  File "/home/kdwyer/.virtualenvs/so37/lib/python3.7/site-packages/marshmallow/schema.py", line 840, in _do_load
    raise exc
marshmallow.exceptions.ValidationError: {'_schema': ['Invalid input type.']}

You can:

Call json.loads() on the data before passing to Schema.load

>>> S().load(json.loads(json.dumps(d)))
{'password': 'test1pswd', 'user_role': 'admin', 'username': 'test1'}

Pass the json to Schema.loads for automatic deserialisation

>>> S().loads(json.dumps(d))
{'password': 'test1pswd', 'user_role': 'admin', 'username': 'test1'}
snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
  • I wasted around 1 hour to figure out whats worng with my code until I came here. I was sending a json data. I just removed the json format and sent normal data and it worked – GKV Apr 14 '20 at 20:26
  • 4
    For me, I was receiving a `List`, had to set `SomeSchema(many=True)` – Asif Ali Jun 03 '20 at 07:14
  • Probably a dumb question, but instead of dumping dict d to JSON string, then recreating a dict from JSON string, why not just do `S().load(d)` ? – chrisinmtown Dec 06 '21 at 20:52
  • @chrisinmtown yes that would work - I think when I answered I didn't want to assume that the original `dict` was available: the asker might only have had a JSON string. But yes, if you have the original object then round-tripping to JSON and back is redundant. – snakecharmerb Dec 07 '21 at 06:12
  • In my case, instead of JSON (and expected dict) it was receiving an obect (caused by nested Schema with `@post_load`) - very confusing as you see same structure for the object as for the expected dict. – uvsmtid Dec 24 '22 at 20:34