1
+ < config > {
2
+ "out": ".",
3
+ "css": false,
4
+ "jsMinify": true,
5
+ "jsObfuscate": false,
6
+ "jsScope": false,
7
+ "jsIIFE": false,
8
+ "prefix": null
9
+ }</ config >
10
+ < script >
11
+ class APICaller {
12
+ static #desc = [
13
+ 'OK' ,
14
+ 'Invalid request' ,
15
+ 'Authorization failed' ,
16
+ 'Request failed' ,
17
+ 'Server error' ,
18
+ 'Invalid server response (JSON error)' ,
19
+ ] ;
20
+ static #isObj( value ) {
21
+ return ( typeof value === 'object' && value !== null ) ;
22
+ }
23
+ #config;
24
+ logging = { } ;
25
+
26
+ constructor ( {
27
+ url,
28
+ headers = null ,
29
+ logging = {
30
+ master : true ,
31
+ collapsed : true ,
32
+ full : false ,
33
+
34
+ params : false ,
35
+ debug : true ,
36
+ meta : false ,
37
+ }
38
+ } = { } ) {
39
+ try {
40
+ url = ( new URL ( url ) ) . href ;
41
+ } catch ( error ) {
42
+ throw new Error ( `Invaild API url` ) ;
43
+ }
44
+ if ( ! url . endsWith ( '/' ) ) {
45
+ url = `${ url } /` ;
46
+ }
47
+ headers ??= { } ;
48
+ if ( ! APICaller . #isObj( headers ) ) {
49
+ throw new Error ( 'Invalid API headers; Expected an object;' ) ;
50
+ }
51
+ this . logging = Object . assign ( { } , this . logging , logging ) ;
52
+ this . #config = {
53
+ url,
54
+ headers
55
+ }
56
+ }
57
+ async coreFetch ( {
58
+ func = '' ,
59
+ params = null ,
60
+ headers = null ,
61
+ logging = { }
62
+ } = { } ) {
63
+ logging = Object . assign ( { } , this . logging , logging ) ;
64
+ headers ??= { } ;
65
+ if ( ! APICaller . #isObj( headers ) ) {
66
+ throw new Error ( 'Invalid API headers; Expected an object;' ) ;
67
+ }
68
+
69
+ let fetched ;
70
+ let ret = {
71
+ status : 0 ,
72
+ value : null ,
73
+ statusDesc : null ,
74
+ headers : null ,
75
+ meta : null ,
76
+ debug : null
77
+ } ;
78
+
79
+ // Create fetch config
80
+ const config = {
81
+ method : 'POST' ,
82
+ mode : 'cors'
83
+ } ;
84
+ // Combine default headers with current headers
85
+ config . headers = Object . assign ( { } , this . #config. headers , headers ) ;
86
+
87
+ // Add params if present
88
+ if ( APICaller . #isObj( params ) ) {
89
+ config . headers [ 'Content-Type' ] = 'application/json' ;
90
+ config . body = JSON . stringify ( params ) ;
91
+ } else {
92
+ config . method = 'GET' ;
93
+ }
94
+
95
+ const url = `${ this . #config. url } ${ func } ` ;
96
+
97
+ // Fetch data
98
+ try {
99
+ // console.log('API CALL', { url, params });
100
+ fetched = await window . fetch ( url , config ) ;
101
+ ret . headers = fetched . headers ;
102
+ } catch ( error ) {
103
+ ret . status = - 1 ;
104
+ ret . statusDesc = 'Network failed' ;
105
+ ret . value ??= error . message ;
106
+ return Promise . resolve ( ret ) ;
107
+ }
108
+ if ( ! fetched . ok ) {
109
+ ret . status = fetched . status ;
110
+ ret . statusDesc = APICaller . #desc[ 3 ] ;
111
+ ret . value = fetched . statusText ;
112
+ return Promise . resolve ( ret ) ;
113
+ }
114
+ fetched = await fetched . text ( ) . catch ( e => e . message ) ;
115
+ try {
116
+ const json = JSON . parse ( fetched ) ;
117
+ if ( ! APICaller . #isObj( json ) ) {
118
+ throw new Error ( 'Not object' ) ;
119
+ }
120
+ fetched = json ;
121
+ } catch ( error ) {
122
+ ret . status = 5 ;
123
+ ret . value = fetched ;
124
+ ret . statusDesc = APICaller . #desc[ 5 ] ;
125
+ return Promise . resolve ( ret ) ;
126
+ }
127
+ ret = { ...ret , ...fetched } ;
128
+
129
+ ret . statusDesc = APICaller . #desc[ ret . status ] ?? 'Unknown' ;
130
+
131
+ if ( logging . master ) {
132
+ if ( logging . full ) {
133
+ logging . collapsed ? console . groupCollapsed ( 'API Call:' , url ) : console . group ( 'API Call:' , url ) ;
134
+ console . log ( 'Request :' , { url, params, headers } ) ;
135
+ console . log ( 'Response:' , ret ) ;
136
+ console . groupEnd ( ) ;
137
+ } else {
138
+ logging . collapsed ? console . groupCollapsed ( 'API Call:' , url ) : console . group ( 'API Call:' , url ) ;
139
+ if ( logging . params ) {
140
+ console . group ( 'Request Params:' , params ) ;
141
+ }
142
+ if ( logging . meta ) {
143
+ console . log ( 'Response Meta:' , ret . meta ) ;
144
+ }
145
+
146
+ console . log ( 'Response Desc:' , ret . statusDesc ) ;
147
+ console . log ( 'Response Value:' , ret . value ) ;
148
+
149
+ if ( logging . debug && ret . debug !== null ) {
150
+ console . log ( 'Debug messages:' ) ;
151
+ if ( ! Array . isArray ( ret . debug ) ) {
152
+ ret . debug = [ ret . debug ] ;
153
+ }
154
+ for ( const msg of ret . debug ) {
155
+ console . log ( msg ) ;
156
+ }
157
+ }
158
+ console . groupEnd ( ) ;
159
+ }
160
+ }
161
+
162
+ return Promise . resolve ( ret ) ;
163
+ }
164
+
165
+ #proxy( ) {
166
+ /*
167
+ syntax:
168
+ this.proxy().funcGroup.funcName(params = null, {
169
+ headers = null,
170
+ logging = {},
171
+ onerror = null
172
+ } = {});
173
+ */
174
+ const list = [ ] ;
175
+ return new Proxy ( function ( ) { } , {
176
+ get : ( dummy , name , pxy ) => {
177
+ list . push ( name ) ;
178
+ return pxy ;
179
+ } ,
180
+ apply : async ( dummy , pxy , args ) => {
181
+ const params = args [ 0 ] ?? null ;
182
+ let opts = {
183
+ headers : null ,
184
+ logging : { } ,
185
+ onerror : null
186
+ } ;
187
+ if ( APICaller . #isObj( args [ 1 ] ) ) {
188
+ opts = Object . assign ( { } , opts , args [ 1 ] ) ;
189
+ }
190
+ const resp = await this . coreFetch ( {
191
+ func : list . join ( '.' ) ,
192
+ params : params ,
193
+ headers : opts . headers ,
194
+ logging : opts . logging
195
+ } ) ;
196
+ if ( resp . status === 0 ) {
197
+ return resp . value ;
198
+ } else {
199
+ if ( typeof opts . onerror === 'function' ) {
200
+ opts . onerror ( resp ) ;
201
+ } else {
202
+ alert ( `${ resp . statusDesc } :\n${ resp . value } ` ) ;
203
+ // App.popupbox({
204
+ // content: resp.value,
205
+ // title: resp.statusDesc
206
+ // });
207
+ }
208
+ }
209
+ return null ;
210
+ }
211
+ } ) ;
212
+ }
213
+ get fetch ( ) {
214
+ return this . #proxy( ) ;
215
+ }
216
+ }
217
+
218
+ export default APICaller ;
219
+ </ script >
0 commit comments