Serialization with Marshmallow
Marshmallow is a Python library that converts complex objects to and from simple data types, serializing your models into JSON and validating incoming request data against a schema.
Learn Serialization with Marshmallow in our free Flask course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Flask course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll declare a Schema , serialize objects with dump , validate input with load , nest schemas for related data, and read structured validation errors.
A Marshmallow Schema is a class whose attributes are typed fields — fields.Str , fields.Int , fields.Email , and so on. Calling schema.dump(obj) reads those fields off the object and returns a plain dictionary, ready to hand to jsonify . A field marked dump_only=True appears only in output, perfect for a database-assigned id .
The runnable example serializes a user dictionary and a list of users.
Output: a single dict with id , name , and email , then a list of two such dicts — exactly the shape you would return from an API.
The other direction is load(data) : it takes incoming data (your parsed JSON body), checks every field's type and validate rules, and returns clean Python values. If anything is wrong it raises a ValidationError whose .messages is a dictionary keyed by field — perfect for a 400 response.
The example loads a valid payload, then a broken one to show the error structure.
Output: the cleaned dict for the valid input, then an errors dict reporting the short name, the malformed email, and the out-of-range age — one entry per failing field.
Related data nests with fields.Nested(OtherSchema) . A BookSchema can embed its AuthorSchema , so dumping a book includes the author object and loading validates the nested fields too — errors are collected under the nested key.
Output: the dumped book with its nested author, the cleanly loaded second book, then an errors dict where the year error and the nested author.name error sit side by side.
In a real project you often pair Marshmallow with SQLAlchemy via flask-marshmallow and SQLAlchemyAutoSchema , which generates fields from your model:
Complete the schema. Replace each ___ so price is required and non-negative, and serialize/validate correctly.
load() raises on bad input. Wrap it in try/except ValidationError and return err.messages with a 400, or your view crashes with a 500.
❌ Accepting a dump_only field from the client
Mark server-controlled fields like id as dump_only=True . Otherwise a client could try to set them on load() .
To dump or load a collection, pass many=True (on the instance or per call). Without it, Marshmallow expects a single object.
Build a schema for an order containing a nested list of line items.
Lesson complete — your API speaks clean, validated JSON!
You can declare a Schema , serialize with dump , validate input with load , separate input/output with dump_only / load_only , nest related data, and read structured ValidationError messages.
🚀 Up next: Checkpoint — Build a REST API — combine login, querying, pagination, and serialization into a real endpoint.
Practice quiz
What is a Marshmallow Schema?
- A database table
- A Flask route
- A class whose attributes are typed fields
- A Jinja template
Answer: A class whose attributes are typed fields. A Schema is a class with typed fields like fields.Str and fields.Int.
Which method serializes an object to a plain dict?
- load()
- validate()
- parse()
- dump()
Answer: dump(). schema.dump(obj) reads the fields and returns a dictionary.
Which method validates and deserializes incoming data?
- load()
- dump()
- serialize()
- render()
Answer: load(). schema.load(data) checks types and validators and returns clean values.
What does a field marked dump_only=True mean?
- It is required on input
- It appears only in output, never accepted from input
- It is always None
- It is encrypted
Answer: It appears only in output, never accepted from input. dump_only fields appear in output but are ignored on load(), ideal for a server-set id.
What does load() raise when input is invalid?
- KeyError
- TypeError
- ValidationError
- ValueError
Answer: ValidationError. Invalid input raises a marshmallow ValidationError.
Where are per-field error messages found on a ValidationError?
- err.args
- err.fields
- err.detail
- err.messages
Answer: err.messages. err.messages is a dict keyed by field name, perfect for a 400 response.
How do you embed related data in a schema?
- fields.Nested(OtherSchema)
- fields.Link(OtherSchema)
- fields.Child(OtherSchema)
- fields.Embed(OtherSchema)
Answer: fields.Nested(OtherSchema). fields.Nested(OtherSchema) embeds another schema for related objects.
How do you serialize a list of objects?
- Pass list=True to dump
- Use Schema(many=True)
- Call dump_all()
- Loop and call dump on each manually only
Answer: Use Schema(many=True). Schema(many=True).dump(items) serializes a collection.
Which field validator restricts a number to a range?
- validate.MinMax()
- validate.Bounds()
- validate.Range(min=..., max=...)
- validate.Limit()
Answer: validate.Range(min=..., max=...). validate.Range(min=0, max=130) enforces numeric bounds.
In a Flask view, how do you handle a ValidationError from load()?
- Catch it and return jsonify(e.messages), 400
- Let it crash with a 500
- Ignore it and continue
- Convert it to a redirect
Answer: Catch it and return jsonify(e.messages), 400. Wrap load() in try/except and return e.messages with a 400 status.