vue-api-request-builder 0.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.
@@ -0,0 +1,55 @@
1
+ // 基础键值对类型
2
+ export interface KeyValuePair {
3
+ key: string;
4
+ value: string;
5
+ }
6
+
7
+ // 认证相关类型
8
+ export interface AuthConfig {
9
+ type: 'none' | 'Basic' | 'Bearer';
10
+ username?: string;
11
+ password?: string;
12
+ token?: string;
13
+ }
14
+
15
+ // 请求体类型
16
+ export interface RequestBody {
17
+ type: 'application/json' | 'multipart/form-data' | 'text/plain';
18
+ json?: string;
19
+ formData?: KeyValuePair[];
20
+ raw?: string;
21
+ }
22
+
23
+ // 响应类型
24
+ export interface ResponseData {
25
+ status: string;
26
+ headers: Record<string, string>;
27
+ body: string;
28
+ timing?: number;
29
+ }
30
+
31
+ // 完整的请求Schema类型
32
+ export interface RequestSchema {
33
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'OPTIONS';
34
+ url: string;
35
+ path: string;
36
+ auth: AuthConfig;
37
+ params: KeyValuePair[];
38
+ headers: KeyValuePair[];
39
+ body: RequestBody;
40
+ }
41
+
42
+ // 默认的请求Schema
43
+ export const defaultRequestSchema: RequestSchema = {
44
+ method: 'GET',
45
+ url: 'https://yesno.wtf',
46
+ path: '/api',
47
+ auth: {
48
+ type: 'none'
49
+ },
50
+ params: [],
51
+ headers: [],
52
+ body: {
53
+ type: 'application/json'
54
+ },
55
+ };
@@ -0,0 +1,194 @@
1
+ import type { RequestSchema, ResponseData } from '../types/request';
2
+
3
+ export type RequestMethod = 'fetch' | 'xhr';
4
+
5
+ export async function executeRequest(schema: RequestSchema, method: RequestMethod = 'xhr'): Promise<ResponseData> {
6
+ if (method === 'fetch') {
7
+ return executeFetchRequest(schema);
8
+ } else {
9
+ return executeXHRRequest(schema);
10
+ }
11
+ }
12
+
13
+ async function executeFetchRequest(schema: RequestSchema): Promise<ResponseData> {
14
+ // Build URL with query parameters
15
+ const queryString = schema.params
16
+ .filter(p => !!p.key)
17
+ .map(p => `${p.key}=${encodeURIComponent(p.value)}`)
18
+ .join('&');
19
+ const fullUrl = `${schema.url}${schema.path}${queryString ? '?' + queryString : ''}`;
20
+
21
+ // Prepare headers
22
+ const headers = new Headers();
23
+ schema.headers.forEach(header => {
24
+ if (header.key) {
25
+ headers.append(header.key, header.value);
26
+ }
27
+ });
28
+
29
+ // Prepare request options
30
+ const options: RequestInit = {
31
+ method: schema.method,
32
+ headers,
33
+ credentials: 'omit'
34
+ };
35
+
36
+ // Handle authentication
37
+ if (schema.auth.type === 'Basic' && schema.auth.username && schema.auth.password) {
38
+ const auth = btoa(`${schema.auth.username}:${schema.auth.password}`);
39
+ headers.append('Authorization', `Basic ${auth}`);
40
+ } else if (schema.auth.type === 'Bearer' && schema.auth.token) {
41
+ headers.append('Authorization', `Bearer ${schema.auth.token}`);
42
+ }
43
+
44
+ // Handle request body for POST/PUT methods
45
+ if (schema.method === 'POST' || schema.method === 'PUT') {
46
+ switch (schema.body.type) {
47
+ case 'application/json':
48
+ options.body = schema.body.json || '';
49
+ headers.set('Content-Type', 'application/json; charset=utf-8');
50
+ break;
51
+ case 'multipart/form-data':
52
+ const formData = new FormData();
53
+ schema.body.formData?.forEach(param => {
54
+ if (param.key) {
55
+ formData.append(param.key, param.value);
56
+ }
57
+ });
58
+ options.body = formData;
59
+ break;
60
+ case 'text/plain':
61
+ options.body = schema.body.raw || '';
62
+ headers.set('Content-Type', 'text/plain; charset=utf-8');
63
+ break;
64
+ }
65
+ }
66
+
67
+ try {
68
+ const response = await fetch(fullUrl, options);
69
+ const headers: Record<string, string> = {};
70
+ response.headers.forEach((value, key) => {
71
+ headers[key.toLowerCase()] = value;
72
+ });
73
+
74
+ let body = '';
75
+ const contentType = headers['content-type'] || '';
76
+ if (contentType.startsWith('application/json')) {
77
+ try {
78
+ const json = await response.json();
79
+ body = JSON.stringify(json, null, 2);
80
+ } catch (e) {
81
+ body = await response.text();
82
+ }
83
+ } else {
84
+ body = await response.text();
85
+ }
86
+
87
+ return {
88
+ status: response.status.toString(),
89
+ headers,
90
+ body
91
+ };
92
+ } catch (error) {
93
+ throw new Error('Request failed');
94
+ }
95
+ }
96
+
97
+ async function executeXHRRequest(schema: RequestSchema): Promise<ResponseData> {
98
+ return new Promise((resolve, reject) => {
99
+ const xhr = new XMLHttpRequest();
100
+ const user = schema.auth.type === 'Basic' ? schema.auth.username : null;
101
+ const pswd = schema.auth.type === 'Basic' ? schema.auth.password : null;
102
+
103
+ // Build URL with query parameters
104
+ const queryString = schema.params
105
+ .filter(p => !!p.key)
106
+ .map(p => `${p.key}=${encodeURIComponent(p.value)}`)
107
+ .join('&');
108
+ const fullUrl = `${schema.url}${schema.path}${queryString ? '?' + queryString : ''}`;
109
+
110
+ xhr.open(schema.method, fullUrl, true, user, pswd);
111
+
112
+ // Add headers
113
+ schema.headers.forEach(header => {
114
+ if (header.key) {
115
+ xhr.setRequestHeader(header.key, header.value);
116
+ }
117
+ });
118
+
119
+ // Add Bearer token if present
120
+ if (schema.auth.type === 'Bearer' && schema.auth.token) {
121
+ xhr.setRequestHeader('Authorization', `Bearer ${schema.auth.token}`);
122
+ }
123
+
124
+ // Handle request body for POST/PUT methods
125
+ if (schema.method === 'POST' || schema.method === 'PUT') {
126
+ let requestBody = '';
127
+
128
+ switch (schema.body.type) {
129
+ case 'application/json':
130
+ requestBody = schema.body.json || '';
131
+ xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
132
+ break;
133
+ case 'multipart/form-data':
134
+ const formData = new FormData();
135
+ schema.body.formData?.forEach(param => {
136
+ if (param.key) {
137
+ formData.append(param.key, param.value);
138
+ }
139
+ });
140
+ requestBody = formData as any;
141
+ // Let browser handle multipart/form-data Content-Type and boundary
142
+ break;
143
+ case 'text/plain':
144
+ requestBody = schema.body.raw || '';
145
+ xhr.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');
146
+ break;
147
+ }
148
+
149
+ xhr.send(requestBody);
150
+ } else {
151
+ xhr.send();
152
+ }
153
+
154
+ xhr.onload = () => {
155
+ const headers = parseHeaders(xhr);
156
+ const response: ResponseData = {
157
+ status: xhr.status.toString(),
158
+ headers,
159
+ body: ''
160
+ };
161
+
162
+ if ((headers['content-type'] || '').startsWith('application/json')) {
163
+ try {
164
+ response.body = JSON.stringify(JSON.parse(xhr.responseText), null, 2);
165
+ } catch (e) {
166
+ response.body = xhr.responseText;
167
+ }
168
+ } else {
169
+ response.body = xhr.responseText;
170
+ }
171
+
172
+ resolve(response);
173
+ };
174
+
175
+ xhr.onerror = () => {
176
+ reject(new Error('Request failed'));
177
+ };
178
+ });
179
+ }
180
+
181
+ function parseHeaders(xhr: XMLHttpRequest): Record<string, string> {
182
+ const headers = xhr
183
+ .getAllResponseHeaders()
184
+ .trim()
185
+ .split(/[\r\n]+/);
186
+ const headerMap: Record<string, string> = {};
187
+ headers.forEach(function (line) {
188
+ const parts = line.split(': ');
189
+ const header = parts.shift()?.toLowerCase() || '';
190
+ const value = parts.join(': ');
191
+ headerMap[header] = value;
192
+ });
193
+ return headerMap;
194
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "vue-api-request-builder",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.umd.js",
6
+ "module": "dist/index.es.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "lib"
11
+ ],
12
+ "scripts": {
13
+ "dev": "vite",
14
+ "build": "vue-tsc -b && vite build --config vite.lib.config.ts",
15
+ "build:static": "vue-tsc -b && vite build",
16
+ "preview": "vite preview"
17
+ },
18
+ "peerDependencies": {
19
+ "ant-design-vue": "^4.0.0",
20
+ "vue": "^3.0.0"
21
+ },
22
+ "dependencies": {
23
+ "ant-design-vue": "4.x",
24
+ "vue": "^3.5.13"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^20.0.0",
28
+ "@unocss/preset-attributify": "^66.1.0",
29
+ "@unocss/preset-icons": "^66.1.0",
30
+ "@unocss/preset-uno": "^66.1.0",
31
+ "@vitejs/plugin-vue": "^5.2.3",
32
+ "@vue/tsconfig": "^0.7.0",
33
+ "typescript": "~5.8.3",
34
+ "unocss": "^66.1.0",
35
+ "vite": "^6.3.5",
36
+ "vite-plugin-dts": "^4.5.3",
37
+ "vue-tsc": "^2.2.8"
38
+ },
39
+ "keywords": [
40
+ "vue",
41
+ "api",
42
+ "request",
43
+ "builder",
44
+ "http",
45
+ "rest"
46
+ ],
47
+ "author": "",
48
+ "license": "MIT"
49
+ }