What is Contract?
Contract is a Go package that lets you define your API as a Go interface, then automatically expose it through multiple protocols (REST, JSON-RPC, MCP) without duplicating code. Write your business logic once, serve it everywhere. The key insight is simple: your API is a contract between you and your clients. Contract takes this literally by using Go interfaces to define that contract, giving you compile-time safety and clear API boundaries.The Problem Contract Solves
Imagine youβre building a todo list application. You want to:- Let web browsers call your API via REST
- Let other services call via JSON-RPC for batching
- Let AI assistants (like Claude) use your API via MCP
- Generate TypeScript types for your frontend
CreateInput, you need to verify every handler handles it correctly.
The Contract Solution
With Contract, you organize your code into a dedicated package (liketodo) and define your API as a Go interface. The interface is named simply API because the package name (todo) already provides context:
Service (again, the package name provides context):
todo.API, implement it in todo.Service, and itβs instantly available via REST, JSON-RPC, and MCP.
Why Interface-First?
Contract uses Go interfaces to define your API. This is called βinterface-firstβ or βcontract-firstβ design. Letβs explore why this approach is powerful.Compile-Time Safety
Goβs compiler checks that your implementation matches your interface. If you forget to implement a method, or if you implement it with the wrong signature, you get a compile error - not a runtime crash:Clear API Boundaries
The interface serves as documentation. Anyone can read it and understand exactly what your service does, without digging through implementation details:Easy Testing
Because your business logic is in plain Go methods, you can test it directly without HTTP mocking. You can also create mock implementations for testing code that depends on your service:Separation of Concerns
The interface separates βwhat your API doesβ (the contract) from βhow itβs implementedβ (the business logic). This lets you swap implementations without changing your API:How Contract Works
Hereβs what happens when you use Contract, step by step:- You define an interface with your API methods (like
todo.API) - You implement the interface with your business logic (like
todo.Service) - Contract inspects your interface at startup using Goβs reflection capabilities
- Contract creates efficient invokers and JSON schemas from your types
- Transport handlers receive HTTP requests and convert them to method calls
- Your method runs with the parsed input and returns results or errors
- Transport handlers convert the response back to the appropriate protocol format
Key Concepts
Letβs understand the core concepts youβll work with in Contract.Interface (The Contract)
An interface defines what operations your API supports. Think of it as a menu at a restaurant - it lists whatβs available without explaining how each dish is prepared:Implementation (The Service)
A struct that implements the interface. This is where your actual business logic lives - the βkitchenβ that prepares the dishes:Resource
A resource is a namespace that groups related methods. It affects how your API endpoints are named and organized:- REST:
/todos(POST for Create, GET for List),/todos/{id}(GET, DELETE) - JSON-RPC:
todos.create,todos.list,todos.get,todos.delete - MCP tools:
todos.create,todos.list, etc.
Transport
A transport is a protocol handler that converts HTTP requests into method calls. Think of transports as translators - they speak different βlanguagesβ (protocols) but all communicate with the same backend (your service):| Transport | Protocol | Best For |
|---|---|---|
| REST | HTTP REST | Web browsers, curl, most HTTP clients |
| JSON-RPC | JSON-RPC 2.0 | Batch operations, service-to-service calls |
| MCP | Model Context Protocol | AI assistants like Claude |
Type Registry
Contract automatically analyzes your Go types and creates JSON schemas. These schemas describe your data structures in a language-agnostic way:- OpenAPI documentation: Generate API docs automatically
- Client code generation: Create typed clients in TypeScript, Python, etc.
- AI tool definitions: Tell AI assistants what parameters your tools accept
What Youβll Learn
This documentation will teach you everything you need to build APIs with Contract:- Quick Start - Build your first API in 5 minutes with step-by-step instructions
- Defining Services - How to structure your interfaces, implementations, and types
- Registration - What happens when you call
contract.Registerand available options - Type System - How Go types map to JSON schemas and wire formats
- Error Handling - Return meaningful errors that work across all protocols
- Transports - Choose the right protocol for your use case
- Testing - Test your services easily without HTTP mocking
- Architecture - Understand how Contract works under the hood
Quick Example
Hereβs a complete, working example. You can copy this code, run it, and start experimenting:Greet method - Contract handles the protocol translation automatically.
Common Questions
Do I need to learn all the transports?
No! Start with REST - itβs the most familiar and works with any HTTP client. You can add other transports later as needed. Your business logic stays exactly the same regardless of which transports you use.Is Contract only for new projects?
Contract works great for new projects, but you can also gradually adopt it in existing codebases. Start by converting one service to see how it fits. Your existing REST handlers can coexist with Contract-powered endpoints.How does Contract handle authentication?
Contract focuses on business logic, not authentication. Use standard mizu middleware to authenticate requests before they reach your methods. You can pass user information to your service methods through context values:Why use interfaces instead of structs with method tags?
Interfaces give you compile-time safety. If your implementation doesnβt match the interface, the compiler catches it immediately. With struct-based or decorator approaches, you might only find out at runtime if a method signature is wrong. Goβs type system is your friend - let it help you catch bugs early.How do I organize my code?
We recommend organizing each service into its own package:todo.API is clearer than TodoAPI).