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.