vibetunnel/docs/openapi.md

386 lines
No EOL
9.2 KiB
Markdown

# OpenAPI Migration Plan for VibeTunnel
## Overview
This document outlines the plan to adopt OpenAPI 3.1 for VibeTunnel's REST API to achieve type safety and consistency between the TypeScript server and Swift clients.
## Goals
1. **Single source of truth** - Define API contracts once in OpenAPI spec
2. **Type safety** - Generate TypeScript and Swift types from the spec
3. **Eliminate inconsistencies** - Fix type mismatches between platforms
4. **API documentation** - Auto-generate API docs from the spec
5. **Gradual adoption** - Migrate endpoint by endpoint without breaking changes
## Current Issues
- Session types differ completely between Mac app and server
- Git repository types have different field names and optional/required mismatches
- No standardized error response format
- Manual type definitions duplicated across platforms
- Runtime parsing errors due to type mismatches
## Implementation Plan
### Phase 1: Setup and Infrastructure (Week 1)
#### 1.1 Install Dependencies
```bash
# In web directory
pnpm add -D @hey-api/openapi-ts @apidevtools/swagger-cli @stoplight/spectral-cli
```
#### 1.2 Create Initial OpenAPI Spec
Create `web/openapi/openapi.yaml`:
```yaml
openapi: 3.1.0
info:
title: VibeTunnel API
version: 1.0.0
description: Terminal sharing and remote access API
servers:
- url: http://localhost:4020
description: Local development server
```
#### 1.3 Setup Code Generation
**TypeScript Generation** (`web/package.json`):
```json
{
"scripts": {
"generate:api": "openapi-ts -i openapi/openapi.yaml -o src/generated/api",
"validate:api": "spectral lint openapi/openapi.yaml",
"prebuild": "npm run generate:api"
}
}
```
**Swift Generation** (Xcode Build Phase):
1. Add `swift-openapi-generator` to Package.swift
2. Add build phase to run before compilation:
```bash
cd "$SRCROOT/../web" && \
swift-openapi-generator generate \
openapi/openapi.yaml \
--mode types \
--mode client \
--output-directory "$SRCROOT/Generated/OpenAPI"
```
#### 1.4 Create Shared Components
Define reusable schemas in `web/openapi/components/`:
```yaml
# components/errors.yaml
ErrorResponse:
type: object
required: [error, timestamp]
properties:
error:
type: string
description: Human-readable error message
code:
type: string
description: Machine-readable error code
enum: [
'INVALID_REQUEST',
'NOT_FOUND',
'UNAUTHORIZED',
'SERVER_ERROR'
]
timestamp:
type: string
format: date-time
```
### Phase 2: Migrate Git Endpoints (Week 2)
Start with Git endpoints as they're well-defined and isolated.
#### 2.1 Define Git Schemas
```yaml
# openapi/paths/git.yaml
/api/git/repository-info:
get:
operationId: getRepositoryInfo
tags: [git]
parameters:
- name: path
in: query
required: true
schema:
type: string
responses:
'200':
description: Repository information
content:
application/json:
schema:
$ref: '../components/schemas.yaml#/GitRepositoryInfo'
# components/schemas.yaml
GitRepositoryInfo:
type: object
required: [isGitRepo, hasChanges, modifiedCount, untrackedCount, stagedCount, addedCount, deletedCount, aheadCount, behindCount, hasUpstream]
properties:
isGitRepo:
type: boolean
repoPath:
type: string
currentBranch:
type: string
nullable: true
remoteUrl:
type: string
nullable: true
githubUrl:
type: string
nullable: true
hasChanges:
type: boolean
modifiedCount:
type: integer
minimum: 0
untrackedCount:
type: integer
minimum: 0
stagedCount:
type: integer
minimum: 0
addedCount:
type: integer
minimum: 0
deletedCount:
type: integer
minimum: 0
aheadCount:
type: integer
minimum: 0
behindCount:
type: integer
minimum: 0
hasUpstream:
type: boolean
```
#### 2.2 Update Server Implementation
```typescript
// src/server/routes/git.ts
import { paths } from '../../generated/api';
type GitRepositoryInfo = paths['/api/git/repository-info']['get']['responses']['200']['content']['application/json'];
router.get('/git/repository-info', async (req, res) => {
const response: GitRepositoryInfo = {
isGitRepo: true,
repoPath: result.repoPath,
// ... ensure all required fields are included
};
res.json(response);
});
```
#### 2.3 Update Mac Client
```swift
// Use generated types
import OpenAPIGenerated
let response = try await client.getRepositoryInfo(path: filePath)
let info = response.body.json // Fully typed!
```
### Phase 3: Migrate Session Endpoints (Week 3)
Session endpoints are more complex due to WebSocket integration.
#### 3.1 Standardize Session Types
```yaml
SessionInfo:
type: object
required: [id, name, workingDir, status, createdAt, pid]
properties:
id:
type: string
format: uuid
name:
type: string
workingDir:
type: string
status:
type: string
enum: [starting, running, exited]
exitCode:
type: integer
nullable: true
createdAt:
type: string
format: date-time
lastActivity:
type: string
format: date-time
pid:
type: integer
nullable: true
command:
type: array
items:
type: string
```
#### 3.2 Create Session Operations
```yaml
/api/sessions:
get:
operationId: listSessions
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/SessionInfo'
post:
operationId: createSession
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSessionRequest'
responses:
'201':
content:
application/json:
schema:
$ref: '#/components/schemas/SessionInfo'
```
### Phase 4: Runtime Validation (Week 4)
#### 4.1 Add Request Validation Middleware
```typescript
// src/server/middleware/openapi-validator.ts
import { OpenAPIValidator } from 'express-openapi-validator';
export const openapiValidator = OpenAPIValidator.middleware({
apiSpec: './openapi/openapi.yaml',
validateRequests: true,
validateResponses: true,
});
// Apply to routes
app.use('/api', openapiValidator);
```
#### 4.2 Add Response Validation in Development
```typescript
// src/server/utils/validated-response.ts
export function validatedJson<T>(res: Response, data: T): void {
if (process.env.NODE_ENV === 'development') {
// Validate against OpenAPI schema
validateResponse(res.req, data);
}
res.json(data);
}
```
### Phase 5: Documentation and Testing (Week 5)
#### 5.1 Generate API Documentation
```bash
# Add to package.json
"docs:api": "npx @redocly/cli build-docs openapi/openapi.yaml -o dist/api-docs.html"
```
#### 5.2 Add Contract Tests
```typescript
// src/test/contract/git-api.test.ts
import { matchesSchema } from './schema-matcher';
test('GET /api/git/repository-info matches schema', async () => {
const response = await request(app)
.get('/api/git/repository-info')
.query({ path: '/test/repo' });
expect(response.body).toMatchSchema('GitRepositoryInfo');
});
```
## Migration Checklist
### Endpoints to Migrate
- [ ] **Git APIs** (Phase 2)
- [ ] GET /api/git/repo-info
- [ ] GET /api/git/repository-info
- [ ] GET /api/git/remote
- [ ] GET /api/git/status
- [ ] POST /api/git/event
- [ ] GET /api/git/follow
- [ ] **Session APIs** (Phase 3)
- [ ] GET /api/sessions
- [ ] POST /api/sessions
- [ ] GET /api/sessions/:id
- [ ] DELETE /api/sessions/:id
- [ ] POST /api/sessions/:id/resize
- [ ] POST /api/sessions/:id/input
- [ ] GET /api/sessions/:id/stream (SSE)
- [ ] **Repository APIs** (Phase 4)
- [ ] GET /api/repositories/discover
- [ ] GET /api/repositories/branches
- [ ] **Worktree APIs** (Phase 4)
- [ ] GET /api/worktrees
- [ ] POST /api/worktrees
- [ ] DELETE /api/worktrees/:branch
- [ ] POST /api/worktrees/switch
## Success Metrics
1. **Zero runtime type errors** between Mac app and server
2. **100% API documentation** coverage
3. **Contract tests** for all endpoints
4. **Reduced code** - Remove manual type definitions
5. **Developer velocity** - Faster API development with code generation
## Long-term Considerations
### Future Enhancements
1. **GraphQL Gateway** - Add GraphQL layer on top of REST for complex queries
2. **API Versioning** - Use OpenAPI to manage v1/v2 migrations
3. **Client SDKs** - Generate SDKs for other platforms (iOS, CLI tools)
4. **Mock Server** - Use OpenAPI spec to run mock server for testing
### Breaking Changes
When making breaking changes:
1. Version the API (e.g., /api/v2/)
2. Deprecate old endpoints with sunset dates
3. Generate migration guides from schema differences
## Resources
- [OpenAPI 3.1 Specification](https://spec.openapis.org/oas/v3.1.0)
- [OpenAPI TypeScript Generator](https://github.com/hey-api/openapi-ts)
- [Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator)
- [Spectral Linting](https://stoplight.io/open-source/spectral)
- [ReDoc Documentation](https://redocly.com/docs/redoc)