Skip to course content
Free FastAPI backend course

FastAPI for AI Backend Development

Unit 06.04: Versioning a contract without breaking callers

Compatibility breaks in a direction people consistently get backwards.

Seven changes, four breaking

Additions, removals and enum widenings, sorted by whether they break callers.

The code lists them.

CHANGES = [
    ("add an optional response field",   "safe",     "old clients ignore it"),
    ("add an optional request field",    "safe",     "old clients omit it"),
    ("add a REQUIRED request field",     "BREAKING", "every existing caller now fails"),
    ("remove a response field",          "BREAKING", "clients reading it break"),
    ("widen an enum you RETURN",         "BREAKING", "clients switching on it break"),
    ("widen an enum you ACCEPT",         "safe",     "old values still valid"),
    ("rename a field",                   "BREAKING", "remove plus add"),
]
print(f"{'change':38} {'kind':10} why")
for change, kind, why in CHANGES:
    print(f"{change:38} {kind:10} {why}")

breaking = sum(1 for _, k, _ in CHANGES if k == "BREAKING")
print(f"\n{breaking} of {len(CHANGES)} require a new version path")

# The two enum rows point in opposite directions, which is the one people get
# wrong. Accepting more is safe; returning something new breaks any client that
# branches on the value.

The two enum rows point in opposite directions. Accepting a new value is safe - old callers simply never send it. *Returning* a new value breaks any client that switches on the response, which is most of them.

That asymmetry is the one to internalise: widening what you accept is safe, widening what you emit is not.

The mistake this prevents

The mistake is adding a required request field to an existing version because the new feature needs it. Every existing caller starts failing validation immediately. Add it optional, or add a new version path.

Takeaway

Additions to what you accept are safe; anything you emit or require is breaking. New required fields and new returned enum values both need a new version.