Skip to content

Commit bc76396

Browse files
committed
version 11.3.1; bug fix; allow execution error messages
1 parent 643b9a8 commit bc76396

File tree

3 files changed

+236
-4
lines changed

3 files changed

+236
-4
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"email": "anshu.krishna5@gmail.com"
1010
}
1111
],
12-
"version": "11.3",
12+
"version": "11.3.1",
1313
"minimum-stability": "stable",
1414
"require": {
1515
"php": ">=8.1",

example/client/api-caller.js

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

src/Server.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,9 @@ private static function final_writer(mixed $value = null, StatusType $status = S
200200
public static function error(mixed $info, StatusType $status = StatusType::EXEC_ERR) : never {
201201
if(!Config::$dev_mode) {
202202
switch($status) {
203-
case StatusType::EXEC_ERR:
204-
$info = 'Server execution error';
205-
break;
203+
// case StatusType::EXEC_ERR:
204+
// $info = 'Server execution error';
205+
// break;
206206
case StatusType::DEV_ERR:
207207
$info = 'Internal server error';
208208
break;

0 commit comments

Comments
 (0)