Module 1: Foundations

API Contracts, Validation & Error Handling

Build predictable REST APIs with explicit contracts and safe error responses.

Learning objectives

By the end of this lesson, you should be able to:

  • Explain the key concepts and when they are useful.
  • Apply the concepts to a realistic engineering scenario.
  • Identify common failure modes and choose a practical mitigation.
  • Complete the assignment and explain your design decisions.

Core concepts

Treat an API as a contract consumed by independently changing clients. Define resource names, methods, status codes, pagination, validation errors, and compatibility expectations before implementation. Validate at the boundary, normalize input once, and return stable error shapes without stack traces or secrets.

Worked example

Example response: {“error”:{“code”:”VALIDATION_ERROR”,”message”:”Request is invalid”,”fields”:{“email”:”Must be a valid email”}}}. Use 400 for malformed input, 401 for missing authentication, 403 for insufficient permission, 404 for absent resources, and 409 for conflicting state when appropriate.

Engineering principles

  1. Make assumptions explicit. Document expected inputs, outputs, ownership, and failure behavior.
  2. Validate at boundaries. Treat user input, files, messages, and third-party responses as untrusted.
  3. Design for failure. Decide what happens when dependencies time out, data is malformed, or a process is retried.
  4. Prefer observable behavior. Log meaningful outcomes and expose enough diagnostics to debug without leaking secrets.
  5. Test the invariant. A test should prove a property that must remain true, not merely repeat the implementation.

Practical assignment

Specify POST /api/projects, GET /api/projects?page=1&limit=20, and PATCH /api/projects/{id}. Include success and failure responses for each.

Suggested solution and reasoning

Document required fields and limits; validate body, query, and path parameters; use consistent error codes; avoid returning internal exceptions; add contract tests for both success and failure cases.

Use this as a reference design, not the only possible answer. A strong submission states assumptions, includes failure cases, and demonstrates how correctness will be tested.

Knowledge check

  1. What problem does this design solve, and what simpler alternative did you consider?
  2. Which input or dependency is most likely to fail?
  3. What invariant must remain true after a retry?
  4. How would you test the unhappy path?

Completion checklist

  • I can explain the concepts without reading the lesson.
  • I completed the practical assignment.
  • I tested at least one failure scenario.
  • I documented trade-offs and next steps.

Continue learning

Was this page helpful?
Powered by IndieFounder