Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API Design

The service should begin with a REST API and leave room for gRPC later.

API Principles

  1. Keep domain logic out of route handlers.
  2. Use application services for use cases.
  3. Keep DTOs separate from domain structs when public API stability matters.
  4. Make continuity state explicit in routes.
  5. Make visibility and permissions impossible to ignore.

Example REST Routes

POST   /v1/projects
GET    /v1/projects
GET    /v1/projects/{project_id}
PATCH  /v1/projects/{project_id}

POST   /v1/projects/{project_id}/entities
GET    /v1/projects/{project_id}/entities
GET    /v1/projects/{project_id}/entities/{entity_id}
PATCH  /v1/projects/{project_id}/entities/{entity_id}

POST   /v1/projects/{project_id}/relationships
GET    /v1/projects/{project_id}/relationships

POST   /v1/projects/{project_id}/continuities
GET    /v1/projects/{project_id}/continuities
GET    /v1/projects/{project_id}/continuities/{continuity_id}

POST   /v1/projects/{project_id}/continuities/{continuity_id}/events
POST   /v1/projects/{project_id}/continuities/{continuity_id}/mutations
POST   /v1/projects/{project_id}/continuities/{continuity_id}/reveal

POST   /v1/projects/{project_id}/continuities
GET    /v1/projects/{project_id}/continuities

GET    /v1/me/projects
GET    /v1/me/continuities
GET    /v1/me/follows

API Contracts

Request and response types can live in forge-api-contracts.

Example:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct CreateProjectRequest {
    pub title: String,
    pub description: Option<String>,
}
}

gRPC Later

gRPC is useful for typed internal clients, desktop clients, or service-to-service integrations.

Do not block the first REST implementation waiting for gRPC unless a known client needs it.