Contracts

This document explains the contract pattern in Azu, where explicit request and response types create clear interfaces between components.

What are Contracts?

Contracts are type definitions that specify the shape of data flowing through your application:

  • Request contracts define expected input

  • Response contracts define expected output

Together, they create a clear API contract that's enforced by the compiler.

The Contract Pattern

Traditional Approach

Without contracts, data shapes are implicit:

def create
  # What fields are expected?
  name = params[:name]
  email = params[:email]

  # What if name is missing? Runtime error
  # What if email is wrong type? Runtime error
end

Contract Approach

With contracts, expectations are explicit:

Benefits:

  • Self-documenting

  • Validated automatically

  • Type-checked at compile time

Request Contracts

Request contracts define what data endpoints accept:

Components

  1. Fields - Properties that will be populated

  2. Types - Crystal types (String, Int32, etc.)

  3. Optionality - Use ? for optional fields

  4. Validations - Rules applied before processing

Parsing

Request contracts automatically parse:

  • JSON bodies (application/json)

  • Form data (application/x-www-form-urlencoded)

  • Multipart forms (multipart/form-data)

Response Contracts

Response contracts define what endpoints return:

Components

  1. Constructor - Accepts data to render

  2. Render method - Produces output string

  3. Content type - Implicit or explicit

Return Type Enforcement

The compiler ensures you return the declared type:

Contract Benefits

1. Self-Documentation

Contracts document the API:

Reading the request tells you exactly what the API accepts.

2. Validation

Validations run before your code:

Invalid requests are rejected before reaching your endpoint.

3. Type Safety

Types are enforced at compile time:

4. Refactoring Confidence

Changing contracts triggers compile errors:

Empty Contracts

For endpoints without body data:

For endpoints without response body:

Composition

Contracts can reference other types:

Contract Versioning

For API versioning, create separate contracts:

Best Practices

  1. One contract per use case

  2. Use meaningful names

  3. Keep contracts focused

See Also

Last updated

Was this helpful?