@open-kingdom/shared-frontend-data-access-external-api 0.0.2-13 → 0.0.2-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 +244 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,7 +1,248 @@
|
|
|
1
1
|
# @open-kingdom/shared-frontend-data-access-external-api
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A unified integration layer for connecting any third-party REST API to the application's Redux store via RTK Query. The library provides `createAxiosBaseQuery` — an Axios-backed RTK Query base query factory — as the foundation for adding new external API integrations. The Cat Facts API is included as a reference implementation demonstrating the expected pattern; it is not the purpose of the library.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Adding a New External API
|
|
8
|
+
|
|
9
|
+
In your application, import `createAxiosBaseQuery` and use it as the `baseQuery` for a new RTK Query `createApi` instance. This lives in your app's own code — not inside this library.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// src/lib/weather-api/weather.api.ts (in your application)
|
|
13
|
+
import { createApi } from '@reduxjs/toolkit/query/react';
|
|
14
|
+
import { createAxiosBaseQuery } from '@open-kingdom/shared-frontend-data-access-external-api';
|
|
15
|
+
|
|
16
|
+
export const weatherApi = createApi({
|
|
17
|
+
reducerPath: 'weatherApi',
|
|
18
|
+
baseQuery: createAxiosBaseQuery({
|
|
19
|
+
baseUrl: 'https://api.openweathermap.org/data/2.5',
|
|
20
|
+
prepareHeaders: (headers) => {
|
|
21
|
+
headers.set('X-Api-Key', process.env.VITE_WEATHER_API_KEY ?? '');
|
|
22
|
+
return headers;
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
endpoints: (builder) => ({
|
|
26
|
+
getCurrentWeather: builder.query<WeatherResponse, string>({
|
|
27
|
+
query: (city) => ({ url: '/weather', params: { q: city } }),
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const WeatherApiKey = weatherApi.reducerPath;
|
|
33
|
+
export const weatherApiReducer = weatherApi.reducer;
|
|
34
|
+
export const weatherApiMiddleware = weatherApi.middleware;
|
|
35
|
+
export const { useGetCurrentWeatherQuery } = weatherApi;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Register the reducer and middleware in your store:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// src/store.ts (in your application)
|
|
42
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
43
|
+
import { WeatherApiKey, weatherApiReducer, weatherApiMiddleware } from './lib/weather-api/weather.api';
|
|
44
|
+
|
|
45
|
+
export const store = configureStore({
|
|
46
|
+
reducer: {
|
|
47
|
+
[WeatherApiKey]: weatherApiReducer,
|
|
48
|
+
// ...other reducers
|
|
49
|
+
},
|
|
50
|
+
middleware: (getDefault) => getDefault().concat(weatherApiMiddleware),
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then use the generated hook anywhere in your components:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { useGetCurrentWeatherQuery } from './lib/weather-api/weather.api';
|
|
58
|
+
|
|
59
|
+
function WeatherWidget({ city }: { city: string }) {
|
|
60
|
+
const { data, isLoading, error } = useGetCurrentWeatherQuery(city);
|
|
61
|
+
|
|
62
|
+
if (isLoading) return <p>Loading...</p>;
|
|
63
|
+
if (error) return <p>Could not load weather</p>;
|
|
64
|
+
return <p>{data?.weather[0].description}</p>;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Exports
|
|
71
|
+
|
|
72
|
+
### Base Query Factory
|
|
73
|
+
|
|
74
|
+
| Export | Type | Description |
|
|
75
|
+
| ------------------------------ | ----------------------------------------------- | ----------------------------------------------------- |
|
|
76
|
+
| `createAxiosBaseQuery(config)` | `(config: AxiosBaseQueryConfig) => BaseQueryFn` | Creates an RTK Query `baseQuery` function using Axios |
|
|
77
|
+
| `AxiosBaseQueryConfig` | `interface` | Configuration for the Axios base query |
|
|
78
|
+
| `AxiosBaseQueryArgs` | `interface` | Per-request arguments passed to the query |
|
|
79
|
+
| `AxiosBaseQueryError` | `interface` | Shape of errors returned on Axios failures |
|
|
80
|
+
| `AxiosBaseQueryMeta` | `interface` | Shape of response metadata |
|
|
81
|
+
|
|
82
|
+
### Cat Facts API (reference implementation)
|
|
83
|
+
|
|
84
|
+
| Export | Type | Description |
|
|
85
|
+
| ----------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
86
|
+
| `catFactsApi` | `Api<...>` | RTK Query `createApi` instance for `https://catfact.ninja`, `reducerPath: 'catFactsApi'` |
|
|
87
|
+
| `CatFactsApiKey` | `'catFactsApi'` | The reducer path string constant |
|
|
88
|
+
| `catFactsApiReducer` | `Reducer` | `catFactsApi.reducer` |
|
|
89
|
+
| `catFactsApiMiddleware` | `Middleware` | `catFactsApi.middleware` |
|
|
90
|
+
| `useGetFactQuery` | `QueryHook<CatFact, void>` | RTK Query hook for `GET /fact` |
|
|
91
|
+
| `useGetFactsQuery` | `QueryHook<PaginatedResponse<CatFact>, PaginationParams \| void>` | RTK Query hook for `GET /facts` |
|
|
92
|
+
| `useGetBreedsQuery` | `QueryHook<PaginatedResponse<Breed>, PaginationParams \| void>` | RTK Query hook for `GET /breeds` |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Type Definitions
|
|
97
|
+
|
|
98
|
+
### `AxiosBaseQueryConfig`
|
|
99
|
+
|
|
100
|
+
| Property | Type | Required | Default | Description |
|
|
101
|
+
| ---------------- | ------------------------------------------------------------ | -------- | ------- | ---------------------------------------------------------------------- |
|
|
102
|
+
| `baseUrl` | `string` | Yes | — | The base URL for all requests made by this query function |
|
|
103
|
+
| `prepareHeaders` | `(headers: AxiosHeaders, api: BaseQueryApi) => AxiosHeaders` | No | — | Optional hook to inject headers (e.g. auth tokens) before each request |
|
|
104
|
+
|
|
105
|
+
### `AxiosBaseQueryArgs`
|
|
106
|
+
|
|
107
|
+
| Property | Type | Required | Default | Description |
|
|
108
|
+
| --------- | ------------------------------ | -------- | ------- | ---------------------------- |
|
|
109
|
+
| `url` | `string` | Yes | — | Path appended to `baseUrl` |
|
|
110
|
+
| `method` | `AxiosRequestConfig['method']` | No | `'GET'` | HTTP method |
|
|
111
|
+
| `params` | `Record<string, unknown>` | No | — | URL query parameters |
|
|
112
|
+
| `body` | `unknown` | No | — | Request body |
|
|
113
|
+
| `headers` | `Record<string, string>` | No | — | Per-request header overrides |
|
|
114
|
+
|
|
115
|
+
Additional properties are passed through to the Axios config object.
|
|
116
|
+
|
|
117
|
+
### `AxiosBaseQueryError`
|
|
118
|
+
|
|
119
|
+
| Property | Type | Required | Description |
|
|
120
|
+
| --------- | --------- | -------- | ------------------------------------- |
|
|
121
|
+
| `status` | `number` | No | HTTP status code |
|
|
122
|
+
| `data` | `unknown` | No | Response body from the failed request |
|
|
123
|
+
| `headers` | `unknown` | No | Response headers |
|
|
124
|
+
|
|
125
|
+
### `AxiosBaseQueryMeta`
|
|
126
|
+
|
|
127
|
+
| Property | Type | Required | Description |
|
|
128
|
+
| --------- | -------------------- | -------- | ------------------------------------- |
|
|
129
|
+
| `headers` | `unknown` | No | Response headers |
|
|
130
|
+
| `status` | `number` | No | HTTP status code |
|
|
131
|
+
| `config` | `AxiosRequestConfig` | No | The Axios config used for the request |
|
|
132
|
+
|
|
133
|
+
### `CatFact`
|
|
134
|
+
|
|
135
|
+
| Property | Type | Description |
|
|
136
|
+
| -------- | -------- | ---------------------------- |
|
|
137
|
+
| `fact` | `string` | The fact text |
|
|
138
|
+
| `length` | `number` | Character length of the fact |
|
|
139
|
+
|
|
140
|
+
### `Breed`
|
|
141
|
+
|
|
142
|
+
| Property | Type | Description |
|
|
143
|
+
| --------- | -------- | ------------------ |
|
|
144
|
+
| `breed` | `string` | Breed name |
|
|
145
|
+
| `country` | `string` | Country of origin |
|
|
146
|
+
| `origin` | `string` | Origin description |
|
|
147
|
+
| `coat` | `string` | Coat type |
|
|
148
|
+
| `pattern` | `string` | Coat pattern |
|
|
149
|
+
|
|
150
|
+
### `PaginatedResponse<T>`
|
|
151
|
+
|
|
152
|
+
| Property | Type | Description |
|
|
153
|
+
| -------------- | -------- | -------------------------------------- |
|
|
154
|
+
| `current_page` | `number` | Current page number |
|
|
155
|
+
| `data` | `T[]` | Array of items for the current page |
|
|
156
|
+
| `last_page` | `number` | Total number of pages |
|
|
157
|
+
| `total` | `number` | Total number of items across all pages |
|
|
158
|
+
|
|
159
|
+
### `PaginationParams`
|
|
160
|
+
|
|
161
|
+
| Property | Type | Required | Description |
|
|
162
|
+
| -------- | -------- | -------- | ------------------------ |
|
|
163
|
+
| `page` | `number` | No | Page number to fetch |
|
|
164
|
+
| `limit` | `number` | No | Number of items per page |
|
|
165
|
+
|
|
166
|
+
Additional properties are forwarded to the query string.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Setup
|
|
171
|
+
|
|
172
|
+
### Adding the Cat Facts reference API to the store
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
176
|
+
import { CatFactsApiKey, catFactsApiReducer, catFactsApiMiddleware } from '@open-kingdom/shared-frontend-data-access-external-api';
|
|
177
|
+
|
|
178
|
+
export const store = configureStore({
|
|
179
|
+
reducer: {
|
|
180
|
+
[CatFactsApiKey]: catFactsApiReducer, // 'catFactsApi'
|
|
181
|
+
},
|
|
182
|
+
middleware: (getDefault) => getDefault().concat(catFactsApiMiddleware),
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Usage Examples
|
|
189
|
+
|
|
190
|
+
### Fetch a random cat fact
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
import { useGetFactQuery } from '@open-kingdom/shared-frontend-data-access-external-api';
|
|
194
|
+
|
|
195
|
+
function CatFactWidget() {
|
|
196
|
+
const { data, isLoading, error } = useGetFactQuery();
|
|
197
|
+
|
|
198
|
+
if (isLoading) return <p>Loading...</p>;
|
|
199
|
+
if (error) return <p>Error loading fact</p>;
|
|
200
|
+
return <p>{data?.fact}</p>;
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Fetch paginated facts
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
import { useGetFactsQuery } from '@open-kingdom/shared-frontend-data-access-external-api';
|
|
208
|
+
|
|
209
|
+
function CatFactsList() {
|
|
210
|
+
const { data } = useGetFactsQuery({ page: 1, limit: 10 });
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<ul>
|
|
214
|
+
{data?.data.map((item, i) => (
|
|
215
|
+
<li key={i}>{item.fact}</li>
|
|
216
|
+
))}
|
|
217
|
+
</ul>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Fetch cat breeds
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
import { useGetBreedsQuery } from '@open-kingdom/shared-frontend-data-access-external-api';
|
|
226
|
+
|
|
227
|
+
function BreedList() {
|
|
228
|
+
const { data } = useGetBreedsQuery({ page: 1, limit: 25 });
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<ul>
|
|
232
|
+
{data?.data.map((breed) => (
|
|
233
|
+
<li key={breed.breed}>
|
|
234
|
+
{breed.breed} — {breed.country}
|
|
235
|
+
</li>
|
|
236
|
+
))}
|
|
237
|
+
</ul>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Testing
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
nx test shared-frontend-data-access-external-api
|
|
248
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-kingdom/shared-frontend-data-access-external-api",
|
|
3
|
-
"version": "0.0.2-
|
|
3
|
+
"version": "0.0.2-15",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
|
+
"README.md",
|
|
21
22
|
"dist",
|
|
22
23
|
"!**/*.tsbuildinfo"
|
|
23
24
|
],
|