Always free. For everyone.
Course outline
Module 03 of 20 · Workflow foundations

Exchange and validate JSON

Read structured messages and reject invalid input before it spreads. This module has 3 lessons and takes about 1h 50m. Each lesson has a practice exercise that runs real Python in your browser and a short quiz.

Start module 03 in the Learning Lab
LESSON 1 OF 3

Parse a JSON message

25 minAI automation
WHAT YOU WILL DO

Parse raw JSON and return its dictionary. Return None for malformed JSON or a value that is not an object.

JSON carries data between systems. A JSON object resembles a Python dictionary, but JSON uses double quotes and values such as null and true. Python converts them to None and True.

json.loads reads text. Catch JSONDecodeError for malformed input, then check the result is a dictionary. Valid JSON can also contain a list or number.

Parsing only proves the text has a readable structure. You still need to check its fields and meaning.

See it in action

example.pyPython 3
def solve(raw):
    import json
    try:
        value = json.loads(raw)
    except (json.JSONDecodeError, TypeError):
        return None
    return value if isinstance(value, dict) else None
print(solve('{"id":"r1"}'))
Keep this in mind

Parsing only proves the text has a readable structure. You still need to check its fields and meaning.

LESSON 2 OF 3

Check required fields and types

25 minAI automation
WHAT YOU WILL DO

Return True only for a dictionary containing non-empty string id and message fields. Extra fields are allowed.

A schema describes expected fields and types. The intake contract here requires a non-empty string id and a non-empty string message. A number is not an acceptable message.

Check the outer object first, then check each required value with isinstance and strip. Return False for invalid input instead of letting a later step crash.

Validation should happen at each trust boundary, including after AI output and before an external write.

See it in action

example.pyPython 3
def solve(record):
    if not isinstance(record, dict):
        return False
    return all(isinstance(record.get(key), str) and bool(record[key].strip()) for key in ("id", "message"))
print(solve({"id":"r1","message":"Help"}))
Keep this in mind

Validation should happen at each trust boundary, including after AI output and before an external write.

LESSON 3 OF 3

Practical: Separate valid and invalid intake

60 minAI automation
WHAT YOU WILL DO

Return accepted ids and rejected zero-based positions. Accept only dictionary rows with non-empty string id and message values.

One bad record should not hide the rest of a batch. Collect accepted ids and the positions of rejected records. Positions let a reviewer find malformed rows without needing an id.

Use enumerate to get each zero-based position. Apply the same id and message checks to every item. Keep both output lists in the original order.

A rejected record needs an owner and a reason. This small example records positions; a real review queue should also keep a safe error code.

GUIDED PRACTICAL · 60 MIN

Your experiment plan

Use the browser editor or the notebook. All records and AI responses are fictional. No network calls, credentials, or real messages are used.

  1. Create a batch with valid, empty, and malformed records.
  2. Run the example and predict its result before changing it.
  3. Complete the function in Practice and run the checks. Add your own normal, empty, and failure cases.
  4. Move a bad record to another position and check its reported index.
  5. Save the notebook with your observations and explain one limitation of the simulation.

What to hand in

  • An intake validator with separate accepted and rejected outputs.
  • A test table with inputs, expected outputs, actual outputs, and one revision.
Reflect on your results

What error information is useful without copying private text?

The automatic exercise checks the core code behaviour. Review observations and written deliverables yourself or with a mentor.

See it in action

example.pyPython 3
def solve(rows):
    accepted, rejected = [], []
    for index, row in enumerate(rows):
        valid = isinstance(row, dict) and all(isinstance(row.get(k), str) and bool(row[k].strip()) for k in ("id", "message"))
        if valid:
            accepted.append(row["id"])
        else:
            rejected.append(index)
    return {"accepted": accepted, "rejected": rejected}
print(solve([{"id":"r1","message":"Hello"},{"id":"r2"},None]))
Keep this in mind

A rejected record needs an owner and a reason. This small example records positions; a real review queue should also keep a safe error code.

ABOUT THE LEARNING LAB

Free, open and run by a nonprofit.

This page is part of AI Automation, a free course of 20 modules and 60 lessons in the engineering.fit( ) Learning Lab. The Learning Lab is built and run by engineering.fit( ), a nonprofit founded by Abdullateef Opeyemi Bakare that helps African engineering students gain research experience. You do not need an account or pay a fee to learn.

Course outline · Project lab · Visit engineering-fit.org