API Design
The service should begin with a REST API and leave room for gRPC later.
API Principles
- Keep domain logic out of route handlers.
- Use application services for use cases.
- Keep DTOs separate from domain structs when public API stability matters.
- Make continuity state explicit in routes.
- 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.