vue-api-kit 1.0.0 → 1.1.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 CHANGED
@@ -1,15 +1,243 @@
1
- # vue-api-kit
1
+ # 🚀 vue-api-kit
2
2
 
3
- To install dependencies:
3
+ A powerful and type-safe API client for Vue 3 applications with built-in validation using Zod.
4
+
5
+ ## 📦 Installation
4
6
 
5
7
  ```bash
6
- bun install
8
+ npm install vue-api-kit
7
9
  ```
8
10
 
9
- To run:
11
+ ## ⚡ Quick Start
10
12
 
11
- ```bash
12
- bun run index.ts
13
+ ```typescript
14
+ import { createApiClient } from 'vue-api-kit';
15
+ import { z } from 'zod';
16
+
17
+ // Define your API client
18
+ const api = createApiClient({
19
+ baseURL: 'https://jsonplaceholder.typicode.com',
20
+ queries: {
21
+ getUsers: {
22
+ path: '/users',
23
+ response: z.array(z.object({
24
+ id: z.number(),
25
+ name: z.string(),
26
+ email: z.string()
27
+ }))
28
+ },
29
+ getUser: {
30
+ path: '/users/{id}',
31
+ params: z.object({ id: z.number() }),
32
+ response: z.object({
33
+ id: z.number(),
34
+ name: z.string(),
35
+ email: z.string()
36
+ })
37
+ }
38
+ },
39
+ mutations: {
40
+ createUser: {
41
+ method: 'POST',
42
+ path: '/users',
43
+ data: z.object({
44
+ name: z.string(),
45
+ email: z.string().email()
46
+ }),
47
+ response: z.object({
48
+ id: z.number(),
49
+ name: z.string(),
50
+ email: z.string()
51
+ })
52
+ },
53
+ updateUser: {
54
+ method: 'PUT',
55
+ path: '/users/{id}',
56
+ params: z.object({ id: z.number() }),
57
+ data: z.object({
58
+ name: z.string(),
59
+ email: z.string().email()
60
+ })
61
+ },
62
+ deleteUser: {
63
+ method: 'DELETE',
64
+ path: '/users/{id}',
65
+ params: z.object({ id: z.number() })
66
+ }
67
+ }
68
+ });
13
69
  ```
14
70
 
15
- This project was created using `bun init` in bun v1.3.4. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
71
+ ## 📖 Usage in Vue Components
72
+
73
+ ### Queries (GET requests)
74
+
75
+ ```vue
76
+ <script setup lang="ts">
77
+ import { api } from './api';
78
+
79
+ // Simple query - loads automatically on mount
80
+ const { result, isLoading, errorMessage } = api.query.getUsers();
81
+
82
+ // Query with parameters
83
+ const userId = ref(1);
84
+ const { result: user, isLoading: loading, refetch } = api.query.getUser({
85
+ params: { id: userId }
86
+ });
87
+
88
+ // Query with options
89
+ const { result: data } = api.query.getUsers({
90
+ loadOnMount: true,
91
+ debounce: 300,
92
+ onResult: (data) => {
93
+ console.log('Data loaded:', data);
94
+ },
95
+ onError: (error) => {
96
+ console.error('Error:', error);
97
+ }
98
+ });
99
+ </script>
100
+
101
+ <template>
102
+ <div>
103
+ <div v-if="isLoading">Loading...</div>
104
+ <div v-else-if="errorMessage">Error: {{ errorMessage }}</div>
105
+ <ul v-else>
106
+ <li v-for="user in result" :key="user.id">
107
+ {{ user.name }}
108
+ </li>
109
+ </ul>
110
+ </div>
111
+ </template>
112
+ ```
113
+
114
+ ### Mutations (POST, PUT, DELETE)
115
+
116
+ ```vue
117
+ <script setup lang="ts">
118
+ import { api } from './api';
119
+ import { ref } from 'vue';
120
+
121
+ const { mutate, isLoading, result, errorMessage } = api.mutation.createUser({
122
+ onResult: (data) => {
123
+ console.log('User created:', data);
124
+ },
125
+ onError: (error) => {
126
+ console.error('Error:', error);
127
+ }
128
+ });
129
+
130
+ const name = ref('');
131
+ const email = ref('');
132
+
133
+ async function handleSubmit() {
134
+ await mutate({
135
+ name: name.value,
136
+ email: email.value
137
+ });
138
+ }
139
+ </script>
140
+
141
+ <template>
142
+ <form @submit.prevent="handleSubmit">
143
+ <input v-model="name" placeholder="Name" />
144
+ <input v-model="email" placeholder="Email" />
145
+ <button type="submit" :disabled="isLoading">
146
+ {{ isLoading ? 'Creating...' : 'Create User' }}
147
+ </button>
148
+ <p v-if="errorMessage" class="error">{{ errorMessage }}</p>
149
+ </form>
150
+ </template>
151
+ ```
152
+
153
+ ## 🎯 Features
154
+
155
+ - ✅ **Type-Safe**: Full TypeScript support with automatic type inference
156
+ - ✅ **Zod Validation**: Built-in request/response validation
157
+ - ✅ **Vue 3 Composition API**: Reactive state management
158
+ - ✅ **Auto Loading States**: Built-in loading, error, and success states
159
+ - ✅ **File Upload**: Support for multipart/form-data
160
+ - ✅ **Path Parameters**: Automatic path parameter replacement
161
+ - ✅ **Debouncing**: Built-in request debouncing
162
+ - ✅ **Global Error Handling**: Centralized error management
163
+ - ✅ **Request Interceptors**: Modify requests before sending
164
+
165
+ ## 🔧 Advanced Configuration
166
+
167
+ ```typescript
168
+ const api = createApiClient({
169
+ baseURL: 'https://api.example.com',
170
+ headers: {
171
+ 'Authorization': 'Bearer token'
172
+ },
173
+ withCredentials: true,
174
+
175
+ // Global handlers
176
+ onBeforeRequest: async (config) => {
177
+ // Modify request before sending
178
+ const token = localStorage.getItem('token');
179
+ config.headers.Authorization = `Bearer ${token}`;
180
+ return config;
181
+ },
182
+
183
+ onStartRequest: async () => {
184
+ // Called when request starts
185
+ console.log('Request started');
186
+ },
187
+
188
+ onFinishRequest: async () => {
189
+ // Called when request finishes
190
+ console.log('Request finished');
191
+ },
192
+
193
+ onErrorRequest: (error) => {
194
+ // Global error handler
195
+ console.error('API Error:', error.message);
196
+ },
197
+
198
+ onZodError: (issues) => {
199
+ // Handle validation errors
200
+ console.error('Validation errors:', issues);
201
+ },
202
+
203
+ queries: { /* ... */ },
204
+ mutations: { /* ... */ }
205
+ });
206
+ ```
207
+
208
+ ## 📤 File Upload Example
209
+
210
+ ```typescript
211
+ const api = createApiClient({
212
+ baseURL: 'https://api.example.com',
213
+ mutations: {
214
+ uploadImage: {
215
+ method: 'POST',
216
+ path: '/upload',
217
+ isMultipart: true, // Enable multipart/form-data
218
+ response: z.object({
219
+ url: z.string()
220
+ })
221
+ }
222
+ }
223
+ });
224
+
225
+ // In component
226
+ const { mutate, uploadProgress } = api.mutation.uploadImage({
227
+ onUploadProgress: (progress) => {
228
+ console.log(`Upload progress: ${progress}%`);
229
+ }
230
+ });
231
+
232
+ async function handleUpload(file: File) {
233
+ await mutate({ file });
234
+ }
235
+ ```
236
+
237
+ ## 📝 License
238
+
239
+ MIT
240
+
241
+ ## 👤 Author
242
+
243
+ MelvishNiz - [GitHub](https://github.com/MelvishNiz)
@@ -1,5 +1,47 @@
1
1
  import { ApiClientOptions, ApiMutation, ApiQuery, Infer, MutationResult, QueryResult, UseMutationOptions, UseQueryOptions } from './types';
2
+ /**
3
+ * Creates a type-safe API client with query and mutation hooks for Vue 3
4
+ * @template Q - Record of query endpoint definitions
5
+ * @template M - Record of mutation endpoint definitions
6
+ * @param {ApiClientOptions<Q, M>} options - Configuration options for the API client
7
+ * @returns {Object} API client with query and mutation hooks
8
+ * @example
9
+ * import { createApiClient } from 'vue-api-kit';
10
+ * import { z } from 'zod';
11
+ *
12
+ * const api = createApiClient({
13
+ * baseURL: 'https://jsonplaceholder.typicode.com',
14
+ * queries: {
15
+ * getUsers: {
16
+ * path: '/users',
17
+ * response: z.array(z.object({
18
+ * id: z.number(),
19
+ * name: z.string()
20
+ * }))
21
+ * }
22
+ * },
23
+ * mutations: {
24
+ * createUser: {
25
+ * method: 'POST',
26
+ * path: '/users',
27
+ * data: z.object({
28
+ * name: z.string(),
29
+ * email: z.string().email()
30
+ * }),
31
+ * response: z.object({
32
+ * id: z.number(),
33
+ * name: z.string(),
34
+ * email: z.string()
35
+ * })
36
+ * }
37
+ * }
38
+ * });
39
+ *
40
+ * // In your Vue component:
41
+ * const { result, isLoading } = api.query.getUsers();
42
+ * const { mutate } = api.mutation.createUser();
43
+ */
2
44
  export declare function createApiClient<Q extends Record<string, ApiQuery>, M extends Record<string, ApiMutation>>(options: ApiClientOptions<Q, M>): {
3
- query: { [K in keyof Q]: (options?: UseQueryOptions<Infer<Q[K]["params"]>>) => QueryResult<Infer<Q[K]["response"]>>; };
4
- mutation: { [K_1 in keyof M]: (options?: UseMutationOptions) => MutationResult<Infer<M[K_1]["response"]>, Infer<M[K_1]["data"]>>; };
45
+ query: { [K in keyof Q]: (options?: UseQueryOptions<Infer<Q[K]["params"]>, Infer<Q[K]["response"]>>) => QueryResult<Infer<Q[K]["response"]>>; };
46
+ mutation: { [K_1 in keyof M]: (options?: UseMutationOptions<Infer<M[K_1]["response"]>>) => MutationResult<Infer<M[K_1]["response"]>, Infer<M[K_1]["data"]>>; };
5
47
  };
@@ -1,15 +1,52 @@
1
- import { InternalAxiosRequestConfig } from 'axios';
1
+ import { AxiosError, InternalAxiosRequestConfig } from 'axios';
2
2
  import { Ref } from 'vue';
3
- import { ZodType } from 'zod';
3
+ import { ZodError, ZodType } from 'zod';
4
4
  import { $ZodIssue } from 'zod/v4/core';
5
+ /**
6
+ * HTTP methods supported by the API client
7
+ * @example
8
+ * const method: HTTPMethod = "GET";
9
+ */
5
10
  export type HTTPMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
11
+ /**
12
+ * Infer TypeScript type from Zod schema
13
+ * @template T - Zod schema type
14
+ * @example
15
+ * const userSchema = z.object({ id: z.number(), name: z.string() });
16
+ * type User = Infer<typeof userSchema>; // { id: number; name: string }
17
+ */
6
18
  export type Infer<T> = T extends ZodType<infer U> ? U : any;
19
+ /**
20
+ * Defines a query (GET request) endpoint configuration
21
+ * @template TParams - Zod schema for query parameters
22
+ * @template TResponse - Zod schema for response data
23
+ * @example
24
+ * const getUsers: ApiQuery = {
25
+ * method: "GET",
26
+ * path: "/users",
27
+ * params: z.object({ page: z.number() }),
28
+ * response: z.array(z.object({ id: z.number(), name: z.string() }))
29
+ * };
30
+ */
7
31
  export interface ApiQuery<TParams extends ZodType<any> | undefined = ZodType<any> | undefined, TResponse extends ZodType<any> | undefined = ZodType<any> | undefined> {
8
32
  method?: Extract<HTTPMethod, "GET">;
9
33
  path: string;
10
34
  params?: TParams;
11
35
  response?: TResponse;
12
36
  }
37
+ /**
38
+ * Defines a mutation (POST, PUT, PATCH, DELETE) endpoint configuration
39
+ * @template TData - Zod schema for request body
40
+ * @template TResponse - Zod schema for response data
41
+ * @template TParams - Zod schema for path/query parameters
42
+ * @example
43
+ * const createUser: ApiMutation = {
44
+ * method: "POST",
45
+ * path: "/users",
46
+ * data: z.object({ name: z.string(), email: z.string().email() }),
47
+ * response: z.object({ id: z.number(), name: z.string(), email: z.string() })
48
+ * };
49
+ */
13
50
  export interface ApiMutation<TData extends ZodType<any> | undefined = ZodType<any> | undefined, TResponse extends ZodType<any> | undefined = ZodType<any> | undefined, TParams extends ZodType<any> | undefined = ZodType<any> | undefined> {
14
51
  method: HTTPMethod;
15
52
  path: string;
@@ -18,14 +55,29 @@ export interface ApiMutation<TData extends ZodType<any> | undefined = ZodType<an
18
55
  response?: TResponse;
19
56
  isMultipart?: boolean;
20
57
  }
58
+ /**
59
+ * Configuration options for creating an API client
60
+ * @template Q - Record of query endpoint definitions
61
+ * @template M - Record of mutation endpoint definitions
62
+ * @example
63
+ * const options: ApiClientOptions = {
64
+ * baseURL: "https://api.example.com",
65
+ * headers: { Authorization: "Bearer token" },
66
+ * queries: { getUsers: { path: "/users" } },
67
+ * mutations: { createUser: { method: "POST", path: "/users" } },
68
+ * onErrorRequest: (error) => console.error(error.message)
69
+ * };
70
+ */
21
71
  export interface ApiClientOptions<Q extends Record<string, ApiQuery> = Record<string, ApiQuery>, M extends Record<string, ApiMutation> = Record<string, ApiMutation>> {
22
72
  baseURL: string;
23
73
  headers?: Record<string, string>;
24
74
  withCredentials?: boolean;
25
75
  queries?: Q;
26
76
  mutations?: M;
27
- beforeRequest?: (config: InternalAxiosRequestConfig<any>) => Promise<any> | any;
28
- onError?: (error: {
77
+ onBeforeRequest?: (config: InternalAxiosRequestConfig<any>) => Promise<any> | any;
78
+ onStartRequest?: () => Promise<void>;
79
+ onFinishRequest?: () => Promise<void>;
80
+ onErrorRequest?: (error: {
29
81
  message: string;
30
82
  status?: number;
31
83
  code?: string;
@@ -33,31 +85,76 @@ export interface ApiClientOptions<Q extends Record<string, ApiQuery> = Record<st
33
85
  }) => void;
34
86
  onZodError?: (issues: Omit<$ZodIssue, "input">[]) => void;
35
87
  }
36
- export interface UseQueryOptions<TParams = any> {
88
+ /**
89
+ * Options for configuring a query hook
90
+ * @template TParams - Type of query parameters
91
+ * @template TResult - Type of result data
92
+ * @example
93
+ * const options: UseQueryOptions = {
94
+ * params: { page: 1 },
95
+ * loadOnMount: true,
96
+ * debounce: 300,
97
+ * onResult: (data) => console.log(data),
98
+ * onError: (error) => console.error(error)
99
+ * };
100
+ */
101
+ export interface UseQueryOptions<TParams = any, TResult = any> {
37
102
  params?: TParams;
38
103
  loadOnMount?: boolean;
39
104
  debounce?: number;
40
- onResult?: (data: any) => void;
41
- onError?: (error: string) => void;
105
+ onResult?: (result: TResult) => void;
106
+ onError?: (error: AxiosError | ZodError | Error) => void;
42
107
  onZodError?: (issues: Omit<$ZodIssue, "input">[]) => void;
43
108
  }
44
- export interface UseMutationOptions<_TData = any> {
45
- onResult?: (data: any) => void;
46
- onError?: (error: string) => void;
109
+ /**
110
+ * Options for configuring a mutation hook
111
+ * @template TResult - Type of result data
112
+ * @example
113
+ * const options: UseMutationOptions = {
114
+ * onResult: (data) => console.log("Success:", data),
115
+ * onError: (error) => console.error("Error:", error),
116
+ * onUploadProgress: (progress) => console.log(`Upload: ${progress}%`)
117
+ * };
118
+ */
119
+ export interface UseMutationOptions<TResult = any> {
120
+ onResult?: (result: TResult) => void;
121
+ onError?: (error: AxiosError | ZodError | Error) => void;
47
122
  onZodError?: (issues: Omit<$ZodIssue, "input">[]) => void;
48
123
  onUploadProgress?: (progress: number) => void;
49
124
  }
50
- export interface QueryResult<T> {
51
- result: Ref<T | undefined>;
52
- error: Ref<string | undefined>;
125
+ /**
126
+ * Return type from a query hook
127
+ * @template TResult - Type of result data
128
+ * @example
129
+ * const { result, isLoading, errorMessage, refetch } = useGetUsers();
130
+ * // result.value contains the data
131
+ * // isLoading.value indicates loading state
132
+ * // errorMessage.value contains any error message
133
+ * // refetch() to manually trigger a new request
134
+ */
135
+ export interface QueryResult<TResult> {
136
+ result: Ref<TResult | undefined>;
137
+ errorMessage: Ref<string | undefined>;
53
138
  zodErrors: Ref<Omit<$ZodIssue, "input">[] | undefined>;
54
139
  isLoading: Ref<boolean>;
55
140
  isDone: Ref<boolean>;
56
141
  refetch: () => Promise<void>;
57
142
  }
58
- export interface MutationResult<T, TData> {
59
- result: Ref<T | undefined>;
60
- error: Ref<string | undefined>;
143
+ /**
144
+ * Return type from a mutation hook
145
+ * @template TResult - Type of result data
146
+ * @template TData - Type of mutation input data
147
+ * @example
148
+ * const { mutate, isLoading, result, errorMessage } = useCreateUser();
149
+ * // Call mutate() to trigger the mutation
150
+ * await mutate({ name: "John", email: "john@example.com" });
151
+ * // result.value contains the response
152
+ * // isLoading.value indicates loading state
153
+ * // uploadProgress.value shows upload progress (0-100)
154
+ */
155
+ export interface MutationResult<TResult, TData> {
156
+ result: Ref<TResult | undefined>;
157
+ errorMessage: Ref<string | undefined>;
61
158
  zodErrors: Ref<Omit<$ZodIssue, "input">[] | undefined>;
62
159
  isLoading: Ref<boolean>;
63
160
  isDone: Ref<boolean>;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export * as z from 'zod';
2
2
  export { createApiClient } from './core/client';
3
3
  export type * from './core/types';
4
+ export type { ZodError } from 'zod';
5
+ export { AxiosError } from 'axios';