mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-27 04:31:27 +08:00
- Removed outdated API model and schema files to simplify the structure. - Consolidated API types and schemas for better organization and clarity. - Updated import paths across the codebase to reflect the new structure. - Enhanced documentation in related README files to guide usage of the new API schema organization.
5.6 KiB
5.6 KiB
Data API Type System
This directory contains the type definitions and utilities for Cherry Studio's Data API system, which provides type-safe IPC communication between renderer and main processes.
Directory Structure
packages/shared/data/api/
├── index.ts # Barrel export for infrastructure types
├── apiTypes.ts # Core request/response types and API utilities
├── apiPaths.ts # Path template literal type utilities
├── errorCodes.ts # Error handling utilities and factories
└── schemas/
├── index.ts # Schema composition (merges all domain schemas)
├── test.ts # Test API schema and DTOs
└── batch.ts # Batch/transaction API schema
File Responsibilities
| File | Purpose |
|---|---|
apiTypes.ts |
Core types (DataRequest, DataResponse, ApiClient) and schema utilities |
apiPaths.ts |
Template literal types for path resolution (/items/:id → /items/${string}) |
errorCodes.ts |
DataApiErrorFactory, error codes, and error handling utilities |
index.ts |
Unified export of infrastructure types (not domain DTOs) |
schemas/index.ts |
Composes all domain schemas into ApiSchemas using intersection types |
schemas/*.ts |
Domain-specific API definitions and DTOs |
Import Conventions
Infrastructure Types (via barrel export)
Use the barrel export for common API infrastructure:
import type {
DataRequest,
DataResponse,
ApiClient,
PaginatedResponse,
ErrorCode
} from '@shared/data/api'
import { DataApiErrorFactory, isDataApiError } from '@shared/data/api'
Domain DTOs (directly from schema files)
Import domain-specific types directly from their schema files:
// Topic domain
import type { Topic, CreateTopicDto, UpdateTopicDto } from '@shared/data/api/schemas/topic'
// Message domain
import type { Message, CreateMessageDto } from '@shared/data/api/schemas/message'
// Test domain (development)
import type { TestItem, CreateTestItemDto } from '@shared/data/api/schemas/test'
Adding a New Domain Schema
- Create the schema file (e.g.,
schemas/topic.ts):
import type { PaginatedResponse } from '../apiTypes'
// Domain models
export interface Topic {
id: string
name: string
createdAt: string
}
export interface CreateTopicDto {
name: string
}
// API Schema - validation happens via AssertValidSchemas in index.ts
export interface TopicSchemas {
'/topics': {
GET: {
response: PaginatedResponse<Topic> // response is required
}
POST: {
body: CreateTopicDto
response: Topic
}
}
'/topics/:id': {
GET: {
params: { id: string }
response: Topic
}
}
}
Validation: Schemas are validated at composition level via AssertValidSchemas in schemas/index.ts:
- Ensures only valid HTTP methods (GET, POST, PUT, DELETE, PATCH)
- Requires
responsefield for each endpoint - Invalid schemas cause TypeScript errors at the composition point
- Register in
schemas/index.ts:
import type { TopicSchemas } from './topic'
// AssertValidSchemas provides fallback validation even if ValidateSchema is forgotten
export type ApiSchemas = AssertValidSchemas<TestSchemas & BatchSchemas & TopicSchemas>
- Implement handlers in
src/main/data/api/handlers/
Type Safety Features
Path Resolution
The system uses template literal types to map concrete paths to schema paths:
// Concrete path '/topics/abc123' maps to schema path '/topics/:id'
api.get('/topics/abc123') // TypeScript knows this returns Topic
Exhaustive Handler Checking
ApiImplementation type ensures all schema endpoints have handlers:
// TypeScript will error if any endpoint is missing
const handlers: ApiImplementation = {
'/topics': {
GET: async () => { /* ... */ },
POST: async ({ body }) => { /* ... */ }
}
// Missing '/topics/:id' would cause compile error
}
Type-Safe Client
ApiClient provides fully typed methods:
const topic = await api.get('/topics/123') // Returns Topic
const topics = await api.get('/topics', { query: { page: 1 } }) // Returns PaginatedResponse<Topic>
await api.post('/topics', { body: { name: 'New' } }) // Body is typed as CreateTopicDto
Error Handling
Use DataApiErrorFactory for consistent error creation:
import { DataApiErrorFactory, ErrorCode } from '@shared/data/api'
// Create errors
throw DataApiErrorFactory.notFound('Topic', id)
throw DataApiErrorFactory.validationError('Name is required')
throw DataApiErrorFactory.fromCode(ErrorCode.DATABASE_ERROR, 'Connection failed')
// Check errors
if (isDataApiError(error)) {
console.log(error.code, error.status)
}
Architecture Overview
Renderer Main
────────────────────────────────────────────────────
DataApiService ──IPC──► IpcAdapter ──► ApiServer
│ │
│ ▼
ApiClient MiddlewareEngine
(typed) │
▼
Handlers
(typed)
- Renderer: Uses
DataApiServicewith type-safeApiClientinterface - IPC: Requests serialized via
IpcAdapter - Main:
ApiServerroutes to handlers throughMiddlewareEngine - Type Safety: End-to-end types from client call to handler implementation