@vc-shell/create-vc-app 1.1.99-alpha.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -552
- package/dist/index.js +530 -1900
- package/dist/templates/base/_package.json +5 -5
- package/dist/templates/base/src/main.ts +4 -0
- package/dist/templates/mocks/sample-data/constants.ts +89 -0
- package/dist/templates/mocks/sample-data/index.ts +2 -0
- package/dist/templates/mocks/sample-data/methods.ts +65 -0
- package/dist/templates/modules/classic-module/composables/index.ts +2 -0
- package/dist/templates/modules/classic-module/composables/use{{ModuleNamePascalCase}}Details/index.ts +24 -0
- package/dist/templates/modules/classic-module/composables/use{{ModuleNamePascalCase}}List/index.ts +47 -0
- package/dist/templates/modules/classic-module/index.ts +8 -0
- package/dist/templates/modules/classic-module/locales/en.json +37 -0
- package/dist/templates/modules/classic-module/locales/index.ts +2 -0
- package/dist/templates/modules/classic-module/pages/details.vue +87 -0
- package/dist/templates/modules/classic-module/pages/index.ts +2 -0
- package/dist/templates/modules/classic-module/pages/list.vue +257 -0
- package/dist/templates/sample/classic-module/composables/index.ts +2 -0
- package/dist/templates/sample/classic-module/composables/useDetails/index.ts +54 -0
- package/dist/templates/sample/classic-module/composables/useList/index.ts +62 -0
- package/dist/templates/sample/classic-module/index.ts +8 -0
- package/dist/templates/sample/classic-module/locales/en.json +67 -0
- package/dist/templates/sample/classic-module/locales/index.ts +2 -0
- package/dist/templates/sample/classic-module/pages/details.vue +238 -0
- package/dist/templates/sample/classic-module/pages/index.ts +2 -0
- package/dist/templates/sample/classic-module/pages/list.vue +300 -0
- package/dist/templates/sample/overrides/main.ts +52 -0
- package/package.json +7 -12
- package/dist/cli/argv.d.ts +0 -4
- package/dist/cli/argv.d.ts.map +0 -1
- package/dist/cli/constants.d.ts +0 -4
- package/dist/cli/constants.d.ts.map +0 -1
- package/dist/cli/errors.d.ts +0 -12
- package/dist/cli/errors.d.ts.map +0 -1
- package/dist/cli/help.d.ts +0 -3
- package/dist/cli/help.d.ts.map +0 -1
- package/dist/cli/run.d.ts +0 -2
- package/dist/cli/run.d.ts.map +0 -1
- package/dist/cli/runtime.d.ts +0 -7
- package/dist/cli/runtime.d.ts.map +0 -1
- package/dist/cli/types.d.ts +0 -30
- package/dist/cli/types.d.ts.map +0 -1
- package/dist/cli/utils.d.ts +0 -4
- package/dist/cli/utils.d.ts.map +0 -1
- package/dist/cli/validation.d.ts +0 -5
- package/dist/cli/validation.d.ts.map +0 -1
- package/dist/commands/generate-blade.d.ts +0 -16
- package/dist/commands/generate-blade.d.ts.map +0 -1
- package/dist/templates/base/ai-guides/.cursorrules-vc-shell +0 -529
- package/dist/templates/base/ai-guides/README.md +0 -360
- package/dist/templates/base/ai-guides/guides/AI_GUIDE.md +0 -195
- package/dist/templates/base/ai-guides/guides/blade-patterns.md +0 -384
- package/dist/templates/base/ai-guides/guides/complete-workflow.md +0 -781
- package/dist/templates/base/ai-guides/guides/composables-reference.md +0 -338
- package/dist/templates/base/ai-guides/guides/troubleshooting.md +0 -529
- package/dist/templates/base/ai-guides/guides/ui-components-reference.md +0 -903
- package/dist/templates/base/ai-guides/prompts/adapt-existing-module.md +0 -1026
- package/dist/templates/base/ai-guides/prompts/advanced-scenarios.md +0 -852
- package/dist/templates/base/ai-guides/prompts/api-client-generation.md +0 -877
- package/dist/templates/base/ai-guides/prompts/cli-usage.md +0 -640
- package/dist/templates/base/ai-guides/prompts/quick-start-scenarios.md +0 -773
- package/dist/templates/base/ai-guides/prompts/simple-modifications.md +0 -987
- package/dist/templates/blades/details/blade.vue +0 -175
- package/dist/templates/blades/grid/blade.vue +0 -340
- package/dist/templates/composables/details-composable.ts +0 -101
- package/dist/templates/composables/grid-composable.ts +0 -244
- package/dist/templates/module/components/index.ts +0 -2
- package/dist/templates/module/components/widgets/index.ts +0 -2
- package/dist/templates/module/composables/index.ts +0 -3
- package/dist/templates/module/index.ts +0 -13
- package/dist/templates/module/locales/en.json +0 -65
- package/dist/templates/module/locales/index.ts +0 -4
- package/dist/templates/module/pages/index.ts +0 -3
- package/dist/templates/widgets/widget.vue +0 -113
- package/dist/utils/form-builder.d.ts +0 -69
- package/dist/utils/form-builder.d.ts.map +0 -1
- package/dist/utils/format.d.ts +0 -24
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/naming.d.ts +0 -44
- package/dist/utils/naming.d.ts.map +0 -1
- package/dist/utils/register-module.d.ts +0 -21
- package/dist/utils/register-module.d.ts.map +0 -1
- package/dist/workflows/create-app.d.ts +0 -14
- package/dist/workflows/create-app.d.ts.map +0 -1
|
@@ -1,877 +0,0 @@
|
|
|
1
|
-
# API Client Generation Guide
|
|
2
|
-
|
|
3
|
-
Complete guide for generating and using API clients in VC Shell applications.
|
|
4
|
-
|
|
5
|
-
## When to Use This
|
|
6
|
-
|
|
7
|
-
Use these prompts when you need to:
|
|
8
|
-
- Connect your module to a backend API
|
|
9
|
-
- Generate TypeScript API clients from OpenAPI/Swagger
|
|
10
|
-
- Integrate with VirtoCommerce Platform
|
|
11
|
-
- Use custom REST APIs
|
|
12
|
-
|
|
13
|
-
## Prerequisites
|
|
14
|
-
|
|
15
|
-
- VC Shell application created with `create-vc-app`
|
|
16
|
-
- Node.js 18 or higher
|
|
17
|
-
- Access to API endpoint or OpenAPI specification
|
|
18
|
-
- Backend URL and authentication details
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Quick Start
|
|
23
|
-
|
|
24
|
-
### Step 1: Configure Environment
|
|
25
|
-
|
|
26
|
-
**Prompt for AI:**
|
|
27
|
-
```
|
|
28
|
-
Configure my VC Shell app to connect to the API at https://my-backend.com
|
|
29
|
-
|
|
30
|
-
Setup:
|
|
31
|
-
- API URL: https://my-backend.com
|
|
32
|
-
- Platform modules: Virtocommerce.Catalog, Virtocommerce.Orders
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
**AI will create/update `.env.local`:**
|
|
36
|
-
```env
|
|
37
|
-
APP_PLATFORM_URL=https://my-backend.com
|
|
38
|
-
APP_PLATFORM_MODULES=[Virtocommerce.Catalog, Virtocommerce.Orders]
|
|
39
|
-
APP_API_CLIENT_DIRECTORY=./src/api_client/
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
### Step 2: Generate API Client
|
|
45
|
-
|
|
46
|
-
**Prompt for AI:**
|
|
47
|
-
```
|
|
48
|
-
Generate API client using the configured platform URL.
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**AI will run:**
|
|
52
|
-
```bash
|
|
53
|
-
yarn generate-api-client
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
**Expected output:**
|
|
57
|
-
```
|
|
58
|
-
✓ Fetching API specifications...
|
|
59
|
-
✓ Generating TypeScript clients...
|
|
60
|
-
✓ Building API client package...
|
|
61
|
-
✓ API client generated successfully!
|
|
62
|
-
|
|
63
|
-
Generated clients:
|
|
64
|
-
- src/api_client/virtocommerce.catalog
|
|
65
|
-
- src/api_client/virtocommerce.orders
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
### Step 3: Use Generated Client
|
|
71
|
-
|
|
72
|
-
**Prompt for AI:**
|
|
73
|
-
```
|
|
74
|
-
Update the products module to use the generated Catalog API client.
|
|
75
|
-
|
|
76
|
-
Operations needed:
|
|
77
|
-
- Load products list in grid blade
|
|
78
|
-
- Load single product in details blade
|
|
79
|
-
- Save product (create/update)
|
|
80
|
-
- Delete product
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**AI will update composables:**
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
// src/modules/products/composables/useProductList.ts
|
|
87
|
-
import { useApiClient } from '@vc-shell/framework';
|
|
88
|
-
import { Catalog } from '../../../api_client/virtocommerce.catalog';
|
|
89
|
-
|
|
90
|
-
export function useProductList() {
|
|
91
|
-
const { getApiClient } = useApiClient(Catalog);
|
|
92
|
-
|
|
93
|
-
const { action: loadProducts, loading, items } = useAsync(async () => {
|
|
94
|
-
const client = await getApiClient();
|
|
95
|
-
const response = await client.searchProducts({
|
|
96
|
-
searchPhrase: searchQuery.value,
|
|
97
|
-
skip: (currentPage.value - 1) * pageSize.value,
|
|
98
|
-
take: pageSize.value
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
results: response.data.results || [],
|
|
103
|
-
totalCount: response.data.totalCount || 0
|
|
104
|
-
};
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
loadProducts,
|
|
109
|
-
loading,
|
|
110
|
-
items
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## Detailed Examples
|
|
118
|
-
|
|
119
|
-
### Example 1: VirtoCommerce Platform Integration
|
|
120
|
-
|
|
121
|
-
**Scenario:** Connect to VirtoCommerce Platform API
|
|
122
|
-
|
|
123
|
-
**Prompt for AI:**
|
|
124
|
-
```
|
|
125
|
-
Configure API client for VirtoCommerce Platform.
|
|
126
|
-
|
|
127
|
-
Platform details:
|
|
128
|
-
- URL: https://demo.virtocommerce.com
|
|
129
|
-
- Modules needed:
|
|
130
|
-
- Virtocommerce.Catalog (products, categories)
|
|
131
|
-
- Virtocommerce.Orders (orders management)
|
|
132
|
-
- Virtocommerce.Customer (customer data)
|
|
133
|
-
- Virtocommerce.Inventory (stock management)
|
|
134
|
-
|
|
135
|
-
Generate clients and show me how to use them in my modules.
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
**AI will:**
|
|
139
|
-
|
|
140
|
-
1. **Update `.env.local`:**
|
|
141
|
-
```env
|
|
142
|
-
APP_PLATFORM_URL=https://demo.virtocommerce.com
|
|
143
|
-
APP_PLATFORM_MODULES=[Virtocommerce.Catalog, Virtocommerce.Orders, Virtocommerce.Customer, Virtocommerce.Inventory]
|
|
144
|
-
APP_API_CLIENT_DIRECTORY=./src/api_client/
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
2. **Update `package.json` (if not exists):**
|
|
148
|
-
```json
|
|
149
|
-
{
|
|
150
|
-
"scripts": {
|
|
151
|
-
"generate-api-client": "cross-env api-client-generator"
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
3. **Run generation:**
|
|
157
|
-
```bash
|
|
158
|
-
yarn generate-api-client
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
4. **Create example usage:**
|
|
162
|
-
```typescript
|
|
163
|
-
// Example: Products composable
|
|
164
|
-
import { useApiClient } from '@vc-shell/framework';
|
|
165
|
-
import { Catalog } from '../../../api_client/virtocommerce.catalog';
|
|
166
|
-
|
|
167
|
-
const { getApiClient } = useApiClient(Catalog);
|
|
168
|
-
const client = await getApiClient();
|
|
169
|
-
|
|
170
|
-
// Search products
|
|
171
|
-
const products = await client.searchProducts({
|
|
172
|
-
searchPhrase: 'laptop',
|
|
173
|
-
skip: 0,
|
|
174
|
-
take: 20
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// Get product by ID
|
|
178
|
-
const product = await client.getProductById({ id: 'prod-123' });
|
|
179
|
-
|
|
180
|
-
// Update product
|
|
181
|
-
await client.updateProduct({
|
|
182
|
-
product: updatedProductData
|
|
183
|
-
});
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
### Example 2: Custom REST API Integration
|
|
189
|
-
|
|
190
|
-
**Scenario:** Connect to your own REST API (not VirtoCommerce Platform)
|
|
191
|
-
|
|
192
|
-
**Prompt for AI:**
|
|
193
|
-
```
|
|
194
|
-
I have a custom REST API at https://api.myapp.com
|
|
195
|
-
|
|
196
|
-
Endpoints:
|
|
197
|
-
- GET /api/products - List products
|
|
198
|
-
- GET /api/products/{id} - Get product
|
|
199
|
-
- POST /api/products - Create product
|
|
200
|
-
- PUT /api/products/{id} - Update product
|
|
201
|
-
- DELETE /api/products/{id} - Delete product
|
|
202
|
-
|
|
203
|
-
Authentication: Bearer token in Authorization header
|
|
204
|
-
|
|
205
|
-
Create API integration without using the platform generator.
|
|
206
|
-
Use fetch or axios directly.
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
**AI will create custom API service:**
|
|
210
|
-
|
|
211
|
-
```typescript
|
|
212
|
-
// src/api_client/custom-api.ts
|
|
213
|
-
const API_BASE_URL = import.meta.env.VITE_API_URL || 'https://api.myapp.com';
|
|
214
|
-
|
|
215
|
-
interface Product {
|
|
216
|
-
id: string;
|
|
217
|
-
name: string;
|
|
218
|
-
price: number;
|
|
219
|
-
description?: string;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
interface ProductSearchResponse {
|
|
223
|
-
data: Product[];
|
|
224
|
-
total: number;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async function getAuthHeaders(): Promise<HeadersInit> {
|
|
228
|
-
// Get token from your auth system
|
|
229
|
-
const token = localStorage.getItem('auth_token');
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
'Content-Type': 'application/json',
|
|
233
|
-
'Authorization': `Bearer ${token}`
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export const customApi = {
|
|
238
|
-
async getProducts(params: { skip: number; take: number; search?: string }): Promise<ProductSearchResponse> {
|
|
239
|
-
const headers = await getAuthHeaders();
|
|
240
|
-
const query = new URLSearchParams({
|
|
241
|
-
skip: params.skip.toString(),
|
|
242
|
-
take: params.take.toString(),
|
|
243
|
-
...(params.search && { search: params.search })
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
const response = await fetch(`${API_BASE_URL}/api/products?${query}`, {
|
|
247
|
-
headers
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
if (!response.ok) {
|
|
251
|
-
throw new Error(`API Error: ${response.statusText}`);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return response.json();
|
|
255
|
-
},
|
|
256
|
-
|
|
257
|
-
async getProductById(id: string): Promise<Product> {
|
|
258
|
-
const headers = await getAuthHeaders();
|
|
259
|
-
const response = await fetch(`${API_BASE_URL}/api/products/${id}`, {
|
|
260
|
-
headers
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
if (!response.ok) {
|
|
264
|
-
throw new Error(`API Error: ${response.statusText}`);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return response.json();
|
|
268
|
-
},
|
|
269
|
-
|
|
270
|
-
async createProduct(product: Omit<Product, 'id'>): Promise<Product> {
|
|
271
|
-
const headers = await getAuthHeaders();
|
|
272
|
-
const response = await fetch(`${API_BASE_URL}/api/products`, {
|
|
273
|
-
method: 'POST',
|
|
274
|
-
headers,
|
|
275
|
-
body: JSON.stringify(product)
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
if (!response.ok) {
|
|
279
|
-
throw new Error(`API Error: ${response.statusText}`);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return response.json();
|
|
283
|
-
},
|
|
284
|
-
|
|
285
|
-
async updateProduct(id: string, product: Partial<Product>): Promise<Product> {
|
|
286
|
-
const headers = await getAuthHeaders();
|
|
287
|
-
const response = await fetch(`${API_BASE_URL}/api/products/${id}`, {
|
|
288
|
-
method: 'PUT',
|
|
289
|
-
headers,
|
|
290
|
-
body: JSON.stringify(product)
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
if (!response.ok) {
|
|
294
|
-
throw new Error(`API Error: ${response.statusText}`);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return response.json();
|
|
298
|
-
},
|
|
299
|
-
|
|
300
|
-
async deleteProduct(id: string): Promise<void> {
|
|
301
|
-
const headers = await getAuthHeaders();
|
|
302
|
-
const response = await fetch(`${API_BASE_URL}/api/products/${id}`, {
|
|
303
|
-
method: 'DELETE',
|
|
304
|
-
headers
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
if (!response.ok) {
|
|
308
|
-
throw new Error(`API Error: ${response.statusText}`);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
**Usage in composable:**
|
|
315
|
-
```typescript
|
|
316
|
-
// src/modules/products/composables/useProductList.ts
|
|
317
|
-
import { useAsync } from '@vc-shell/framework';
|
|
318
|
-
import { customApi } from '../../../api_client/custom-api';
|
|
319
|
-
|
|
320
|
-
export function useProductList() {
|
|
321
|
-
const { action: loadProducts, loading, items } = useAsync(async () => {
|
|
322
|
-
const response = await customApi.getProducts({
|
|
323
|
-
skip: (currentPage.value - 1) * pageSize.value,
|
|
324
|
-
take: pageSize.value,
|
|
325
|
-
search: searchQuery.value
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
return {
|
|
329
|
-
results: response.data,
|
|
330
|
-
totalCount: response.total
|
|
331
|
-
};
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
return {
|
|
335
|
-
loadProducts,
|
|
336
|
-
loading,
|
|
337
|
-
items
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
---
|
|
343
|
-
|
|
344
|
-
### Example 3: GraphQL API Integration
|
|
345
|
-
|
|
346
|
-
**Scenario:** Connect to GraphQL API
|
|
347
|
-
|
|
348
|
-
**Prompt for AI:**
|
|
349
|
-
```
|
|
350
|
-
Integrate with GraphQL API at https://api.myapp.com/graphql
|
|
351
|
-
|
|
352
|
-
Queries needed:
|
|
353
|
-
- products (search, pagination)
|
|
354
|
-
- product (by ID)
|
|
355
|
-
|
|
356
|
-
Mutations needed:
|
|
357
|
-
- createProduct
|
|
358
|
-
- updateProduct
|
|
359
|
-
- deleteProduct
|
|
360
|
-
|
|
361
|
-
Setup GraphQL client and create integration.
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
**AI will install dependencies and create client:**
|
|
365
|
-
|
|
366
|
-
```bash
|
|
367
|
-
yarn add graphql-request graphql
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
// src/api_client/graphql-client.ts
|
|
372
|
-
import { GraphQLClient } from 'graphql-request';
|
|
373
|
-
|
|
374
|
-
const endpoint = import.meta.env.VITE_GRAPHQL_URL || 'https://api.myapp.com/graphql';
|
|
375
|
-
|
|
376
|
-
const client = new GraphQLClient(endpoint, {
|
|
377
|
-
headers: {
|
|
378
|
-
authorization: `Bearer ${localStorage.getItem('auth_token')}`
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
export const graphqlApi = {
|
|
383
|
-
async getProducts(search: string, skip: number, take: number) {
|
|
384
|
-
const query = `
|
|
385
|
-
query GetProducts($search: String, $skip: Int, $take: Int) {
|
|
386
|
-
products(search: $search, skip: $skip, take: $take) {
|
|
387
|
-
items {
|
|
388
|
-
id
|
|
389
|
-
name
|
|
390
|
-
price
|
|
391
|
-
description
|
|
392
|
-
}
|
|
393
|
-
totalCount
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
`;
|
|
397
|
-
|
|
398
|
-
const data = await client.request(query, { search, skip, take });
|
|
399
|
-
return data.products;
|
|
400
|
-
},
|
|
401
|
-
|
|
402
|
-
async getProduct(id: string) {
|
|
403
|
-
const query = `
|
|
404
|
-
query GetProduct($id: ID!) {
|
|
405
|
-
product(id: $id) {
|
|
406
|
-
id
|
|
407
|
-
name
|
|
408
|
-
price
|
|
409
|
-
description
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
`;
|
|
413
|
-
|
|
414
|
-
const data = await client.request(query, { id });
|
|
415
|
-
return data.product;
|
|
416
|
-
},
|
|
417
|
-
|
|
418
|
-
async createProduct(input: any) {
|
|
419
|
-
const mutation = `
|
|
420
|
-
mutation CreateProduct($input: ProductInput!) {
|
|
421
|
-
createProduct(input: $input) {
|
|
422
|
-
id
|
|
423
|
-
name
|
|
424
|
-
price
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
`;
|
|
428
|
-
|
|
429
|
-
const data = await client.request(mutation, { input });
|
|
430
|
-
return data.createProduct;
|
|
431
|
-
},
|
|
432
|
-
|
|
433
|
-
async updateProduct(id: string, input: any) {
|
|
434
|
-
const mutation = `
|
|
435
|
-
mutation UpdateProduct($id: ID!, $input: ProductInput!) {
|
|
436
|
-
updateProduct(id: $id, input: $input) {
|
|
437
|
-
id
|
|
438
|
-
name
|
|
439
|
-
price
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
`;
|
|
443
|
-
|
|
444
|
-
const data = await client.request(mutation, { id, input });
|
|
445
|
-
return data.updateProduct;
|
|
446
|
-
},
|
|
447
|
-
|
|
448
|
-
async deleteProduct(id: string) {
|
|
449
|
-
const mutation = `
|
|
450
|
-
mutation DeleteProduct($id: ID!) {
|
|
451
|
-
deleteProduct(id: $id)
|
|
452
|
-
}
|
|
453
|
-
`;
|
|
454
|
-
|
|
455
|
-
await client.request(mutation, { id });
|
|
456
|
-
}
|
|
457
|
-
};
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
---
|
|
461
|
-
|
|
462
|
-
### Example 4: Update Existing Module with API
|
|
463
|
-
|
|
464
|
-
**Scenario:** You have a generated module, need to connect it to API
|
|
465
|
-
|
|
466
|
-
**Prompt for AI:**
|
|
467
|
-
```
|
|
468
|
-
I have a products module generated with create-vc-app.
|
|
469
|
-
Connect it to my API at https://api.shop.com
|
|
470
|
-
|
|
471
|
-
API structure:
|
|
472
|
-
- GET /products?page={page}&limit={limit}&search={query}
|
|
473
|
-
Response: { data: Product[], total: number }
|
|
474
|
-
|
|
475
|
-
- GET /products/{id}
|
|
476
|
-
Response: Product
|
|
477
|
-
|
|
478
|
-
- POST /products
|
|
479
|
-
Body: Product (without id)
|
|
480
|
-
Response: Product
|
|
481
|
-
|
|
482
|
-
- PUT /products/{id}
|
|
483
|
-
Body: Product
|
|
484
|
-
Response: Product
|
|
485
|
-
|
|
486
|
-
- DELETE /products/{id}
|
|
487
|
-
Response: 204
|
|
488
|
-
|
|
489
|
-
Replace all TODO comments in composables with actual API calls.
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
**AI will update:**
|
|
493
|
-
|
|
494
|
-
**1. Create API client:**
|
|
495
|
-
```typescript
|
|
496
|
-
// src/api_client/shop-api.ts
|
|
497
|
-
const API_URL = 'https://api.shop.com';
|
|
498
|
-
|
|
499
|
-
export const shopApi = {
|
|
500
|
-
async getProducts(page: number, limit: number, search?: string) {
|
|
501
|
-
const params = new URLSearchParams({
|
|
502
|
-
page: page.toString(),
|
|
503
|
-
limit: limit.toString(),
|
|
504
|
-
...(search && { search })
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
const response = await fetch(`${API_URL}/products?${params}`);
|
|
508
|
-
return response.json();
|
|
509
|
-
},
|
|
510
|
-
|
|
511
|
-
async getProduct(id: string) {
|
|
512
|
-
const response = await fetch(`${API_URL}/products/${id}`);
|
|
513
|
-
return response.json();
|
|
514
|
-
},
|
|
515
|
-
|
|
516
|
-
async createProduct(product: any) {
|
|
517
|
-
const response = await fetch(`${API_URL}/products`, {
|
|
518
|
-
method: 'POST',
|
|
519
|
-
headers: { 'Content-Type': 'application/json' },
|
|
520
|
-
body: JSON.stringify(product)
|
|
521
|
-
});
|
|
522
|
-
return response.json();
|
|
523
|
-
},
|
|
524
|
-
|
|
525
|
-
async updateProduct(id: string, product: any) {
|
|
526
|
-
const response = await fetch(`${API_URL}/products/${id}`, {
|
|
527
|
-
method: 'PUT',
|
|
528
|
-
headers: { 'Content-Type': 'application/json' },
|
|
529
|
-
body: JSON.stringify(product)
|
|
530
|
-
});
|
|
531
|
-
return response.json();
|
|
532
|
-
},
|
|
533
|
-
|
|
534
|
-
async deleteProduct(id: string) {
|
|
535
|
-
await fetch(`${API_URL}/products/${id}`, {
|
|
536
|
-
method: 'DELETE'
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
};
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
**2. Update list composable:**
|
|
543
|
-
```typescript
|
|
544
|
-
// src/modules/products/composables/useProductsList.ts
|
|
545
|
-
import { shopApi } from '../../../api_client/shop-api';
|
|
546
|
-
|
|
547
|
-
// Replace TODO with:
|
|
548
|
-
const { action: loadProducts, loading, items } = useAsync(async () => {
|
|
549
|
-
const response = await shopApi.getProducts(
|
|
550
|
-
currentPage.value,
|
|
551
|
-
pageSize.value,
|
|
552
|
-
searchQuery.value
|
|
553
|
-
);
|
|
554
|
-
|
|
555
|
-
return {
|
|
556
|
-
results: response.data,
|
|
557
|
-
totalCount: response.total
|
|
558
|
-
};
|
|
559
|
-
});
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
**3. Update details composable:**
|
|
563
|
-
```typescript
|
|
564
|
-
// src/modules/products/composables/useProductDetails.ts
|
|
565
|
-
import { shopApi } from '../../../api_client/shop-api';
|
|
566
|
-
|
|
567
|
-
// Load product
|
|
568
|
-
const loadProduct = async (id: string) => {
|
|
569
|
-
const product = await shopApi.getProduct(id);
|
|
570
|
-
item.value = product;
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
// Save product
|
|
574
|
-
const saveChanges = async () => {
|
|
575
|
-
if (item.value.id) {
|
|
576
|
-
await shopApi.updateProduct(item.value.id, item.value);
|
|
577
|
-
} else {
|
|
578
|
-
const created = await shopApi.createProduct(item.value);
|
|
579
|
-
item.value = created;
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
// Delete product
|
|
584
|
-
const deleteProduct = async () => {
|
|
585
|
-
if (item.value.id) {
|
|
586
|
-
await shopApi.deleteProduct(item.value.id);
|
|
587
|
-
}
|
|
588
|
-
};
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
---
|
|
592
|
-
|
|
593
|
-
## Configuration Options
|
|
594
|
-
|
|
595
|
-
### Environment Variables
|
|
596
|
-
|
|
597
|
-
**Required variables in `.env.local`:**
|
|
598
|
-
```env
|
|
599
|
-
# For VirtoCommerce Platform
|
|
600
|
-
APP_PLATFORM_URL=https://platform-url.com
|
|
601
|
-
APP_PLATFORM_MODULES=[Module1, Module2]
|
|
602
|
-
APP_API_CLIENT_DIRECTORY=./src/api_client/
|
|
603
|
-
|
|
604
|
-
# For custom APIs
|
|
605
|
-
VITE_API_URL=https://api.myapp.com
|
|
606
|
-
VITE_GRAPHQL_URL=https://api.myapp.com/graphql
|
|
607
|
-
```
|
|
608
|
-
|
|
609
|
-
### package.json Script
|
|
610
|
-
|
|
611
|
-
**If not already present, add:**
|
|
612
|
-
```json
|
|
613
|
-
{
|
|
614
|
-
"scripts": {
|
|
615
|
-
"generate-api-client": "cross-env api-client-generator"
|
|
616
|
-
},
|
|
617
|
-
"devDependencies": {
|
|
618
|
-
"@vc-shell/api-client-generator": "latest",
|
|
619
|
-
"cross-env": "latest"
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
---
|
|
625
|
-
|
|
626
|
-
## Error Handling
|
|
627
|
-
|
|
628
|
-
### Pattern 1: Basic Error Handling
|
|
629
|
-
|
|
630
|
-
```typescript
|
|
631
|
-
import { notification } from '@vc-shell/framework';
|
|
632
|
-
|
|
633
|
-
const { action: loadProducts, loading, error } = useAsync(async () => {
|
|
634
|
-
try {
|
|
635
|
-
const response = await api.getProducts();
|
|
636
|
-
return response.data;
|
|
637
|
-
} catch (err) {
|
|
638
|
-
notification.error('Failed to load products', {
|
|
639
|
-
timeout: 5000
|
|
640
|
-
});
|
|
641
|
-
console.error('API Error:', err);
|
|
642
|
-
throw err;
|
|
643
|
-
}
|
|
644
|
-
});
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
### Pattern 2: Retry Logic
|
|
648
|
-
|
|
649
|
-
```typescript
|
|
650
|
-
const { action: loadProducts, loading } = useAsync(async () => {
|
|
651
|
-
let retries = 3;
|
|
652
|
-
|
|
653
|
-
while (retries > 0) {
|
|
654
|
-
try {
|
|
655
|
-
const response = await api.getProducts();
|
|
656
|
-
return response.data;
|
|
657
|
-
} catch (err) {
|
|
658
|
-
retries--;
|
|
659
|
-
if (retries === 0) {
|
|
660
|
-
notification.error('Failed to load products after 3 attempts');
|
|
661
|
-
throw err;
|
|
662
|
-
}
|
|
663
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
});
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
### Pattern 3: Validation Errors
|
|
670
|
-
|
|
671
|
-
```typescript
|
|
672
|
-
const saveProduct = async () => {
|
|
673
|
-
try {
|
|
674
|
-
await api.updateProduct(item.value.id, item.value);
|
|
675
|
-
notification.success('Product saved successfully');
|
|
676
|
-
} catch (err: any) {
|
|
677
|
-
if (err.response?.status === 400) {
|
|
678
|
-
// Validation errors
|
|
679
|
-
const errors = err.response.data.errors;
|
|
680
|
-
notification.error('Validation failed', {
|
|
681
|
-
timeout: 5000
|
|
682
|
-
});
|
|
683
|
-
// Display field-specific errors
|
|
684
|
-
Object.keys(errors).forEach(field => {
|
|
685
|
-
console.error(`${field}: ${errors[field]}`);
|
|
686
|
-
});
|
|
687
|
-
} else {
|
|
688
|
-
notification.error('Failed to save product');
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
---
|
|
695
|
-
|
|
696
|
-
## Authentication Patterns
|
|
697
|
-
|
|
698
|
-
### Pattern 1: Bearer Token
|
|
699
|
-
|
|
700
|
-
```typescript
|
|
701
|
-
async function getAuthHeaders(): Promise<HeadersInit> {
|
|
702
|
-
const token = localStorage.getItem('auth_token');
|
|
703
|
-
|
|
704
|
-
return {
|
|
705
|
-
'Content-Type': 'application/json',
|
|
706
|
-
'Authorization': `Bearer ${token}`
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// Usage
|
|
711
|
-
const headers = await getAuthHeaders();
|
|
712
|
-
const response = await fetch(url, { headers });
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
### Pattern 2: API Key
|
|
716
|
-
|
|
717
|
-
```typescript
|
|
718
|
-
const headers = {
|
|
719
|
-
'Content-Type': 'application/json',
|
|
720
|
-
'X-API-Key': import.meta.env.VITE_API_KEY
|
|
721
|
-
};
|
|
722
|
-
```
|
|
723
|
-
|
|
724
|
-
### Pattern 3: OAuth 2.0
|
|
725
|
-
|
|
726
|
-
```typescript
|
|
727
|
-
import { useAuth } from '@vc-shell/framework';
|
|
728
|
-
|
|
729
|
-
const { getAccessToken } = useAuth();
|
|
730
|
-
|
|
731
|
-
async function getAuthHeaders(): Promise<HeadersInit> {
|
|
732
|
-
const token = await getAccessToken();
|
|
733
|
-
|
|
734
|
-
return {
|
|
735
|
-
'Content-Type': 'application/json',
|
|
736
|
-
'Authorization': `Bearer ${token}`
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
---
|
|
742
|
-
|
|
743
|
-
## Testing API Integration
|
|
744
|
-
|
|
745
|
-
### Manual Testing
|
|
746
|
-
|
|
747
|
-
**Prompt for AI:**
|
|
748
|
-
```
|
|
749
|
-
Create a test script to verify API connection.
|
|
750
|
-
|
|
751
|
-
Check:
|
|
752
|
-
- Can connect to API
|
|
753
|
-
- Can authenticate
|
|
754
|
-
- Can fetch data
|
|
755
|
-
- Can create/update/delete
|
|
756
|
-
|
|
757
|
-
Create a test file I can run with: node test-api.js
|
|
758
|
-
```
|
|
759
|
-
|
|
760
|
-
**AI will create:**
|
|
761
|
-
```javascript
|
|
762
|
-
// test-api.js
|
|
763
|
-
const API_URL = 'https://api.myapp.com';
|
|
764
|
-
|
|
765
|
-
async function testApi() {
|
|
766
|
-
console.log('Testing API connection...');
|
|
767
|
-
|
|
768
|
-
try {
|
|
769
|
-
// Test connection
|
|
770
|
-
const response = await fetch(`${API_URL}/health`);
|
|
771
|
-
console.log('✓ API is reachable');
|
|
772
|
-
|
|
773
|
-
// Test products endpoint
|
|
774
|
-
const products = await fetch(`${API_URL}/products?page=1&limit=10`);
|
|
775
|
-
const data = await products.json();
|
|
776
|
-
console.log(`✓ Products endpoint working (${data.total} products)`);
|
|
777
|
-
|
|
778
|
-
console.log('\nAll tests passed!');
|
|
779
|
-
} catch (err) {
|
|
780
|
-
console.error('✗ API test failed:', err.message);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
testApi();
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
---
|
|
788
|
-
|
|
789
|
-
## Common Issues and Solutions
|
|
790
|
-
|
|
791
|
-
### Issue 1: CORS Errors
|
|
792
|
-
|
|
793
|
-
**Error:** `Access-Control-Allow-Origin header is missing`
|
|
794
|
-
|
|
795
|
-
**Solution:**
|
|
796
|
-
```typescript
|
|
797
|
-
// For development, configure Vite proxy
|
|
798
|
-
// vite.config.mts
|
|
799
|
-
export default defineConfig({
|
|
800
|
-
server: {
|
|
801
|
-
proxy: {
|
|
802
|
-
'/api': {
|
|
803
|
-
target: 'https://api.myapp.com',
|
|
804
|
-
changeOrigin: true,
|
|
805
|
-
rewrite: (path) => path.replace(/^\/api/, '')
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
// Then use relative URLs
|
|
812
|
-
const response = await fetch('/api/products');
|
|
813
|
-
```
|
|
814
|
-
|
|
815
|
-
---
|
|
816
|
-
|
|
817
|
-
### Issue 2: Authentication Token Expired
|
|
818
|
-
|
|
819
|
-
**Solution:**
|
|
820
|
-
```typescript
|
|
821
|
-
async function fetchWithRetry(url: string, options: RequestInit) {
|
|
822
|
-
let response = await fetch(url, options);
|
|
823
|
-
|
|
824
|
-
if (response.status === 401) {
|
|
825
|
-
// Refresh token
|
|
826
|
-
await refreshAuthToken();
|
|
827
|
-
|
|
828
|
-
// Retry with new token
|
|
829
|
-
const newHeaders = await getAuthHeaders();
|
|
830
|
-
response = await fetch(url, {
|
|
831
|
-
...options,
|
|
832
|
-
headers: newHeaders
|
|
833
|
-
});
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
return response;
|
|
837
|
-
}
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
---
|
|
841
|
-
|
|
842
|
-
### Issue 3: API Client Generator Fails
|
|
843
|
-
|
|
844
|
-
**Error:** `Cannot connect to platform URL`
|
|
845
|
-
|
|
846
|
-
**Checklist:**
|
|
847
|
-
1. Verify URL is correct in `.env.local`
|
|
848
|
-
2. Check network connection
|
|
849
|
-
3. Verify platform modules exist
|
|
850
|
-
4. Try with `--VERBOSE=true` flag
|
|
851
|
-
|
|
852
|
-
```bash
|
|
853
|
-
cross-env VERBOSE=true yarn generate-api-client
|
|
854
|
-
```
|
|
855
|
-
|
|
856
|
-
---
|
|
857
|
-
|
|
858
|
-
## Next Steps
|
|
859
|
-
|
|
860
|
-
After setting up API integration:
|
|
861
|
-
|
|
862
|
-
1. **Test Endpoints:** Verify all CRUD operations work
|
|
863
|
-
2. **Add Error Handling:** Implement proper error handling
|
|
864
|
-
3. **Add Loading States:** Show loading indicators
|
|
865
|
-
4. **Add Validation:** Validate data before sending to API
|
|
866
|
-
5. **Add Caching:** Implement caching for better performance
|
|
867
|
-
6. **Monitor Performance:** Track API response times
|
|
868
|
-
|
|
869
|
-
---
|
|
870
|
-
|
|
871
|
-
## Related Documentation
|
|
872
|
-
|
|
873
|
-
- [CLI Usage Guide](./cli-usage.md) - Using create-vc-app
|
|
874
|
-
- [Quick Start Scenarios](./quick-start-scenarios.md) - Common patterns
|
|
875
|
-
- [Complete Workflow Guide](../guides/complete-workflow.md) - Full process
|
|
876
|
-
- [Official API Client Documentation](https://docs.virtocommerce.org/platform/developer-guide/custom-apps-development/vc-shell/Essentials/API-Integration/api-client-integration/)
|
|
877
|
-
|