typespec1-12 Exercise 2: Which Bad Bookings Does the Contract Reject? ========================================================================= The script (ex2_cases.py) posts eleven bookings to the Prism mock (port 4020, version 2 contract, with a bearer token in the header): """Send invalid bookings to the Prism mock and report which ones the contract alone rejects. py ex2_cases.py (mock on port 4020) """ import json import urllib.error import urllib.request good = {"roomId": "rm_1", "title": "Design review", "organizer": "ada@example.com", "start": "2026-11-02T10:00:00Z", "end": "2026-11-02T11:00:00Z", "attendees": 6} cases = [ ("a valid booking", good), ("empty title", {**good, "title": ""}), ("title of 121 characters", {**good, "title": "x" * 121}), ("organizer not an email", {**good, "organizer": "ada"}), ("start is not a date-time", {**good, "start": "tomorrow"}), ("attendees 0", {**good, "attendees": 0}), ("attendees 501", {**good, "attendees": 501}), ("no roomId", {k: v for k, v in good.items() if k != "roomId"}), ("end before start", {**good, "start": "2026-11-02T11:00:00Z", "end": "2026-11-02T10:00:00Z"}), ("an extra property 'colour'", {**good, "colour": "red"}), ("sends id (read-only)", {**good, "id": "bk_9"}), ] for label, body in cases: req = urllib.request.Request("http://127.0.0.1:4020/bookings", method="POST", data=json.dumps(body).encode(), headers={"Content-Type": "application/json", "Authorization": "Bearer demo-token"}) try: with urllib.request.urlopen(req) as r: status = r.status except urllib.error.HTTPError as e: status = e.code print(f"{label:<28} {status} {'accepted' if status == 201 else 'rejected'}") Results: a valid booking 201 accepted empty title 400 rejected title of 121 characters 400 rejected organizer not an email 400 rejected start is not a date-time 400 rejected attendees 0 400 rejected attendees 501 400 rejected no roomId 400 rejected end before start 201 accepted an extra property 'colour' 201 accepted sends id (read-only) 201 accepted REJECTED BY THE CONTRACT (400): empty title, title of 121 characters, organizer that is not an email, start that is not a date-time, attendees below 1 and above 500, a missing roomId. Each of these is a field-by-field rule from a decorator (@minLength, @maxLength, @format, @minValue, @maxValue, required). ACCEPTED, AND WHAT WOULD HAVE TO ENFORCE IT End before start: no contract keyword can compare two fields. The server must check it (and return the BadRequest the contract declares), and a test must cover it. An extra property 'colour': the schemas are open. Compiling with seal-object-schemas (chapters 9 and 10) and validating with a tool that honours it would reject it; the mock, running the default contract, did not. A read-only 'id' in the request: CreateBooking does not list id, but the open schema allows extra properties, so the mock lets it through. With sealed schemas it would be rejected; otherwise the server should ignore or reject it, and say which in the documentation. Note: the mock is one validator. I did not run the same cases through the generated Python client (it has no validation, as chapter 10 found) or through any real server. WHY THIS WORKS AS AN ANSWER --------------------------- It draws the line between what a contract can state and what code must enforce, with a result for each case, instead of asserting the line in the abstract.