@einja/dev-cli 0.1.13 → 0.1.15
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 +27 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +91 -11
- package/dist/commands/sync.js.map +1 -1
- package/dist/lib/sync/json-processor.d.ts +80 -0
- package/dist/lib/sync/json-processor.d.ts.map +1 -0
- package/dist/lib/sync/json-processor.js +167 -0
- package/dist/lib/sync/json-processor.js.map +1 -0
- package/dist/types/sync.d.ts +17 -0
- package/dist/types/sync.d.ts.map +1 -1
- package/dist/types/sync.js +10 -0
- package/dist/types/sync.js.map +1 -1
- package/package.json +1 -1
- package/presets/default/.claude/commands/einja/sync-cursor-commands.md +118 -43
- package/scaffolds/steering/development/api-development.md +57 -11
- package/scaffolds/steering/development/frontend-development.md +251 -104
|
@@ -43,52 +43,58 @@ Tanstack Query、React Hook Form、Hono Clientを活用した型安全で保守
|
|
|
43
43
|
|
|
44
44
|
```
|
|
45
45
|
apps/web/
|
|
46
|
-
├──
|
|
47
|
-
│ ├──
|
|
48
|
-
│ │ ├──
|
|
49
|
-
│ │ │
|
|
50
|
-
│ │ └──
|
|
51
|
-
│ │
|
|
52
|
-
│
|
|
53
|
-
│ │ ├──
|
|
54
|
-
│ │ │ ├──
|
|
55
|
-
│ │ │ ├──
|
|
56
|
-
│ │ │ │
|
|
57
|
-
│ │ │ └──
|
|
58
|
-
│ │ │
|
|
59
|
-
│ │ └──
|
|
60
|
-
│ │
|
|
61
|
-
│
|
|
62
|
-
│ │
|
|
63
|
-
│ │
|
|
64
|
-
│
|
|
65
|
-
│ └──
|
|
66
|
-
├──
|
|
67
|
-
│
|
|
68
|
-
│
|
|
69
|
-
│ │ ├──
|
|
70
|
-
│ │ ├──
|
|
71
|
-
│ │ ├──
|
|
72
|
-
│ │
|
|
73
|
-
│
|
|
74
|
-
│
|
|
75
|
-
│
|
|
76
|
-
│
|
|
77
|
-
│ │ ├──
|
|
78
|
-
│ │
|
|
79
|
-
│
|
|
80
|
-
│
|
|
81
|
-
│
|
|
82
|
-
├──
|
|
83
|
-
│
|
|
84
|
-
│ ├──
|
|
85
|
-
│
|
|
86
|
-
├──
|
|
87
|
-
│
|
|
88
|
-
│
|
|
46
|
+
├── src/
|
|
47
|
+
│ ├── app/ # Next.js App Router
|
|
48
|
+
│ │ ├── (auth)/ # ルートグループ: 認証関連
|
|
49
|
+
│ │ │ ├── login/
|
|
50
|
+
│ │ │ │ └── page.tsx
|
|
51
|
+
│ │ │ └── register/
|
|
52
|
+
│ │ │ └── page.tsx
|
|
53
|
+
│ │ ├── (dashboard)/ # ルートグループ: ダッシュボード
|
|
54
|
+
│ │ │ ├── posts/
|
|
55
|
+
│ │ │ │ ├── page.tsx # 投稿一覧
|
|
56
|
+
│ │ │ │ ├── new/
|
|
57
|
+
│ │ │ │ │ └── page.tsx # 投稿作成
|
|
58
|
+
│ │ │ │ └── [id]/
|
|
59
|
+
│ │ │ │ └── page.tsx # 投稿詳細
|
|
60
|
+
│ │ │ └── profile/
|
|
61
|
+
│ │ │ └── page.tsx
|
|
62
|
+
│ │ ├── api/ # API Routes
|
|
63
|
+
│ │ │ └── rpc/
|
|
64
|
+
│ │ │ └── [[...route]]/
|
|
65
|
+
│ │ │ └── route.ts # Honoエントリーポイント
|
|
66
|
+
│ │ ├── layout.tsx # ルートレイアウト
|
|
67
|
+
│ │ └── page.tsx # トップページ
|
|
68
|
+
│ ├── components/ # UIコンポーネント
|
|
69
|
+
│ │ ├── ui/ # 基本コンポーネント
|
|
70
|
+
│ │ │ ├── button.tsx
|
|
71
|
+
│ │ │ ├── card.tsx
|
|
72
|
+
│ │ │ ├── input.tsx
|
|
73
|
+
│ │ │ ├── modal.tsx
|
|
74
|
+
│ │ │ └── ...
|
|
75
|
+
│ │ └── features/ # 機能別コンポーネント
|
|
76
|
+
│ │ ├── posts/
|
|
77
|
+
│ │ │ ├── PostList.tsx
|
|
78
|
+
│ │ │ ├── PostCard.tsx
|
|
79
|
+
│ │ │ ├── PostCreateForm.tsx
|
|
80
|
+
│ │ │ └── PostDetail.tsx
|
|
81
|
+
│ │ └── auth/
|
|
82
|
+
│ │ ├── LoginForm.tsx
|
|
83
|
+
│ │ └── RegisterForm.tsx
|
|
84
|
+
│ ├── lib/ # ユーティリティ
|
|
85
|
+
│ │ ├── api/
|
|
86
|
+
│ │ │ ├── client.ts # Hono Client設定
|
|
87
|
+
│ │ │ └── parse-response.ts # レスポンスパース&バリデーション
|
|
88
|
+
│ │ ├── query-client.ts # Tanstack Query設定
|
|
89
|
+
│ │ └── utils.ts # 共通ユーティリティ
|
|
90
|
+
│ ├── hooks/ # カスタムフック
|
|
91
|
+
│ │ ├── api/ # API関連フック
|
|
92
|
+
│ │ │ └── use-posts.ts
|
|
93
|
+
│ │ └── use-auth.ts # 認証フック
|
|
94
|
+
│ └── shared/
|
|
95
|
+
│ └── schemas/ # レスポンススキーマ(フロント固有)
|
|
96
|
+
│ └── user.ts
|
|
89
97
|
├── public/ # 静的ファイル
|
|
90
|
-
├── styles/ # グローバルスタイル
|
|
91
|
-
│ └── globals.css
|
|
92
98
|
├── next.config.js
|
|
93
99
|
├── package.json
|
|
94
100
|
├── tsconfig.json
|
|
@@ -99,29 +105,31 @@ apps/web/
|
|
|
99
105
|
|
|
100
106
|
```
|
|
101
107
|
apps/admin/
|
|
102
|
-
├──
|
|
103
|
-
│ ├──
|
|
104
|
-
│ │ ├──
|
|
105
|
-
│ │ │ ├──
|
|
106
|
-
│ │ │ │
|
|
107
|
-
│ │ │
|
|
108
|
-
│ │ │ │
|
|
109
|
-
│ │ │ └──
|
|
110
|
-
│ │ │
|
|
111
|
-
│
|
|
112
|
-
│ │
|
|
113
|
-
│ │
|
|
114
|
-
│
|
|
115
|
-
│ └──
|
|
116
|
-
├──
|
|
117
|
-
│
|
|
118
|
-
│
|
|
119
|
-
│
|
|
120
|
-
│
|
|
121
|
-
│
|
|
122
|
-
├──
|
|
123
|
-
|
|
124
|
-
|
|
108
|
+
├── src/
|
|
109
|
+
│ ├── app/
|
|
110
|
+
│ │ ├── (protected)/ # ルートグループ: 認証必須
|
|
111
|
+
│ │ │ ├── admin/
|
|
112
|
+
│ │ │ │ ├── users/
|
|
113
|
+
│ │ │ │ │ └── page.tsx
|
|
114
|
+
│ │ │ │ ├── posts/
|
|
115
|
+
│ │ │ │ │ └── page.tsx
|
|
116
|
+
│ │ │ │ └── analytics/
|
|
117
|
+
│ │ │ │ └── page.tsx
|
|
118
|
+
│ │ ├── api/
|
|
119
|
+
│ │ │ └── rpc/
|
|
120
|
+
│ │ │ └── [[...route]]/
|
|
121
|
+
│ │ │ └── route.ts
|
|
122
|
+
│ │ ├── layout.tsx
|
|
123
|
+
│ │ └── page.tsx
|
|
124
|
+
│ ├── components/
|
|
125
|
+
│ │ ├── ui/
|
|
126
|
+
│ │ └── features/
|
|
127
|
+
│ │ └── admin/
|
|
128
|
+
│ │ ├── UserTable.tsx
|
|
129
|
+
│ │ └── PostStatusManager.tsx
|
|
130
|
+
│ ├── lib/
|
|
131
|
+
│ ├── hooks/
|
|
132
|
+
│ └── ...
|
|
125
133
|
```
|
|
126
134
|
|
|
127
135
|
**設計ポイント**:
|
|
@@ -129,6 +137,45 @@ apps/admin/
|
|
|
129
137
|
- **コロケーション**: 機能別にコンポーネント、フック、ユーティリティを配置
|
|
130
138
|
- **共通コンポーネント**: ui/に再利用可能な基本コンポーネント、features/に機能別コンポーネント
|
|
131
139
|
|
|
140
|
+
### スキーマ配置の設計方針
|
|
141
|
+
|
|
142
|
+
スキーマはリクエスト/レスポンスで配置場所を分離します。
|
|
143
|
+
|
|
144
|
+
| スキーマ種別 | 配置場所 | 用途 |
|
|
145
|
+
|-------------|---------|------|
|
|
146
|
+
| **リクエストスキーマ** | `@repo/server-core/domain/validators/` | APIリクエストのバリデーション(バックエンド) |
|
|
147
|
+
| **レスポンススキーマ** | `apps/web/src/shared/schemas/` | APIレスポンスの型検証(フロントエンド固有) |
|
|
148
|
+
|
|
149
|
+
**理由**:
|
|
150
|
+
- レスポンス形式はフロントエンドが消費するものなので、フロントエンド側で定義すべき
|
|
151
|
+
- apps間で異なるレスポンス形式を持つ可能性がある
|
|
152
|
+
- フロント固有のバリデーションルール(例: 日付フォーマット)を追加しやすい
|
|
153
|
+
|
|
154
|
+
**例**:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// リクエストスキーマ(バックエンド)
|
|
158
|
+
// @repo/server-core/domain/validators/user.ts
|
|
159
|
+
export const createUserSchema = z.object({
|
|
160
|
+
email: z.string().email(),
|
|
161
|
+
name: z.string().min(1).max(100),
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
// レスポンススキーマ(フロントエンド)
|
|
165
|
+
// apps/web/src/shared/schemas/user.ts
|
|
166
|
+
export const userSchema = z.object({
|
|
167
|
+
id: z.string(),
|
|
168
|
+
email: z.string(),
|
|
169
|
+
name: z.string(),
|
|
170
|
+
createdAt: z.string(), // ISO 8601文字列
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
export const paginatedUserListSchema = z.object({
|
|
174
|
+
users: z.array(userSchema),
|
|
175
|
+
total: z.number(),
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
132
179
|
---
|
|
133
180
|
|
|
134
181
|
## 2. 技術スタック
|
|
@@ -153,24 +200,24 @@ apps/admin/
|
|
|
153
200
|
**Hono Clientの初期化**:
|
|
154
201
|
|
|
155
202
|
```typescript
|
|
156
|
-
// apps/web/lib/api
|
|
203
|
+
// apps/web/src/lib/api/client.ts
|
|
157
204
|
import { hc } from 'hono/client'
|
|
158
|
-
import type { AppType } from '@/app/api/[[...route]]/route'
|
|
205
|
+
import type { AppType } from '@/app/api/rpc/[[...route]]/route'
|
|
159
206
|
|
|
160
|
-
export const apiClient = hc<AppType>('/
|
|
207
|
+
export const apiClient = hc<AppType>('/')
|
|
161
208
|
```
|
|
162
209
|
|
|
163
210
|
**型定義のエクスポート**:
|
|
164
211
|
|
|
165
212
|
```typescript
|
|
166
|
-
// apps/web/app/api/[[...route]]/route.ts
|
|
213
|
+
// apps/web/src/app/api/rpc/[[...route]]/route.ts
|
|
167
214
|
import { Hono } from 'hono'
|
|
168
215
|
import { handle } from 'hono/vercel'
|
|
169
|
-
import
|
|
216
|
+
import { userRoutes } from '@web/server/presentation/routes/userRoutes'
|
|
170
217
|
|
|
171
|
-
const app = new Hono().basePath('/api')
|
|
218
|
+
const app = new Hono().basePath('/api/rpc')
|
|
172
219
|
|
|
173
|
-
app.route('/',
|
|
220
|
+
const routes = app.route('/users', userRoutes)
|
|
174
221
|
|
|
175
222
|
export const GET = handle(app)
|
|
176
223
|
export const POST = handle(app)
|
|
@@ -178,7 +225,7 @@ export const PUT = handle(app)
|
|
|
178
225
|
export const DELETE = handle(app)
|
|
179
226
|
|
|
180
227
|
// 型のエクスポート(フロントエンドで使用)
|
|
181
|
-
export type AppType = typeof
|
|
228
|
+
export type AppType = typeof routes
|
|
182
229
|
```
|
|
183
230
|
|
|
184
231
|
### API呼び出しパターン
|
|
@@ -186,49 +233,49 @@ export type AppType = typeof app
|
|
|
186
233
|
**GET リクエスト**:
|
|
187
234
|
|
|
188
235
|
```typescript
|
|
189
|
-
//
|
|
190
|
-
const response = await apiClient.
|
|
236
|
+
// ユーザー一覧取得
|
|
237
|
+
const response = await apiClient.api.rpc.users.$get({
|
|
191
238
|
query: { page: '1', limit: '10' }
|
|
192
239
|
})
|
|
193
|
-
const data = await response.json() // 型推論: {
|
|
240
|
+
const data = await response.json() // 型推論: { users: User[], total: number }
|
|
194
241
|
```
|
|
195
242
|
|
|
196
243
|
**POST リクエスト**:
|
|
197
244
|
|
|
198
245
|
```typescript
|
|
199
|
-
//
|
|
200
|
-
const response = await apiClient.
|
|
201
|
-
json: {
|
|
246
|
+
// ユーザー作成
|
|
247
|
+
const response = await apiClient.api.rpc.users.$post({
|
|
248
|
+
json: { email: 'user@example.com', name: 'User Name' }
|
|
202
249
|
})
|
|
203
|
-
const data = await response.json() // 型推論: {
|
|
250
|
+
const data = await response.json() // 型推論: { user: User }
|
|
204
251
|
```
|
|
205
252
|
|
|
206
253
|
**GET リクエスト(パスパラメータ)**:
|
|
207
254
|
|
|
208
255
|
```typescript
|
|
209
|
-
//
|
|
210
|
-
const response = await apiClient.
|
|
256
|
+
// ユーザー詳細取得
|
|
257
|
+
const response = await apiClient.api.rpc.users[':id'].$get({
|
|
211
258
|
param: { id: '123' }
|
|
212
259
|
})
|
|
213
|
-
const data = await response.json() // 型推論: {
|
|
260
|
+
const data = await response.json() // 型推論: { user: User }
|
|
214
261
|
```
|
|
215
262
|
|
|
216
263
|
**PUT リクエスト**:
|
|
217
264
|
|
|
218
265
|
```typescript
|
|
219
|
-
//
|
|
220
|
-
const response = await apiClient.
|
|
266
|
+
// ユーザー更新
|
|
267
|
+
const response = await apiClient.api.rpc.users[':id'].$put({
|
|
221
268
|
param: { id: '123' },
|
|
222
|
-
json: {
|
|
269
|
+
json: { name: 'Updated Name' }
|
|
223
270
|
})
|
|
224
|
-
const data = await response.json() // 型推論: {
|
|
271
|
+
const data = await response.json() // 型推論: { user: User }
|
|
225
272
|
```
|
|
226
273
|
|
|
227
274
|
**DELETE リクエスト**:
|
|
228
275
|
|
|
229
276
|
```typescript
|
|
230
|
-
//
|
|
231
|
-
const response = await apiClient.
|
|
277
|
+
// ユーザー削除
|
|
278
|
+
const response = await apiClient.api.rpc.users[':id'].$delete({
|
|
232
279
|
param: { id: '123' }
|
|
233
280
|
})
|
|
234
281
|
const data = await response.json() // 型推論: { success: true }
|
|
@@ -239,6 +286,100 @@ const data = await response.json() // 型推論: { success: true }
|
|
|
239
286
|
- 型エラーでAPI仕様の不一致を早期発見
|
|
240
287
|
- IDEの補完機能でAPI仕様を確認可能
|
|
241
288
|
|
|
289
|
+
### APIレスポンスパース処理
|
|
290
|
+
|
|
291
|
+
`lib/api/parse-response.ts` は、APIレスポンスのパースとZodスキーマによるバリデーションを行います。
|
|
292
|
+
|
|
293
|
+
**parseResponse 関数**:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import type { z } from "zod";
|
|
297
|
+
|
|
298
|
+
export class ApiError extends Error {
|
|
299
|
+
constructor(
|
|
300
|
+
public readonly code: string,
|
|
301
|
+
message: string,
|
|
302
|
+
public readonly statusCode: number,
|
|
303
|
+
public readonly details?: Record<string, unknown>
|
|
304
|
+
) {
|
|
305
|
+
super(message);
|
|
306
|
+
this.name = "ApiError";
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export async function parseResponse<T>(
|
|
311
|
+
response: Response,
|
|
312
|
+
schema: z.ZodSchema<T>
|
|
313
|
+
): Promise<T> {
|
|
314
|
+
if (!response.ok) {
|
|
315
|
+
const errorData = await response.json().catch(() => ({}));
|
|
316
|
+
throw new ApiError(
|
|
317
|
+
errorData.error?.code || "UNKNOWN_ERROR",
|
|
318
|
+
errorData.error?.message || "APIエラーが発生しました",
|
|
319
|
+
response.status,
|
|
320
|
+
errorData.error?.details
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const data = await response.json();
|
|
325
|
+
const parsed = schema.safeParse(data);
|
|
326
|
+
|
|
327
|
+
if (!parsed.success) {
|
|
328
|
+
throw new ApiError(
|
|
329
|
+
"VALIDATION_ERROR",
|
|
330
|
+
"レスポンスの形式が不正です",
|
|
331
|
+
500,
|
|
332
|
+
{ zodError: parsed.error.flatten() }
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return parsed.data;
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**カスタムフック内での使用**:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { useQuery } from "@tanstack/react-query";
|
|
344
|
+
import { parseResponse } from "@/lib/api/parse-response";
|
|
345
|
+
import { paginatedUserListSchema } from "@/shared/schemas/user";
|
|
346
|
+
import { apiClient } from "@/lib/api/client";
|
|
347
|
+
|
|
348
|
+
export function useUsers(filters: UserFilters = {}) {
|
|
349
|
+
return useQuery({
|
|
350
|
+
queryKey: ["users", filters],
|
|
351
|
+
queryFn: async () => {
|
|
352
|
+
const response = await apiClient.api.rpc.users.$get({
|
|
353
|
+
query: { page: String(filters.page || 1), limit: String(filters.limit || 10) },
|
|
354
|
+
});
|
|
355
|
+
return parseResponse(response, paginatedUserListSchema);
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**エラーハンドリング**:
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import { ApiError } from "@/lib/api/parse-response";
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
const users = await parseResponse(response, paginatedUserListSchema);
|
|
368
|
+
} catch (error) {
|
|
369
|
+
if (error instanceof ApiError) {
|
|
370
|
+
console.error(`API Error [${error.code}]: ${error.message}`);
|
|
371
|
+
// error.statusCode, error.details も利用可能
|
|
372
|
+
}
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**メリット**:
|
|
378
|
+
- レスポンス形式の型安全性を保証
|
|
379
|
+
- フロント固有のバリデーションルールを適用可能
|
|
380
|
+
- エラーハンドリングの一元化
|
|
381
|
+
- APIエラーとバリデーションエラーの明確な区別
|
|
382
|
+
|
|
242
383
|
---
|
|
243
384
|
|
|
244
385
|
## 4. Server ComponentとClient Component
|
|
@@ -958,12 +1099,18 @@ export function PostCard({ post }: PostCardProps) {
|
|
|
958
1099
|
- 状態管理ロジックの再利用
|
|
959
1100
|
- コンポーネントをシンプルに保つ
|
|
960
1101
|
|
|
1102
|
+
**フックの分類**:
|
|
1103
|
+
- **API関連フック**: `hooks/api/` に配置(例: `use-posts.ts`, `use-users.ts`)
|
|
1104
|
+
- **UI状態フック**: `hooks/` 直下に配置(例: `use-toast.ts`, `use-auth.ts`)
|
|
1105
|
+
|
|
961
1106
|
**例**:
|
|
962
1107
|
|
|
963
1108
|
```typescript
|
|
964
|
-
// hooks/use-posts.ts
|
|
1109
|
+
// hooks/api/use-posts.ts
|
|
965
1110
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
966
|
-
import {
|
|
1111
|
+
import { parseResponse } from '@/lib/api/parse-response'
|
|
1112
|
+
import { paginatedPostListSchema } from '@/shared/schemas/post'
|
|
1113
|
+
import { apiClient } from '@/lib/api/client'
|
|
967
1114
|
import type { CreatePostInput, UpdatePostInput } from '@repo/server-core/domain/validators/post'
|
|
968
1115
|
|
|
969
1116
|
// 投稿一覧取得
|
|
@@ -971,10 +1118,10 @@ export function usePostList(page: number, limit: number) {
|
|
|
971
1118
|
return useQuery({
|
|
972
1119
|
queryKey: ['posts', page, limit],
|
|
973
1120
|
queryFn: async () => {
|
|
974
|
-
const response = await apiClient.posts.$get({
|
|
1121
|
+
const response = await apiClient.api.posts.$get({
|
|
975
1122
|
query: { page: String(page), limit: String(limit) }
|
|
976
1123
|
})
|
|
977
|
-
return response
|
|
1124
|
+
return parseResponse(response, paginatedPostListSchema)
|
|
978
1125
|
},
|
|
979
1126
|
})
|
|
980
1127
|
}
|
|
@@ -984,8 +1131,8 @@ export function usePost(id: string) {
|
|
|
984
1131
|
return useQuery({
|
|
985
1132
|
queryKey: ['posts', id],
|
|
986
1133
|
queryFn: async () => {
|
|
987
|
-
const response = await apiClient.posts[':id'].$get({ param: { id } })
|
|
988
|
-
return response
|
|
1134
|
+
const response = await apiClient.api.posts[':id'].$get({ param: { id } })
|
|
1135
|
+
return parseResponse(response, postSchema)
|
|
989
1136
|
},
|
|
990
1137
|
})
|
|
991
1138
|
}
|
|
@@ -996,8 +1143,8 @@ export function useCreatePost() {
|
|
|
996
1143
|
|
|
997
1144
|
return useMutation({
|
|
998
1145
|
mutationFn: async (data: CreatePostInput) => {
|
|
999
|
-
const response = await apiClient.posts.$post({ json: data })
|
|
1000
|
-
return response
|
|
1146
|
+
const response = await apiClient.api.posts.$post({ json: data })
|
|
1147
|
+
return parseResponse(response, postSchema)
|
|
1001
1148
|
},
|
|
1002
1149
|
onSuccess: () => {
|
|
1003
1150
|
queryClient.invalidateQueries({ queryKey: ['posts'] })
|
|
@@ -1011,11 +1158,11 @@ export function useUpdatePost(id: string) {
|
|
|
1011
1158
|
|
|
1012
1159
|
return useMutation({
|
|
1013
1160
|
mutationFn: async (data: UpdatePostInput) => {
|
|
1014
|
-
const response = await apiClient.posts[':id'].$put({
|
|
1161
|
+
const response = await apiClient.api.posts[':id'].$put({
|
|
1015
1162
|
param: { id },
|
|
1016
1163
|
json: data
|
|
1017
1164
|
})
|
|
1018
|
-
return response
|
|
1165
|
+
return parseResponse(response, postSchema)
|
|
1019
1166
|
},
|
|
1020
1167
|
onSuccess: () => {
|
|
1021
1168
|
queryClient.invalidateQueries({ queryKey: ['posts', id] })
|
|
@@ -1030,8 +1177,8 @@ export function useDeletePost() {
|
|
|
1030
1177
|
|
|
1031
1178
|
return useMutation({
|
|
1032
1179
|
mutationFn: async (id: string) => {
|
|
1033
|
-
const response = await apiClient.posts[':id'].$delete({ param: { id } })
|
|
1034
|
-
return response
|
|
1180
|
+
const response = await apiClient.api.posts[':id'].$delete({ param: { id } })
|
|
1181
|
+
return parseResponse(response, deleteResponseSchema)
|
|
1035
1182
|
},
|
|
1036
1183
|
onSuccess: () => {
|
|
1037
1184
|
queryClient.invalidateQueries({ queryKey: ['posts'] })
|