@deep-document-search/api-client-typescript-v2
v1.0.15
Published
TypeScript client generated from Swagger/OpenAPI specification
Maintainers
Readme
API Client Typescript V2
A TypeScript client library generated from the OpenAPI/Swagger specification for the backend API. This client provides type-safe access to all API endpoints with comprehensive TypeScript support.
Table of Contents
Installation
npm install
npm run buildSetup
// 完整导入所有方法和类型
import {
// 方法
postAuthLogin,
getOrganizations,
// 类型
type Options,
type Document,
type UserResponse
} from '@deep-document-search/api-client-typescript-v2';
// 或者只导入需要的模块
import { postAuthLogin, type LoginRequest } from '@deep-document-search/api-client-typescript-v2';
// 默认客户端已经预配置,所有API函数都使用这个客户端实例
// 默认基础URL: localhost:8080/api/v1Authentication
Authentication Token Configuration
有三种方式可以设置认证令牌,推荐使用方式3(直接设置请求头):
方式1:全局客户端配置(持久性配置)
import { client, getOrganizations } from '@deep-document-search/api-client-typescript-v2';
// 配置全局认证设置
client.setConfig({
security: [{ name: 'Authorization', type: 'apiKey' }],
auth: async () => {
// 返回认证令牌(从localStorage或其他存储获取)
return localStorage.getItem('authToken');
}
});
// 现在所有API调用都会自动添加认证头
await getOrganizations(); // ✅ 自动包含认证方式2:请求级认证配置(按需配置)
import { getOrganizations } from '@deep-document-search/api-client-typescript-v2';
// 在特定请求中配置认证
await getOrganizations({
security: [{ name: 'Authorization', type: 'apiKey' }],
auth: localStorage.getItem('authToken') // 直接传递令牌
});方式3:直接设置请求头(推荐,最简单直接)
import { getOrganizations } from '@deep-document-search/api-client-typescript-v2';
await getOrganizations({
headers: {
'Authorization': `Bearer ${localStorage.getItem('authToken')}`
}
});推荐使用方式3的原因:
- 简单直观:无需理解复杂的security配置
- 灵活控制:每个请求独立管理认证
- 调试友好:明确可见认证头内容
- 兼容性好:适用于所有HTTP客户端
Login & Token Storage
import { postAuthLogin, getUsersById, type LoginRequest, type LoginResponse, type UserResponse } from '@deep-document-search/api-client-typescript-v2';
// 1. Login and get token with typed request const loginRequest: LoginRequest = { username: 'your-username', password: 'your-password' };
const loginResult = await postAuthLogin({ body: loginRequest });
// 2. Store token in localStorage (for web applications) if (loginResult.data && 'token' in loginResult.data) { const loginResponse = loginResult.data as LoginResponse; localStorage.setItem('authToken', loginResponse.token!); }
// 3. Retrieve token for subsequent requests
const getAuthHeaders = () => ({
'Authorization': Bearer ${localStorage.getItem('authToken')}
});
// 4. Use in API calls with typed response const userProfile = await getUsersById({ path: { id: 'current-user-id' }, headers: getAuthHeaders() });
const userData: UserResponse = userProfile.data!;
const userProfile: UserResponse = userProfileResponse.data!;
### Token Refresh Strategy
```typescript
import {
postAuthRefresh,
type RefreshTokenRequest,
type LoginResponse
} from '@deep-document-search/api-client-typescript-v2';
// Check token expiration and refresh if needed
async function refreshTokenIfExpired(): Promise<string> {
const token = localStorage.getItem('authToken');
if (token && isTokenExpired(token)) {
const refreshRequest: RefreshTokenRequest = {
refreshToken: localStorage.getItem('refreshToken') || ''
};
const refreshResponse = await postAuthRefresh({
body: refreshRequest
});
if (refreshResponse.data && 'token' in refreshResponse.data) {
const loginResponse = refreshResponse.data as LoginResponse;
localStorage.setItem('authToken', loginResponse.token);
return loginResponse.token;
}
}
return token || '';
}
// Wrap API calls with token refresh
async function safeApiCall<T>(apiFunction: (token: string) => Promise<T>): Promise<T> {
const token = await refreshTokenIfExpired();
return apiFunction(token);
}Using Authentication in Requests
Most API endpoints require authentication. Include the JWT token in the Authorization header:
import {
getOrganizations,
type ListOrganizationsResponse
} from '@deep-document-search/api-client-typescript-v2';
const organizationsResponse: ListOrganizationsResponse = await getOrganizations({
headers: {
'Authorization': `Bearer ${token}`
}
});
const organizations = organizationsResponse.data?.organizations || []);API Modules
Authentication API
Authentication endpoints for user login, logout, token refresh, and email verification.
| Method | Endpoint | Description |
|--------|----------|-------------|
| postAuthLogin | /auth/login | Authenticate user and return JWT token |
| postAuthLogout | /auth/logout | Revoke current user session |
| postAuthRefresh | /auth/refresh | Refresh JWT token using refresh token |
| postAuthResendVerification | /auth/resend-verification | Resend email verification |
| postAuthVerifyEmail | /auth/verify-email | Verify user email address |
| getAuthVerificationStatusByEmail | /auth/verification-status/{email} | Check email verification status |
Search API
Search and search index management for configuring search clusters and indices.
Search Indices
| Method | Endpoint | Description |
|--------|----------|-------------|
| getApiV1SearchIndices | /api/v1/search-indices | List search indices with pagination |
| postApiV1SearchIndices | /api/v1/search-indices | Create new search index |
| deleteApiV1SearchIndicesById | /api/v1/search-indices/{id} | Delete search index |
| getApiV1SearchIndicesById | /api/v1/search-indices/{id} | Get search index by ID |
| putApiV1SearchIndicesById | /api/v1/search-indices/{id} | Update search index |
| postApiV1SearchIndicesByIdAssociate | /api/v1/search-indices/{id}/associate | Associate index with search |
| postApiV1SearchIndicesByIdSync | /api/v1/search-indices/{id}/sync | Sync index with Elasticsearch |
Searches
| Method | Endpoint | Description |
|--------|----------|-------------|
| getApiV1Searches | /api/v1/searches | List searches with pagination |
| postApiV1Searches | /api/v1/searches | Create new search |
| deleteApiV1SearchesById | /api/v1/searches/{id} | Delete search |
| getApiV1SearchesById | /api/v1/searches/{id} | Get search by ID |
| putApiV1SearchesById | /api/v1/searches/{id} | Update search |
| getApiV1SearchesByIdIndices | /api/v1/searches/{id}/indices | List search indices by search ID |
Document Management API
Comprehensive document handling including upload, download, and batch operations with S3 integration.
Single Document Operations
| Method | Endpoint | Description |
|--------|----------|-------------|
| getWorkspaceDocuments | /workspace/documents | List documents with filtering |
| postWorkspaceDocuments | /workspace/documents | Upload document (multipart/form-data) |
| deleteWorkspaceDocumentsById | /workspace/documents/{id} | Delete document |
| getWorkspaceDocumentsById | /workspace/documents/{id} | Get document details |
| putWorkspaceDocumentsById | /workspace/documents/{id} | Update document metadata |
| postWorkspaceDocumentsByIdAssociate | /workspace/documents/{id}/associate | Associate document with item |
| deleteWorkspaceDocumentsByIdDisassociateByItemId | /workspace/documents/{id}/disassociate/{itemId} | Disassociate document from item |
| getWorkspaceDocumentsByIdDownload | /workspace/documents/{id}/download | Download document file |
Batch Document Operations
| Method | Endpoint | Description |
|--------|----------|-------------|
| deleteWorkspaceDocumentsBatch | /workspace/documents/batch | Batch delete documents |
| postWorkspaceDocumentsBatch | /workspace/documents/batch | Batch create documents |
| putWorkspaceDocumentsBatch | /workspace/documents/batch | Batch update documents |
| postWorkspaceDocumentsBatchConfirmUpload | /workspace/documents/batch-confirm-upload | Confirm batch uploads |
| postWorkspaceDocumentsBatchDownloadUrls | /workspace/documents/batch-download-urls | Generate batch download URLs |
| postApiV1DocumentsBatchUploadUrls | /api/v1/documents/batch-upload-urls | Generate batch upload URLs |
| postWorkspaceDocumentsBatchUploadUrls | /workspace/documents/batch-upload-urls | Generate batch upload URLs |
| postWorkspaceDocumentsBatchUploads | /workspace/documents/batch-uploads | Batch upload documents |
Workspace API
Workspace management for organizing projects and resources.
| Method | Endpoint | Description |
|--------|----------|-------------|
| getWorkspaceWorkspaces | /workspace/workspaces | List workspaces with filtering |
| postWorkspaceWorkspaces | /workspace/workspaces | Create new workspace |
| deleteWorkspaceWorkspacesById | /workspace/workspaces/{id} | Delete workspace |
| getWorkspaceWorkspacesById | /workspace/workspaces/{id} | Get workspace by ID |
| putWorkspaceWorkspacesById | /workspace/workspaces/{id} | Update workspace |
Item Management API
Item management within projects, supporting associations with documents.
Single Item Operations
| Method | Endpoint | Description |
|--------|----------|-------------|
| getWorkspaceItems | /workspace/items | List items with filtering |
| postWorkspaceItems | /workspace/items | Create new item |
| deleteWorkspaceItemsById | /workspace/items/{id} | Delete item |
| getWorkspaceItemsById | /workspace/items/{id} | Get item by ID |
| putWorkspaceItemsById | /workspace/items/{id} | Update item |
| postWorkspaceItemsByIdAssociate | /workspace/items/{id}/associate | Associate item with document |
| deleteWorkspaceItemsByIdDisassociateByDocId | /workspace/items/{id}/disassociate/{docId} | Disassociate item from document |
Batch Item Operations
| Method | Endpoint | Description |
|--------|----------|-------------|
| deleteWorkspaceItemsBatch | /workspace/items/batch | Batch delete items |
| postWorkspaceItemsBatch | /workspace/items/batch | Batch create items |
| putWorkspaceItemsBatch | /workspace/items/batch | Batch update items |
Project Management API
Project management within workspaces.
| Method | Endpoint | Description |
|--------|----------|-------------|
| getWorkspaceProjects | /workspace/projects | List projects with filtering |
| postWorkspaceProjects | /workspace/projects | Create new project |
| deleteWorkspaceProjectsById | /workspace/projects/{id} | Delete project |
| getWorkspaceProjectsById | /workspace/projects/{id} | Get project by ID |
| putWorkspaceProjectsById | /workspace/projects/{id} | Update project |
Organization Management API
Organization-level resource management.
| Method | Endpoint | Description |
|--------|----------|-------------|
| getOrganizations | /organizations | List organizations with filtering |
| postOrganizations | /organizations | Create new organization |
| deleteOrganizationsById | /organizations/{id} | Delete organization |
| getOrganizationsById | /organizations/{id} | Get organization by ID |
| putOrganizationsById | /organizations/{id} | Update organization |
User Management API
User administration and audit logging.
| Method | Endpoint | Description |
|--------|----------|-------------|
| getUsers | /users | List users with pagination |
| postUsers | /users | Create new user |
| deleteUsersById | /users/{id} | Delete user |
| getUsersById | /users/{id} | Get user by ID |
| putUsersById | /users/{id} | Update user |
| getUsersByIdAuditLogs | /users/{id}/audit-logs | Get user audit logs |
| postUsersOrganization | /users/organization | Create user within organization |
Complete Import Guide
Authentication API
postAuthLogin // 用户登录
postAuthLogout // 用户登出
postAuthRefresh // 刷新令牌
postAuthResendVerification // 重发验证邮件
postAuthVerifyEmail // 验证邮箱
getAuthVerificationStatusByEmail // 检查验证状态Organization Management API
getOrganizations // 获取组织列表
postOrganizations // 创建组织
deleteOrganizationsById // 删除组织
getOrganizationsById // 获取组织详情
putOrganizationsById // 更新组织User Management API
getUsers // 获取用户列表
postUsers // 创建用户
deleteUsersById // 删除用户
getUsersById // 获取用户详情
putUsersById // 更新用户
getUsersByIdAuditLogs // 获取用户审计日志
postUsersOrganization // 在组织内创建用户Workspace Management API
getWorkspaceWorkspaces // 获取工作区列表
postWorkspaceWorkspaces // 创建工作区
deleteWorkspaceWorkspacesById // 删除工作区
getWorkspaceWorkspacesById // 获取工作区详情
putWorkspaceWorkspacesById // 更新工作区Project Management API
getWorkspaceProjects // 获取项目列表
postWorkspaceProjects // 创建项目
deleteWorkspaceProjectsById // 删除项目
getWorkspaceProjectsById // 获取项目详情
putWorkspaceProjectsById // 更新项目Item Management API
getWorkspaceItems // 获取项目项列表
postWorkspaceItems // 创建项目项
deleteWorkspaceItemsById // 删除项目项
getWorkspaceItemsById // 获取项目项详情
putWorkspaceItemsById // 更新项目项
postWorkspaceItemsByIdAssociate // 关联文档
deleteWorkspaceItemsByIdDisassociateByDocId // 解除关联Document Management API
getWorkspaceDocuments // 获取文档列表
postWorkspaceDocuments // 上传文档
deleteWorkspaceDocumentsById // 删除文档
getWorkspaceDocumentsById // 获取文档详情
putWorkspaceDocumentsById // 更新文档元数据
postWorkspaceDocumentsByIdAssociate // 关联文档到项目项
deleteWorkspaceDocumentsByIdDisassociateByItemId // 解除关联
getWorkspaceDocumentsByIdDownload // 下载文档Search API
getApiV1SearchIndices // 获取搜索索引
postApiV1SearchIndices // 创建搜索索引
deleteApiV1SearchIndicesById // 删除索引
getApiV1SearchIndicesById // 获取索引详情
putApiV1SearchIndicesById // 更新索引
postApiV1SearchIndicesByIdAssociate // 关联索引到搜索
postApiV1SearchIndicesByIdSync // 同步索引
getApiV1Searches // 获取搜索配置
postApiV1Searches // 创建搜索配置
deleteApiV1SearchesById // 删除搜索配置
getApiV1SearchesById // 获取搜索详情
putApiV1SearchesById // 更新搜索配置
getApiV1SearchesByIdIndices // 按搜索ID获取索引Domain Types
Core Types
Options // 请求选项
ClientOptions // 客户端配置
ErrorResponse // 错误响应
SuccessResponse // 成功响应Authentication Types
LoginRequest // 登录请求
LoginResponse // 登录响应
RefreshTokenRequest // 刷新令牌请求User & Organization Types
UserResponse // 用户响应
CreateUserRequest // 创建用户请求
UpdateUserRequest // 更新用户请求
Organization // 组织
OrganizationResponse // 组织响应
CreateOrganizationRequest // 创建组织请求
UpdateOrganizationRequest // 更新组织请求Document Types
Document // 文档对象
DocumentStatus // 文档状态
CreateDocumentRequest // 创建文档请求
UpdateDocumentRequest // 更新文档请求
FileUploadRequest // 文件上传请求
UploadUrlResponse // 上传URL响应
DownloadUrlResponse // 下载URL响应Project & Item Types
Project // 项目
Item // 项目项
CreateProjectRequest // 创建项目请求
UpdateProjectRequest // 更新项目请求
CreateItemRequest // 创建项请求
UpdateItemRequest // 更新项请求Workspace Types
Workspace // 工作区
CreateWorkspaceRequest // 创建工作区请求
UpdateWorkspaceRequest // 更新工作区请求Search Types
Search // 搜索配置
SearchIndex // 搜索索引
SearchCluster // 搜索集群
CreateSearchRequest // 创建搜索请求
UpdateSearchRequest // 更新搜索请求
CreateSearchIndexRequest // 创建索引请求
UpdateSearchIndexRequest // 更新索引请求Error Handling
The client includes comprehensive error handling with typed error responses:
import {
getOrganizations,
type ListOrganizationsResponse,
type ErrorResponse
} from '@deep-document-search/api-client-typescript-v2';
try {
const result: ListOrganizationsResponse = await getOrganizations({
headers: { 'Authorization': 'Bearer your-token' }
});
} catch (error: any) {
if (error.status === 401) {
console.error('Authentication required');
} else if (error.status === 404) {
console.error('Resource not found');
} else if (error.data) {
const errorResponse = error.data as ErrorResponse;
console.error('API Error:', errorResponse.message);
}
}Advanced Configuration
Custom Client Configuration
默认客户端已经预配置,但如果需要自定义配置,可以通过以下方式:
import { client } from '@deep-document-search/api-client-typescript-v2';
// 方式1:修改默认客户端配置
client.setConfig({
baseUrl: 'https://your-api-server.com/api/v1',
// 其他配置选项...
});
// 使用自定义客户端
import {
getOrganizations,
type ListOrganizationsResponse
} from '@deep-document-search/api-client-typescript-v2';
const organizationsResponse: ListOrganizationsResponse = await getOrganizations({
client: client, // 传递自定义客户端
headers: {
'Authorization': `Bearer ${token}`
}
});Options Parameter
所有API方法都接受一个可选的Options参数,具有以下属性:
interface Options {
headers?: Record<string, string>;
client?: Client; // 自定义客户端实例(可选)
meta?: Record<string, unknown>; // 任意元数据
// 错误处理
throwOnError?: boolean;
// 请求特定配置
baseUrl?: string; // 基础URL(可选覆盖,优先级高于客户端配置)
timeout?: number; // 超时时间
}Examples
Complete Workflow Example
import {
postAuthLogin,
getOrganizations,
postWorkspaceWorkspaces,
postWorkspaceProjects,
postWorkspaceDocuments,
getWorkspaceDocuments,
// Import request and response types
type LoginRequest,
type LoginResponse,
type ListOrganizationsResponse,
type Organization,
type CreateWorkspaceRequest,
type WorkspaceSuccessResponse,
type Workspace,
type CreateProjectRequest,
type ProjectSuccessResponse,
type Project,
type CreateDocumentRequest,
type DocumentSuccessResponse,
type Document,
type ListDocumentsResponse
} from '@deep-document-search/api-client-typescript-v2';
// 1. Authenticate with typed request
const loginRequest: LoginRequest = {
username: 'admin',
password: 'password123'
};
const loginResponse = await postAuthLogin({
body: loginRequest
});
let token: string;
if (loginResponse.data && 'token' in loginResponse.data) {
const loginData = loginResponse.data as LoginResponse;
token = loginData.token;
} else {
throw new Error('Login failed: No token received');
}
const headers = { 'Authorization': `Bearer ${token}` };
// 2. Get organizations with typed response
const organizationsResponse: ListOrganizationsResponse = await getOrganizations({ headers });
const organizations: Organization[] = organizationsResponse.data?.organizations || [];
// 3. Create workspace with typed request and response
const workspaceRequest: CreateWorkspaceRequest = {
name: 'My Workspace',
description: 'Test workspace for development'
};
const workspaceResponse: WorkspaceSuccessResponse = await postWorkspaceWorkspaces({
body: workspaceRequest,
headers
});
const workspace: Workspace = workspaceResponse;
// 4. Create project with typed request and response
const projectRequest: CreateProjectRequest = {
name: 'My Project',
description: 'Test project for API integration',
workspace_id: workspace.id!,
owner_id: 'user-id-from-auth'
};
const projectResponse: ProjectSuccessResponse = await postWorkspaceProjects({
body: projectRequest,
headers
});
const project: Project = projectResponse;
// 5. Upload document with typed request and response
const documentRequest: CreateDocumentRequest = {
name: 'api-integration-test-document'
};
const formData = new FormData();
formData.append('name', documentRequest.name);
formData.append('file', fileBlob); // Assume fileBlob is defined
const documentResponse: DocumentSuccessResponse = await postWorkspaceDocuments({
body: formData,
headers: {
...headers,
'Content-Type': null
}
});
const document: Document = documentResponse;
// 6. List documents with typed response
const documentsResponse: ListDocumentsResponse = await getWorkspaceDocuments({ headers });
const documents: Document[] = documentsResponse.documents || [];Batch Operations Example
import {
postApiV1DocumentsBatchUploadUrls,
type BatchGenerateUploadUrlRequest,
type BatchGenerateUploadUrlResponse,
type UploadUrlResponse
} from '@deep-document-search/api-client-typescript-v2';
// Generate batch upload URLs with typed request
const uploadRequest: BatchGenerateUploadUrlRequest = {
files: [
{
file_name: 'document1.pdf',
file_size: 1024000,
mime_type: 'application/pdf'
},
{
file_name: 'image.jpg',
file_size: 2048000,
mime_type: 'image/jpeg'
}
],
expiry_minutes: 60
};
const uploadUrlsResponse: BatchGenerateUploadUrlResponse = await postApiV1DocumentsBatchUploadUrls({
body: uploadRequest,
headers
});
// Use the presigned URLs to upload files
uploadUrlsResponse.uploads?.forEach(async (urlInfo: UploadUrlResponse) => {
await fetch(urlInfo.presigned_url!, {
method: 'PUT',
body: fileData
});
});Best Practices & Advanced Usage
Architecture Overview
This library is built on a modern function-first architecture with the following key characteristics:
- Function-Only API: Each API endpoint is exposed as a standalone function
- Default Client Pattern: All functions use a pre-configured
clientinstance - Type Safety: Full TypeScript support with comprehensive type definitions
- Flexible Configuration: Support for request-level and client-level customization
Pinia Store Integration Best Practices
1. Service Layer Pattern (Recommended)
Create a service layer that encapsulates API calls and provides clean interfaces for your stores:
// services/organizationService.ts
import {
getOrganizations,
postOrganizations,
putOrganizationsById,
deleteOrganizationsById,
type Organization,
type CreateOrganizationRequest,
type UpdateOrganizationRequest
} from '@deep-document-search/api-client-typescript-v2';
export class OrganizationService {
static async listOrganizations(headers?: Record<string, string>): Promise<ListOrganizationsResponse> {
return getOrganizations({ headers });
}
static async createOrganization(data: CreateOrganizationRequest, headers?: Record<string, string>): Promise<OrganizationSuccessResponse> {
return postOrganizations({ body: data, headers });
}
static async updateOrganization(id: string, data: UpdateOrganizationRequest, headers?: Record<string, string>): Promise<OrganizationSuccessResponse> {
return putOrganizationsById({
path: { id },
body: data,
headers
});
}
static async deleteOrganization(id: string, headers?: Record<string, string>): Promise<void> {
await deleteOrganizationsById({
path: { id },
headers
});
}
}2. Pinia Store Implementation
// stores/organizationStore.ts
import { defineStore } from 'pinia';
import { OrganizationService } from '../services/organizationService';
import type { Organization, CreateOrganizationRequest, UpdateOrganizationRequest } from '@deep-document-search/api-client-typescript-v2';
export const useOrganizationStore = defineStore('organizations', {
state: () => ({
organizations: [] as Organization[],
currentOrganization: null as Organization | null,
isLoading: false,
error: null as string | null
}),
getters: {
organizationById: (state) => (id: string) => {
return state.organizations.find(org => org.id === id);
},
activeOrganizations: (state) => {
return state.organizations.filter(org => org.isActive);
}
},
actions: {
async loadOrganizations(authToken: string) {
this.isLoading = true;
this.error = null;
try {
const response: ListOrganizationsResponse = await OrganizationService.listOrganizations({
'Authorization': `Bearer ${authToken}`
});
if (response.data && response.data.organizations) {
this.organizations = response.data.organizations;
}
} catch (error) {
this.error = error.message || 'Failed to load organizations';
throw error;
} finally {
this.isLoading = false;
}
},
async createOrganization(data: CreateOrganizationRequest, authToken: string) {
this.isLoading = true;
this.error = null;
try {
const response: OrganizationSuccessResponse = await OrganizationService.createOrganization(data, {
'Authorization': `Bearer ${authToken}`
});
if (response) {
this.organizations.push(response);
return response;
}
} catch (error) {
this.error = error.message || 'Failed to create organization';
throw error;
} finally {
this.isLoading = false;
}
},
async updateOrganization(id: string, data: UpdateOrganizationRequest, authToken: string) {
this.isLoading = true;
this.error = null;
try {
const response: OrganizationSuccessResponse = await OrganizationService.updateOrganization(id, data, {
'Authorization': `Bearer ${authToken}`
});
if (response) {
const index = this.organizations.findIndex(org => org.id === id);
if (index !== -1) {
this.organizations[index] = response;
}
return response;
}
} catch (error) {
this.error = error.message || 'Failed to update organization';
throw error;
} finally {
this.isLoading = false;
}
}
}
});3. Component Usage with Pinia
<!-- components/OrganizationList.vue -->
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useOrganizationStore } from '../stores/organizationStore';
import { useAuthStore } from '../stores/authStore';
const organizationStore = useOrganizationStore();
const authStore = useAuthStore();
onMounted(async () => {
if (authStore.isAuthenticated) {
await organizationStore.loadOrganizations(authStore.token);
}
});
const newOrganizationName = ref('');
async function handleCreateOrganization() {
if (!newOrganizationName.value.trim()) return;
try {
await organizationStore.createOrganization(
{ name: newOrganizationName.value },
authStore.token
);
newOrganizationName.value = '';
} catch (error) {
console.error('Failed to create organization:', error);
}
}
</script>
<template>
<div class="organization-list">
<div v-if="organizationStore.isLoading">Loading organizations...</div>
<div v-else-if="organizationStore.error" class="error">
{{ organizationStore.error }}
</div>
<div v-else>
<h3>Organizations</h3>
<ul>
<li v-for="org in organizationStore.organizations" :key="org.id">
{{ org.name }} - {{ org.description }}
</li>
</ul>
<div class="create-form">
<input v-model="newOrganizationName" placeholder="New organization name">
<button @click="handleCreateOrganization" :disabled="!newOrganizationName.trim()">
Create Organization
</button>
</div>
</div>
</div>
</template>Advanced Pinia Colada Integration
Plugin Registration and Global Configuration
First, register Pinia Colada in your main application file:
// main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { PiniaColada } from '@pinia/colada'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
// Register Pinia Colada plugin with global configuration
app.use(pinia)
app.use(PiniaColada, {
// Global request interceptor
onRequest: (request) => {
const token = localStorage.getItem('authToken')
if (token) {
request.headers = {
...request.headers,
Authorization: `Bearer ${token}`
}
}
return request
},
// Token refresh handler for 401 errors
onResponseError: async (error) => {
if (error.status === 401) {
// Handle token refresh logic here
const newToken = await refreshToken()
localStorage.setItem('authToken', newToken)
// The original request will be retried automatically
}
throw error
}
})
app.mount('#app')Component Usage with Pinia Colada
<script setup>
import { useQuery, useMutation } from '@pinia/colada'
import {
getOrganizations,
postOrganizations,
type CreateOrganizationRequest
} from '@deep-document-search/api-client-typescript-v2'
import { useAuthStore } from '../stores/authStore'
const authStore = useAuthStore()
// Query for organizations with automatic caching and typed response
const {
data: organizationsResponse,
isLoading,
error,
refetch
} = useQuery({
key: () => ['organizations', authStore.token], // Cache key includes token for different users
query: () => getOrganizations({
headers: { 'Authorization': `Bearer ${authStore.token}` }
}),
// Cache settings
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
})
// Extract organizations from response for cleaner usage
const organizations = organizationsResponse?.data?.organizations || [];
// Mutation for creating organizations
const createOrgMutation = useMutation({
mutation: (data: CreateOrganizationRequest) =>
postOrganizations({
body: data,
headers: { 'Authorization': `Bearer ${authStore.token}` }
}),
// Auto-invalidate related queries after mutation
onSuccess: () => {
// This will trigger a refetch of the organizations query
refetch()
}
})
async function handleCreate(name: string) {
await createOrgMutation.mutate({ name })
// organizations query will automatically refetch due to onSuccess
}
</script>
<template>
<div>
<div v-if="isLoading">Loading organizations...</div>
<div v-else-if="error" class="error">{{ error.message }}</div>
<div v-else>
<ul>
<li v-for="org in organizations" :key="org.id">
{{ org.name }}
</li>
</ul>
</div>
</div>
</template>Error Handling Best Practices
Centralized Error Handling
// utils/errorHandler.ts
export class ApiErrorHandler {
static handleApiError(error: any, context: string): string {
let userMessage = 'An unexpected error occurred';
if (error.status === 401) {
userMessage = 'Authentication required. Please log in again.';
// Trigger logout flow
this.handleUnauthorized();
} else if (error.status === 403) {
userMessage = 'You do not have permission to perform this action.';
} else if (error.status === 404) {
userMessage = 'The requested resource was not found.';
} else if (error.data?.message) {
userMessage = error.data.message;
}
console.error(`API Error in ${context}:`, error);
return userMessage;
}
static handleUnauthorized() {
// Clear auth state and redirect to login
localStorage.removeItem('authToken');
window.location.href = '/login';
}
}
// Usage in store
async function loadOrganizations(authToken: string) {
try {
const response = await OrganizationService.listOrganizations({
'Authorization': `Bearer ${authToken}`
});
return response.data?.organizations || [];
} catch (error) {
const message = ApiErrorHandler.handleApiError(error, 'loading organizations');
throw new Error(message);
}
}Performance Optimization
Request Batching
// Batch multiple related requests
async function loadDashboardData(authToken: string) {
const headers = { 'Authorization': `Bearer ${authToken}` };
const [organizations, projects, documents] = await Promise.all([
getOrganizations({ headers }),
getWorkspaceProjects({ headers }),
getWorkspaceDocuments({ headers })
]);
return {
organizations: organizations.data?.organizations || [],
projects: projects.data?.projects || [],
documents: documents.data?.documents || []
};
}Optimistic Updates
// Store with optimistic updates
async updateOrganization(id: string, data: UpdateOrganizationRequest, authToken: string) {
// Optimistically update UI
const original = this.organizations.find(org => org.id === id);
if (original) {
const optimistic = { ...original, ...data };
this.organizations = this.organizations.map(org =>
org.id === id ? optimistic : org
);
}
try {
const response = await OrganizationService.updateOrganization(id, data, {
'Authorization': `Bearer ${authToken}`
});
// Update with server response
if (response.data) {
this.organizations = this.organizations.map(org =>
org.id === id ? response.data! : org
);
}
} catch (error) {
// Revert optimistic update on error
if (original) {
this.organizations = this.organizations.map(org =>
org.id === id ? original : org
);
}
throw error;
}
}This architecture provides excellent separation of concerns, type safety, and maintainability for Vue/Pinia applications.
Pinia Colada Deep Dive
How Pinia Colada Actually Works
Pinia Colada is not a standalone object but a Pinia plugin that provides intelligent data fetching capabilities. Here's the actual architecture:
Architecture Flow
Your Components → useQuery/useMutation hooks → Internal Pinia Colada Cache → API Calls
↓
Pinia DevTools (for debugging)Key Concepts Explained
- Plugin Registration: Pinia Colada registers itself as a Pinia plugin
- Internal Cache: Creates a query cache inside Pinia's store system
- Hook Access: Components use
useQuery/useMutationto access the cache - Automatic Integration: All query states are visible in Pinia DevTools
Real Usage Pattern (Corrected)
// ✅ Correct: Register once, use hooks everywhere
// main.ts
app.use(PiniaColada)
// Component.vue
import { useQuery } from '@pinia/colada'
const { data, isLoading } = useQuery({
key: ['data'],
query: fetchData // Uses the registered Pinia Colada instance
})Common Misconceptions Clarified
Myth: "I need to create a colada object" Truth: Pinia Colada is a singleton plugin - you register it once and use hooks
Myth: "The colada object is used directly"
Truth: You interact through useQuery/useMutation hooks
Myth: "I need to manage cache manually" Truth: Cache management is automatic through query keys and invalidation
Advanced Pinia Colada Patterns
Store Integration Pattern
// stores/organizationStore.ts
import { defineStore } from 'pinia'
import { defineQuery, defineMutation } from '@pinia/colada'
export const useOrganizationStore = defineStore('organizations', () => {
// Define reusable queries that automatically use Pinia Colada cache
const fetchOrganizations = defineQuery({
key: () => ['organizations'],
query: () => getOrganizations({ headers })
})
const createOrganization = defineMutation({
mutation: (data) => postOrganizations({ body: data, headers }),
onSuccess: () => {
// Auto-invalidate organizations query
}
})
return { fetchOrganizations, createOrganization }
})
// Usage in component
const orgStore = useOrganizationStore()
const { data, isLoading } = orgStore.fetchOrganizations()Dynamic Query Patterns
// Dynamic queries based on route parameters
const route = useRoute()
const { data: user } = useQuery({
key: () => ['user', route.params.id],
query: () => getUserById(route.params.id)
})
// Paginated queries
const { data: paginatedData } = useQuery({
key: () => ['items', currentPage.value],
query: () => getItems({ page: currentPage.value })
})This architecture provides a seamless data fetching experience without manual cache management.
Publishing the Package
When publishing this package to npm, only the compiled code is included, not the source code. The package is configured to publish only the dist directory and README.md.
Publishing Configuration
The package.json is configured with:
{
"files": [
"dist",
"README.md"
],
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts"
}This ensures that:
- Only compiled JavaScript files are published (from
dist/directory) - TypeScript definitions are included for type safety
- Source code (
src/) is excluded from the published package
Publishing Steps
- Build the package:
npm run build- Update version (if needed):
npm version patch # or minor, major- Publish to npm:
npm publish --access publicFile Structure in Published Package
The published package will contain:
dist/
├── client/
│ ├── index.js # Main entry point
│ ├── index.d.ts # Type definitions
│ ├── sdk.gen.js # API methods
│ ├── sdk.gen.d.ts # API method types
│ ├── types.gen.js # Type implementations
│ ├── types.gen.d.ts # Type definitions
│ └── ...other files
README.mdCreated Files
scripts/generate-llm-txt.ts - LLM-friendly documentation generator that:
- Parses the OpenAPI spec from swagger.yaml
- Generates structured text optimized for LLM consumption
- Includes API endpoints, type definitions, authentication info, and usage examples
- Outputs to llm.txt in the project root
typedoc.json - TypeDoc configuration for API documentation
Updated Files
package.json - Added new scripts:
- npm run docs:generate - Generate llm.txt
- npm run docs:api - Generate TypeDoc HTML documentation
- npm run docs:all - Generate both
Added dependencies:
- tsx - TypeScript execution
- typedoc - API documentation
- yaml - YAML parsing
Benefits of Publishing Only Compiled Code
- Smaller package size: No source code, tests, or development files
- Better security: Source code remains private
- Faster downloads: Users download only what they need
- TypeScript support: Full type definitions included
Development
Regenerating the Client
npm run generateThis will regenerate the client from the OpenAPI specification file (swagger.yaml).
Building
npm run buildDevelopment Mode (Watch)
npm run devLicense
MIT
