@brickflow/http 0.0.14 → 0.0.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 +296 -277
- package/dist/http.d.ts +61 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +144 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nuxt.d.ts +72 -0
- package/dist/nuxt.d.ts.map +1 -0
- package/dist/nuxt.mjs +222 -0
- package/dist/nuxt.mjs.map +1 -0
- package/dist/utils-DMSINHi5.js +39 -0
- package/dist/utils-DMSINHi5.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +27 -16
- package/dist/module.d.mts +0 -73
- package/dist/module.json +0 -12
- package/dist/module.mjs +0 -59
- package/dist/runtime/composables/useHttp.d.ts +0 -27
- package/dist/runtime/composables/useHttp.js +0 -197
- package/dist/runtime/http/client.d.ts +0 -3
- package/dist/runtime/http/client.js +0 -217
- package/dist/runtime/plugin.d.ts +0 -7
- package/dist/runtime/plugin.js +0 -56
- package/dist/runtime/types.d.ts +0 -21
- package/dist/runtime/utils/helpers.d.ts +0 -5
- package/dist/runtime/utils/helpers.js +0 -14
- package/dist/runtime/utils/index.d.ts +0 -6
- package/dist/runtime/utils/index.js +0 -5
- package/dist/runtime/utils/indexeddb.d.ts +0 -14
- package/dist/runtime/utils/indexeddb.js +0 -222
- package/dist/runtime/utils/middleware.d.ts +0 -8
- package/dist/runtime/utils/middleware.js +0 -20
- package/dist/runtime/utils/shared.d.ts +0 -83
- package/dist/runtime/utils/shared.js +0 -50
- package/dist/runtime/utils/typed.d.ts +0 -46
- package/dist/runtime/utils/typed.js +0 -9
- package/dist/types.d.mts +0 -11
package/README.md
CHANGED
|
@@ -1,406 +1,425 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @brickflow/http
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Minimal HTTP package used in this repo for:
|
|
4
4
|
|
|
5
|
-
- `
|
|
6
|
-
- `
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- optional client cache via IndexedDB
|
|
10
|
-
- typed URL literals for `get`, `post`, and `useHttp`
|
|
5
|
+
- low-level HTTP transport via `createHttp`
|
|
6
|
+
- Nuxt async state wrapper via `createUseHttp`
|
|
7
|
+
- reusable endpoint factory via `createGet`
|
|
8
|
+
- project-level typing through `declare module '@brickflow/http'`
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
This package does not know your API schema by default. The schema and error type are configured in the consumer project through `type.d.ts`.
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
## Exports
|
|
13
|
+
|
|
14
|
+
From `@brickflow/http`:
|
|
15
|
+
|
|
16
|
+
- `createHttp`
|
|
17
|
+
- `createURL`
|
|
18
|
+
- `hashData`
|
|
19
|
+
- HTTP types: `HttpClient`, `HttpError`, `HttpKey`, `HttpParam`, `HttpResponse`, `HttpResponseData`, `HttpSuccessData`
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
From `@brickflow/http/nuxt`:
|
|
22
|
+
|
|
23
|
+
- `createUseHttp`
|
|
24
|
+
- `createGet`
|
|
25
|
+
- Nuxt types: `UseHttpOptions`, `UseHttpResult`, `UseHttpFn`
|
|
26
|
+
|
|
27
|
+
## 1. Configure API types in `type.d.ts`
|
|
28
|
+
|
|
29
|
+
In this repo the typing is configured in `types/http.d.ts`.
|
|
19
30
|
|
|
20
31
|
```ts
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
32
|
+
import type { Convention, ConventionKeys } from 'convention'
|
|
33
|
+
|
|
34
|
+
type BrickHttpError = Exclude<Convention<ConventionKeys>, { status: 'success' }>
|
|
35
|
+
type BrickHttpSchema = {
|
|
36
|
+
[TKey in ConventionKeys]: Convention<TKey>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare module '@brickflow/http' {
|
|
40
|
+
interface HttpTypeConfig {
|
|
41
|
+
endpoints: BrickHttpSchema
|
|
42
|
+
error: BrickHttpError
|
|
43
|
+
}
|
|
44
|
+
}
|
|
24
45
|
```
|
|
25
46
|
|
|
26
|
-
|
|
47
|
+
What this gives:
|
|
48
|
+
|
|
49
|
+
- `HttpKey` becomes your endpoint union
|
|
50
|
+
- `HttpResponseData<'some/endpoint'>` becomes the response type for that endpoint
|
|
51
|
+
- `HttpSuccessData<'some/endpoint'>` becomes response without the configured error branch
|
|
52
|
+
- `UseHttpResult<T, P>['error']` is inferred from `HttpTypeConfig['error']`
|
|
53
|
+
|
|
54
|
+
This is the main place where project typing should live.
|
|
55
|
+
|
|
56
|
+
## 2. Create low-level HTTP client
|
|
57
|
+
|
|
58
|
+
Real usage from `plugins/01.di.ts`:
|
|
27
59
|
|
|
28
60
|
```ts
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
disableCacheInDev: true,
|
|
42
|
-
requestTimeoutMs: 80000,
|
|
43
|
-
retry: {
|
|
44
|
-
delay: 300,
|
|
45
|
-
retries: 3,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
61
|
+
import { createHttp } from '@brickflow/http'
|
|
62
|
+
|
|
63
|
+
const httpClient = createHttp({
|
|
64
|
+
baseURL: apiUrl,
|
|
65
|
+
headers: () => ({
|
|
66
|
+
'Client-Env': config.public.isDev ? 'development' : undefined,
|
|
67
|
+
'Client-Lang': String(locale.value ?? 'en'),
|
|
68
|
+
'Client-Socket-Id': socketClient?.io.id || '',
|
|
69
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
70
|
+
}),
|
|
71
|
+
onResponseError: responseInterceptor,
|
|
48
72
|
})
|
|
49
73
|
```
|
|
50
74
|
|
|
51
|
-
|
|
75
|
+
Available options:
|
|
52
76
|
|
|
53
|
-
`
|
|
77
|
+
- `baseURL`
|
|
78
|
+
- `fetch`
|
|
79
|
+
- `headers`
|
|
80
|
+
- `onResponseError`
|
|
81
|
+
- `requestInit`
|
|
82
|
+
- `timeout`
|
|
54
83
|
|
|
55
|
-
|
|
56
|
-
| ------------------- | ------------------ |
|
|
57
|
-
| `baseURL` | `''` |
|
|
58
|
-
| `cache` | `true` |
|
|
59
|
-
| `cacheDbName` | `'smart-cache-v2'` |
|
|
60
|
-
| `cacheStoreName` | `'data'` |
|
|
61
|
-
| `cacheTtlMs` | `604800000` |
|
|
62
|
-
| `clientEnvHeader` | `true` |
|
|
63
|
-
| `defaultHeaders` | `{}` |
|
|
64
|
-
| `disableCacheInDev` | `true` |
|
|
65
|
-
| `requestTimeoutMs` | `80000` |
|
|
66
|
-
| `retry.delay` | `300` |
|
|
67
|
-
| `retry.retries` | `3` |
|
|
84
|
+
`createHttp` returns:
|
|
68
85
|
|
|
69
|
-
|
|
86
|
+
```ts
|
|
87
|
+
interface HttpClient {
|
|
88
|
+
get(url, config?)
|
|
89
|
+
post(url, data?, config?)
|
|
90
|
+
}
|
|
91
|
+
```
|
|
70
92
|
|
|
71
|
-
|
|
72
|
-
- in dev, `Client-Env: development` is added when `clientEnvHeader` is enabled
|
|
73
|
-
- `5xx` and `451` responses with `{ status: 'error' }` trigger Nuxt `showError()`
|
|
93
|
+
## 3. Use `HttpClient` directly
|
|
74
94
|
|
|
75
|
-
|
|
95
|
+
Used in domain methods that do not need cached async state.
|
|
76
96
|
|
|
77
|
-
|
|
97
|
+
Example from `domains/content/use-case.ts`:
|
|
78
98
|
|
|
79
99
|
```ts
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
})
|
|
100
|
+
async create(title: string, type: string, description?: string) {
|
|
101
|
+
const { data } = await httpClient.post('content/create', {
|
|
102
|
+
description,
|
|
103
|
+
title,
|
|
104
|
+
type,
|
|
105
|
+
})
|
|
87
106
|
|
|
88
|
-
|
|
89
|
-
console.error(response.data.message)
|
|
90
|
-
} else {
|
|
91
|
-
console.log(response.data.name)
|
|
107
|
+
return data
|
|
92
108
|
}
|
|
93
109
|
```
|
|
94
110
|
|
|
95
|
-
|
|
111
|
+
Another example:
|
|
96
112
|
|
|
97
113
|
```ts
|
|
98
|
-
|
|
114
|
+
async updateType(itemId: string, type: string) {
|
|
115
|
+
const { data } = await httpClient.post('content/update-type', {
|
|
116
|
+
itemId,
|
|
117
|
+
type,
|
|
118
|
+
})
|
|
99
119
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
title: 'Hello',
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
params: {
|
|
107
|
-
draft: true,
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
)
|
|
120
|
+
return data
|
|
121
|
+
}
|
|
111
122
|
```
|
|
112
123
|
|
|
113
|
-
|
|
124
|
+
Use this style when:
|
|
114
125
|
|
|
115
|
-
|
|
126
|
+
- request is one-shot
|
|
127
|
+
- you do not need `pending`, `hasFirstData`, cache, SSR sync, or `fetch()`
|
|
116
128
|
|
|
117
|
-
|
|
118
|
-
- `error`
|
|
119
|
-
- `pending`
|
|
120
|
-
- `pendingCache`
|
|
121
|
-
- `hasFirstData`
|
|
122
|
-
- `hasFreshData`
|
|
123
|
-
- `fetch()`
|
|
129
|
+
## 4. Create Nuxt `useHttp`
|
|
124
130
|
|
|
125
|
-
|
|
131
|
+
In this repo the app-level `useHttp` is created once in `core/util.ts`:
|
|
126
132
|
|
|
127
133
|
```ts
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
import { createUseHttp } from '@brickflow/http/nuxt'
|
|
135
|
+
|
|
136
|
+
const useHttp = createUseHttp({
|
|
137
|
+
getCache: () => ({
|
|
138
|
+
deleteKeysWithPart: async (part) => await dbDeleteKeysWithPart(part, 'smart-cache-v2', STORE_NAME),
|
|
139
|
+
get: async (key) => await dbGet(key, 'smart-cache-v2', STORE_NAME),
|
|
140
|
+
set: async (key, value, ttl) => await dbSafeSet(key, value, 'smart-cache-v2', STORE_NAME, ttl),
|
|
141
|
+
}),
|
|
142
|
+
getHttpClient: () => useNuxtApp().$http,
|
|
143
|
+
isDev: () => useRuntimeConfig().public.isDev,
|
|
131
144
|
})
|
|
132
145
|
```
|
|
133
146
|
|
|
134
|
-
|
|
147
|
+
Dependencies:
|
|
135
148
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
})
|
|
149
|
+
- `getHttpClient`
|
|
150
|
+
- `getCache`
|
|
151
|
+
- `isError`
|
|
152
|
+
- `isDev`
|
|
153
|
+
- `ttl`
|
|
154
|
+
- `channelName`
|
|
143
155
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
```
|
|
156
|
+
`isError` can be set globally here if your project needs a custom runtime error predicate.
|
|
157
|
+
|
|
158
|
+
## 5. Bind `createGet` once
|
|
148
159
|
|
|
149
|
-
|
|
160
|
+
The package exports `createGet(useHttp)`, which builds typed endpoint helpers on top of your local `useHttp`.
|
|
161
|
+
|
|
162
|
+
Real usage from `core/util.ts`:
|
|
150
163
|
|
|
151
164
|
```ts
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
},
|
|
158
|
-
url: '/profile',
|
|
159
|
-
})
|
|
165
|
+
import { createGet as createHttpGet, createUseHttp } from '@brickflow/http/nuxt'
|
|
166
|
+
|
|
167
|
+
const useHttp = createUseHttp({ ... })
|
|
168
|
+
|
|
169
|
+
export const createGet = createHttpGet(useHttp)
|
|
160
170
|
```
|
|
161
171
|
|
|
162
|
-
|
|
172
|
+
After that you can reuse `createGet` in domain files.
|
|
173
|
+
|
|
174
|
+
## 6. Create typed GET endpoints
|
|
163
175
|
|
|
164
|
-
|
|
176
|
+
### Without params
|
|
165
177
|
|
|
166
|
-
|
|
178
|
+
Example from `domains/storage/use-case.ts`:
|
|
167
179
|
|
|
168
180
|
```ts
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
error: HttpErrorPayload & { code?: 'NOT_FOUND' }
|
|
176
|
-
params: { id: string }
|
|
177
|
-
}
|
|
178
|
-
'/api/posts': {
|
|
179
|
-
data: Array<{ id: string; title: string }>
|
|
180
|
-
params: { page?: number }
|
|
181
|
-
}
|
|
182
|
-
'/api/posts/create': {
|
|
183
|
-
body: { title: string }
|
|
184
|
-
data: { id: string }
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
181
|
+
plans: createGet()('storage/plans')
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### With params
|
|
185
|
+
|
|
186
|
+
Example from `domains/feed/use-case.ts`:
|
|
188
187
|
|
|
189
|
-
|
|
188
|
+
```ts
|
|
189
|
+
home: createGet<{
|
|
190
|
+
category?: 'fresh' | 'popular' | 'recommended' | 'updated'
|
|
191
|
+
limit: number
|
|
192
|
+
offset: number
|
|
193
|
+
}>()('feed/home')
|
|
190
194
|
```
|
|
191
195
|
|
|
192
|
-
|
|
196
|
+
### With `ignore`
|
|
193
197
|
|
|
194
|
-
|
|
198
|
+
Example from `domains/content/use-case.ts`:
|
|
195
199
|
|
|
196
200
|
```ts
|
|
197
|
-
|
|
201
|
+
analytics: createGet<{
|
|
202
|
+
itemId: string
|
|
203
|
+
period: '7d' | '28d' | '90d'
|
|
204
|
+
}>()('content/analytics', {
|
|
205
|
+
ignore(res) {
|
|
206
|
+
if (res.data.kind === 'no_auth') {
|
|
207
|
+
return true
|
|
208
|
+
}
|
|
198
209
|
|
|
199
|
-
|
|
200
|
-
params: {
|
|
201
|
-
id: '42',
|
|
210
|
+
return false
|
|
202
211
|
},
|
|
203
212
|
})
|
|
204
213
|
```
|
|
205
214
|
|
|
206
|
-
|
|
215
|
+
### With `effect`
|
|
216
|
+
|
|
217
|
+
Example from `domains/root/use-case.ts`:
|
|
207
218
|
|
|
208
219
|
```ts
|
|
209
|
-
|
|
220
|
+
main: createGet()('root/main', {
|
|
221
|
+
effect(data, config) {
|
|
222
|
+
if (data.status === 'error') {
|
|
223
|
+
return
|
|
224
|
+
}
|
|
210
225
|
|
|
211
|
-
|
|
212
|
-
|
|
226
|
+
if (!config.cached) {
|
|
227
|
+
userStore.setUser(data.user)
|
|
228
|
+
userStore.setRegion(data.region)
|
|
229
|
+
}
|
|
230
|
+
},
|
|
213
231
|
})
|
|
214
232
|
```
|
|
215
233
|
|
|
216
|
-
|
|
234
|
+
### With `effect` and success handling
|
|
235
|
+
|
|
236
|
+
Example from `domains/storage/use-case.ts`:
|
|
217
237
|
|
|
218
238
|
```ts
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
239
|
+
current: createGet()('storage/current', {
|
|
240
|
+
effect(data) {
|
|
241
|
+
if (data.status === 'success') {
|
|
242
|
+
storageStore.setCurrentPlan(data.plan)
|
|
243
|
+
}
|
|
222
244
|
},
|
|
223
|
-
url: '/api/posts',
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
await posts.fetch({
|
|
227
|
-
page: 2,
|
|
228
245
|
})
|
|
229
246
|
```
|
|
230
247
|
|
|
231
|
-
##
|
|
248
|
+
## 7. Consume endpoint state in components
|
|
232
249
|
|
|
233
|
-
|
|
250
|
+
### Create request object
|
|
234
251
|
|
|
235
|
-
|
|
252
|
+
Example from `components/Search/index.vue`:
|
|
236
253
|
|
|
237
254
|
```ts
|
|
238
|
-
|
|
255
|
+
const searchFastHttp = await app.$di.search.fast({
|
|
256
|
+
lazy: true,
|
|
257
|
+
server: false,
|
|
258
|
+
})
|
|
259
|
+
```
|
|
239
260
|
|
|
240
|
-
|
|
241
|
-
const strictHttp = createStrictHttpClient($http)
|
|
261
|
+
### Trigger fetch manually
|
|
242
262
|
|
|
243
|
-
|
|
244
|
-
|
|
263
|
+
```ts
|
|
264
|
+
await searchFastHttp.fetch({
|
|
265
|
+
text: searchQuery.value,
|
|
245
266
|
})
|
|
246
|
-
|
|
247
|
-
// TypeScript error
|
|
248
|
-
await strictHttp.get('/api/unknown')
|
|
249
267
|
```
|
|
250
268
|
|
|
251
|
-
|
|
269
|
+
### Read `data`
|
|
252
270
|
|
|
253
271
|
```ts
|
|
254
|
-
|
|
272
|
+
const data = searchFastHttp.data
|
|
255
273
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
)
|
|
274
|
+
if (data?.status === 'success') {
|
|
275
|
+
items.value = data.items
|
|
276
|
+
users.value = data.users
|
|
277
|
+
}
|
|
261
278
|
```
|
|
262
279
|
|
|
263
|
-
|
|
280
|
+
### Read loading flags
|
|
264
281
|
|
|
265
|
-
|
|
282
|
+
Example from `components/ProfileMyGrid/index.vue`:
|
|
266
283
|
|
|
267
|
-
```
|
|
268
|
-
|
|
284
|
+
```vue
|
|
285
|
+
:loading="myContentHttp.pending || myContentHttp.pendingCache"
|
|
286
|
+
```
|
|
269
287
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
288
|
+
### Use `hasFirstData`
|
|
289
|
+
|
|
290
|
+
```vue
|
|
291
|
+
v-if="!myContentHttp.pending && myContentHttp.hasFirstData && items.length === 0"
|
|
273
292
|
```
|
|
274
293
|
|
|
275
|
-
|
|
294
|
+
## 8. `effect` semantics
|
|
276
295
|
|
|
277
|
-
|
|
278
|
-
import { addHttpRequestMiddleware } from '@brickflow/http'
|
|
296
|
+
`effect` receives the full response payload.
|
|
279
297
|
|
|
280
|
-
|
|
281
|
-
const apiBaseUrl = useState('api-base-url', () => 'https://dummyjson.com')
|
|
298
|
+
That means:
|
|
282
299
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
300
|
+
- it is called for success
|
|
301
|
+
- it is called for error
|
|
302
|
+
- you can branch on `data.status`
|
|
303
|
+
- `config.cached` tells whether the payload came from cache
|
|
304
|
+
- `config.params` contains mapped params used for the request
|
|
305
|
+
|
|
306
|
+
Example from `pages/profile/[username].vue`:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
const profileHttp = await app.$di.profile.info({
|
|
310
|
+
effect(data) {
|
|
311
|
+
if (data.status === 'error' && data.kind === 'not_found') {
|
|
312
|
+
showError(createError({
|
|
313
|
+
fatal: true,
|
|
314
|
+
statusCode: 404,
|
|
315
|
+
statusMessage: 'Page Not Found',
|
|
316
|
+
}))
|
|
286
317
|
}
|
|
287
|
-
}
|
|
318
|
+
},
|
|
319
|
+
initParams: {
|
|
320
|
+
username: String(profileParam.value),
|
|
321
|
+
},
|
|
322
|
+
server: true,
|
|
288
323
|
})
|
|
289
324
|
```
|
|
290
325
|
|
|
291
|
-
|
|
326
|
+
## 9. `data` and `error`
|
|
292
327
|
|
|
293
|
-
|
|
294
|
-
const products = await useHttp({
|
|
295
|
-
url: '/products',
|
|
296
|
-
})
|
|
328
|
+
`UseHttpResult<T, P>` is split like this:
|
|
297
329
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
```
|
|
330
|
+
- `data`: success payload only
|
|
331
|
+
- `error`: configured project error payload only
|
|
301
332
|
|
|
302
|
-
|
|
333
|
+
Internally the split is done by runtime error predicate:
|
|
303
334
|
|
|
304
|
-
-
|
|
305
|
-
-
|
|
335
|
+
- global `isError` from `createUseHttp(...)`
|
|
336
|
+
- or per-request `isError`
|
|
337
|
+
- fallback: `payload.status === 'error'`
|
|
306
338
|
|
|
307
|
-
|
|
339
|
+
Important:
|
|
308
340
|
|
|
309
|
-
-
|
|
310
|
-
-
|
|
341
|
+
- runtime error predicate does not reconfigure TypeScript types
|
|
342
|
+
- TypeScript error type comes from `declare module '@brickflow/http'`
|
|
311
343
|
|
|
312
|
-
##
|
|
344
|
+
## 10. Supported request options
|
|
313
345
|
|
|
314
|
-
|
|
346
|
+
For `useHttp` / `createGet`:
|
|
315
347
|
|
|
316
|
-
|
|
317
|
-
|
|
348
|
+
- `url`
|
|
349
|
+
- `initParams`
|
|
350
|
+
- `mapParams`
|
|
351
|
+
- `effect`
|
|
352
|
+
- `ignore`
|
|
353
|
+
- `isError`
|
|
354
|
+
- `lazy`
|
|
355
|
+
- `server`
|
|
318
356
|
|
|
319
|
-
|
|
320
|
-
addHttpRequestMiddleware((request) => {
|
|
321
|
-
request.headers.set('X-App-Version', '1.0.0')
|
|
322
|
-
})
|
|
357
|
+
Example with `initParams`:
|
|
323
358
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
359
|
+
```ts
|
|
360
|
+
const myContentHttp = await app.$di.content.my({
|
|
361
|
+
initParams: {
|
|
362
|
+
limit: props.limit,
|
|
363
|
+
offset: 0,
|
|
364
|
+
order: selectedOrder.value,
|
|
365
|
+
orderColumn: 'date',
|
|
366
|
+
type: selectedType.value,
|
|
367
|
+
},
|
|
329
368
|
})
|
|
330
369
|
```
|
|
331
370
|
|
|
332
|
-
|
|
371
|
+
Example with `fetch(...)` overriding params:
|
|
333
372
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
373
|
+
```ts
|
|
374
|
+
await myContentHttp.fetch({
|
|
375
|
+
limit: props.limit,
|
|
376
|
+
offset,
|
|
377
|
+
order: selectedOrder.value,
|
|
378
|
+
orderColumn: 'date',
|
|
379
|
+
type: selectedType.value,
|
|
380
|
+
})
|
|
381
|
+
```
|
|
342
382
|
|
|
343
|
-
|
|
383
|
+
## 11. Cache behavior
|
|
344
384
|
|
|
345
|
-
|
|
346
|
-
- `request`
|
|
385
|
+
When `getCache` is provided, `createUseHttp`:
|
|
347
386
|
|
|
348
|
-
|
|
387
|
+
- tries cached value first
|
|
388
|
+
- calls `effect(..., { cached: true })` for cached payload
|
|
389
|
+
- then performs fresh request
|
|
390
|
+
- stores success response in cache
|
|
391
|
+
- invalidates related keys when response hash changes
|
|
349
392
|
|
|
350
|
-
|
|
351
|
-
import { addHttpRequestMiddleware, removeHttpRequestMiddleware } from '@brickflow/http'
|
|
393
|
+
In this repo the cache is backed by IndexedDB in `core/util.ts`.
|
|
352
394
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
395
|
+
## 12. URL and hash helpers
|
|
396
|
+
|
|
397
|
+
The package also exports helpers used by the current implementation:
|
|
356
398
|
|
|
357
|
-
|
|
358
|
-
|
|
399
|
+
```ts
|
|
400
|
+
import { createURL, hashData } from '@brickflow/http'
|
|
359
401
|
```
|
|
360
402
|
|
|
361
|
-
|
|
403
|
+
`createURL(url, params)` builds query strings.
|
|
362
404
|
|
|
363
|
-
|
|
405
|
+
`hashData(data)` computes response hash for cache invalidation.
|
|
364
406
|
|
|
365
|
-
|
|
366
|
-
import { createHttpClient } from '@brickflow/http'
|
|
367
|
-
|
|
368
|
-
const http = createHttpClient({
|
|
369
|
-
baseURL: 'https://api.example.com',
|
|
370
|
-
requestTimeoutMs: 10000,
|
|
371
|
-
retry: {
|
|
372
|
-
delay: 250,
|
|
373
|
-
retries: 2,
|
|
374
|
-
},
|
|
375
|
-
})
|
|
407
|
+
## 13. Recommended usage in this repo
|
|
376
408
|
|
|
377
|
-
|
|
378
|
-
```
|
|
409
|
+
Use `createHttp` when:
|
|
379
410
|
|
|
380
|
-
|
|
411
|
+
- you need direct `get/post`
|
|
412
|
+
- you are writing mutations or one-shot calls
|
|
381
413
|
|
|
382
|
-
|
|
383
|
-
const http = createHttpClient({
|
|
384
|
-
baseURL: async () => `https://${tenant.value}.api.example.com`,
|
|
385
|
-
createHeaders: async () => {
|
|
386
|
-
return {
|
|
387
|
-
Authorization: `Bearer ${token}`,
|
|
388
|
-
}
|
|
389
|
-
},
|
|
390
|
-
})
|
|
391
|
-
```
|
|
414
|
+
Use `createUseHttp` + `createGet` when:
|
|
392
415
|
|
|
393
|
-
|
|
416
|
+
- you need SSR-aware async state
|
|
417
|
+
- you need `pending`, `pendingCache`, `hasFirstData`, `hasFreshData`
|
|
418
|
+
- you need cache integration
|
|
419
|
+
- you want reusable typed endpoint factories in domain modules
|
|
420
|
+
|
|
421
|
+
Use `type.d.ts` when:
|
|
394
422
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
-
|
|
398
|
-
- `createHttpClient`
|
|
399
|
-
- `createTypedHttpClient`
|
|
400
|
-
- `createStrictHttpClient`
|
|
401
|
-
- `defineHttpRoutes`
|
|
402
|
-
- `addHttpRequestMiddleware`
|
|
403
|
-
- `addHttpResponseMiddleware`
|
|
404
|
-
- `removeHttpRequestMiddleware`
|
|
405
|
-
- `removeHttpResponseMiddleware`
|
|
406
|
-
- public TypeScript types for client, config, middleware, payloads, and typed route maps
|
|
423
|
+
- you want to define endpoint keys
|
|
424
|
+
- you want to define the project-wide error type
|
|
425
|
+
- you want all consumers to infer the same API schema
|