Why the contract comes before the code
API-first means you design and agree on the interface — the URL, inputs, outputs, error shapes — before you build the thing behind it. The API is not a side effect of your implementation. It is the product.
For ML systems this matters twice as much. Models change. Training data changes. Inference backends get swapped out. But if the contract is stable, everything that depends on your model keeps working.
The API layer is the only layer your users ever touch. Everything below can be rewritten, replaced, or rehosted without notice — as long as the top of this stack keeps its promises.
Build the logic, then see what comes out.
Design the contract, then build both sides against it.
A developer should understand what an endpoint does from its URL and method alone. POST /predict is clear. POST /doStuff is not.
Same shape on success, same shape on error. Fields that can be null should be typed as nullable, not silently omitted. Clients that can predict what they'll get write half as much code.
The API doesn't expose which model served the prediction, where the database lives, or how the feature store is shaped. The client asks a product-shaped question and gets a product-shaped answer.
Reject bad input at the API layer with 422. Don't let malformed requests reach your model. Every layer below should trust its inputs.
Every response should be inspectable. Health endpoints, request IDs in responses, and stable error codes turn "it's broken" into "it's broken because X."
Prediction endpoint for a sentiment classifier. Same model, same inputs. Which one would you rather integrate with?
# Request POST /api/run_bert_sentiment_v3 { "input_tokens": [101, 2023, 2003, 2204, 102], "temperature": 0.7, "model_checkpoint": "bert-base-uncased-ft-2025-03-14" } # Response { "logits": [2.34, -1.87], "model_hash": "sha256:abc...", "gpu_ms": 42 }
# Request POST /v1/predict { "text": "I loved this product" } # Response { "prediction": "positive", "confidence": 0.94, "request_id": "req_01H..." }
In Breakout 1 you'll design POST /predict, GET /health, and GET /metadata. Apply these principles:
/health answers one question: is this service alive enough to take traffic?/metadata tells clients which version of the contract they're talking to