@marianmeres/http-utils 1.11.0 → 1.13.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/dist/error.d.ts +8 -1
- package/dist/index.cjs +54 -14
- package/dist/index.d.ts +1 -1
- package/dist/index.js +54 -15
- package/dist/status.d.ts +1 -0
- package/package.json +1 -1
package/dist/error.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ declare class Gone extends HttpError {
|
|
|
44
44
|
status: number;
|
|
45
45
|
statusText: string;
|
|
46
46
|
}
|
|
47
|
+
declare class UnprocessableContent extends HttpError {
|
|
48
|
+
name: string;
|
|
49
|
+
status: number;
|
|
50
|
+
statusText: string;
|
|
51
|
+
}
|
|
47
52
|
declare class ImATeapot extends HttpError {
|
|
48
53
|
name: string;
|
|
49
54
|
status: number;
|
|
@@ -78,10 +83,12 @@ export declare const HTTP_ERROR: {
|
|
|
78
83
|
Conflict: typeof Conflict;
|
|
79
84
|
Gone: typeof Gone;
|
|
80
85
|
ImATeapot: typeof ImATeapot;
|
|
86
|
+
UnprocessableContent: typeof UnprocessableContent;
|
|
81
87
|
InternalServerError: typeof InternalServerError;
|
|
82
88
|
NotImplemented: typeof NotImplemented;
|
|
83
89
|
BadGateway: typeof BadGateway;
|
|
84
90
|
ServiceUnavailable: typeof ServiceUnavailable;
|
|
85
91
|
};
|
|
86
|
-
export declare const createHttpError: (code: number | string, message?: string | null, body?: string | null, cause?: any) => BadRequest | Unauthorized | Forbidden | NotFound | MethodNotAllowed | RequestTimeout | Conflict | Gone | ImATeapot | InternalServerError | NotImplemented | BadGateway | ServiceUnavailable;
|
|
92
|
+
export declare const createHttpError: (code: number | string, message?: string | null, body?: string | null, cause?: any) => BadRequest | Unauthorized | Forbidden | NotFound | MethodNotAllowed | RequestTimeout | Conflict | Gone | UnprocessableContent | ImATeapot | InternalServerError | NotImplemented | BadGateway | ServiceUnavailable;
|
|
93
|
+
export declare const getErrorMessage: (e: any, stripErrorPrefix?: boolean) => string;
|
|
87
94
|
export {};
|
package/dist/index.cjs
CHANGED
|
@@ -103,6 +103,7 @@ class HTTP_STATUS {
|
|
|
103
103
|
static METHOD_NOT_ALLOWED = HTTP_STATUS.ERROR_CLIENT.METHOD_NOT_ALLOWED.CODE;
|
|
104
104
|
static CONFLICT = HTTP_STATUS.ERROR_CLIENT.CONFLICT.CODE;
|
|
105
105
|
static GONE = HTTP_STATUS.ERROR_CLIENT.GONE.CODE;
|
|
106
|
+
static UNPROCESSABLE_CONTENT = HTTP_STATUS.ERROR_CLIENT.UNPROCESSABLE_CONTENT.CODE;
|
|
106
107
|
// 5xx
|
|
107
108
|
static INTERNAL_SERVER_ERROR = HTTP_STATUS.ERROR_SERVER.INTERNAL_SERVER_ERROR.CODE;
|
|
108
109
|
static NOT_IMPLEMENTED = HTTP_STATUS.ERROR_SERVER.NOT_IMPLEMENTED.CODE;
|
|
@@ -173,6 +174,11 @@ class Gone extends HttpError {
|
|
|
173
174
|
status = HTTP_STATUS.ERROR_CLIENT.GONE.CODE;
|
|
174
175
|
statusText = HTTP_STATUS.ERROR_CLIENT.GONE.TEXT;
|
|
175
176
|
}
|
|
177
|
+
class UnprocessableContent extends HttpError {
|
|
178
|
+
name = 'HttpUnprocessableContentError';
|
|
179
|
+
status = HTTP_STATUS.ERROR_CLIENT.UNPROCESSABLE_CONTENT.CODE;
|
|
180
|
+
statusText = HTTP_STATUS.ERROR_CLIENT.UNPROCESSABLE_CONTENT.TEXT;
|
|
181
|
+
}
|
|
176
182
|
class ImATeapot extends HttpError {
|
|
177
183
|
name = 'HttpImATeapotError';
|
|
178
184
|
status = HTTP_STATUS.ERROR_CLIENT.IM_A_TEAPOT.CODE;
|
|
@@ -211,6 +217,7 @@ const HTTP_ERROR = {
|
|
|
211
217
|
Conflict,
|
|
212
218
|
Gone,
|
|
213
219
|
ImATeapot,
|
|
220
|
+
UnprocessableContent,
|
|
214
221
|
// server
|
|
215
222
|
InternalServerError,
|
|
216
223
|
NotImplemented,
|
|
@@ -227,12 +234,22 @@ const _wellKnownCtorMap = {
|
|
|
227
234
|
'409': Conflict,
|
|
228
235
|
'410': Gone,
|
|
229
236
|
'418': ImATeapot,
|
|
237
|
+
'422': UnprocessableContent,
|
|
230
238
|
//
|
|
231
239
|
'500': InternalServerError,
|
|
232
240
|
'501': NotImplemented,
|
|
233
241
|
'502': BadGateway,
|
|
234
242
|
'503': ServiceUnavailable,
|
|
235
243
|
};
|
|
244
|
+
const _maybeJsonParse = (v) => {
|
|
245
|
+
if (typeof v === 'string') {
|
|
246
|
+
try {
|
|
247
|
+
v = JSON.parse(v);
|
|
248
|
+
}
|
|
249
|
+
catch (e) { }
|
|
250
|
+
}
|
|
251
|
+
return v;
|
|
252
|
+
};
|
|
236
253
|
const createHttpError = (code, message,
|
|
237
254
|
// arbitrary content, typically http response body which threw this error
|
|
238
255
|
// (will be JSON.parse-d if the content is a valid json string)
|
|
@@ -245,21 +262,9 @@ cause) => {
|
|
|
245
262
|
if (isNaN(code) || !(code >= 400 && code < 600))
|
|
246
263
|
code = fallback.CODE;
|
|
247
264
|
// opinionated convention
|
|
248
|
-
|
|
249
|
-
// prettier-ignore
|
|
250
|
-
try {
|
|
251
|
-
body = JSON.parse(body);
|
|
252
|
-
}
|
|
253
|
-
catch (e) { }
|
|
254
|
-
}
|
|
265
|
+
body = _maybeJsonParse(body);
|
|
255
266
|
// opinionated convention
|
|
256
|
-
|
|
257
|
-
// prettier-ignore
|
|
258
|
-
try {
|
|
259
|
-
cause = JSON.parse(cause);
|
|
260
|
-
}
|
|
261
|
-
catch (e) { }
|
|
262
|
-
}
|
|
267
|
+
cause = _maybeJsonParse(cause);
|
|
263
268
|
// try to find the well known one, otherwise fallback to generic
|
|
264
269
|
const ctor = _wellKnownCtorMap[`${code}`] ?? HttpError;
|
|
265
270
|
//
|
|
@@ -272,6 +277,40 @@ cause) => {
|
|
|
272
277
|
e.body = body;
|
|
273
278
|
return e;
|
|
274
279
|
};
|
|
280
|
+
const getErrorMessage = (e, stripErrorPrefix = true) => {
|
|
281
|
+
if (!e)
|
|
282
|
+
return '';
|
|
283
|
+
// PROBLEM is that error may bubble from various sources which are not always under control
|
|
284
|
+
// and even if they were it still may not be trivial to keep similar structure on each error boundary...
|
|
285
|
+
// So, we'll just do what we can, it will not be perfect, but should handle most cases most of the time.
|
|
286
|
+
// Also, I'm relying on some of my own opinionated conventions as well...
|
|
287
|
+
const cause = _maybeJsonParse(e?.cause);
|
|
288
|
+
const body = _maybeJsonParse(e?.body);
|
|
289
|
+
let msg =
|
|
290
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause
|
|
291
|
+
// e.cause is the standard prop for error details, so should be considered as
|
|
292
|
+
// the most authoritative (if available)
|
|
293
|
+
// "code" and "message" are my own conventions
|
|
294
|
+
cause?.code ||
|
|
295
|
+
cause?.message ||
|
|
296
|
+
(typeof cause === 'string' ? cause : null) ||
|
|
297
|
+
// non-standard "body" is this package's HttpError prop
|
|
298
|
+
body?.error?.message ||
|
|
299
|
+
body?.message ||
|
|
300
|
+
(typeof body === 'string' ? body : null) ||
|
|
301
|
+
// the common message from Error ctor (e.g. "Foo" if new TypeError("Foo"))
|
|
302
|
+
e?.message ||
|
|
303
|
+
// the Error class name (e.g. TypeError)
|
|
304
|
+
e?.name ||
|
|
305
|
+
// this should handle (almost) everything else (mainly if e is not the Error instance)
|
|
306
|
+
e?.toString() ||
|
|
307
|
+
// very last fallback if `toString()` was not available (or returned empty)
|
|
308
|
+
'Unknown Error';
|
|
309
|
+
if (stripErrorPrefix) {
|
|
310
|
+
msg = msg.replace(/^[^:]*Error: /, '');
|
|
311
|
+
}
|
|
312
|
+
return msg;
|
|
313
|
+
};
|
|
275
314
|
|
|
276
315
|
const _fetchRaw = async ({ method, path, data = null, token = null, headers = null, signal = null, credentials, }) => {
|
|
277
316
|
headers = Object.entries(headers || {}).reduce((m, [k, v]) => ({ ...m, [k.toLowerCase()]: v }), {});
|
|
@@ -397,3 +436,4 @@ exports.HTTP_ERROR = HTTP_ERROR;
|
|
|
397
436
|
exports.HTTP_STATUS = HTTP_STATUS;
|
|
398
437
|
exports.createHttpApi = createHttpApi;
|
|
399
438
|
exports.createHttpError = createHttpError;
|
|
439
|
+
exports.getErrorMessage = getErrorMessage;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -101,6 +101,7 @@ class HTTP_STATUS {
|
|
|
101
101
|
static METHOD_NOT_ALLOWED = HTTP_STATUS.ERROR_CLIENT.METHOD_NOT_ALLOWED.CODE;
|
|
102
102
|
static CONFLICT = HTTP_STATUS.ERROR_CLIENT.CONFLICT.CODE;
|
|
103
103
|
static GONE = HTTP_STATUS.ERROR_CLIENT.GONE.CODE;
|
|
104
|
+
static UNPROCESSABLE_CONTENT = HTTP_STATUS.ERROR_CLIENT.UNPROCESSABLE_CONTENT.CODE;
|
|
104
105
|
// 5xx
|
|
105
106
|
static INTERNAL_SERVER_ERROR = HTTP_STATUS.ERROR_SERVER.INTERNAL_SERVER_ERROR.CODE;
|
|
106
107
|
static NOT_IMPLEMENTED = HTTP_STATUS.ERROR_SERVER.NOT_IMPLEMENTED.CODE;
|
|
@@ -171,6 +172,11 @@ class Gone extends HttpError {
|
|
|
171
172
|
status = HTTP_STATUS.ERROR_CLIENT.GONE.CODE;
|
|
172
173
|
statusText = HTTP_STATUS.ERROR_CLIENT.GONE.TEXT;
|
|
173
174
|
}
|
|
175
|
+
class UnprocessableContent extends HttpError {
|
|
176
|
+
name = 'HttpUnprocessableContentError';
|
|
177
|
+
status = HTTP_STATUS.ERROR_CLIENT.UNPROCESSABLE_CONTENT.CODE;
|
|
178
|
+
statusText = HTTP_STATUS.ERROR_CLIENT.UNPROCESSABLE_CONTENT.TEXT;
|
|
179
|
+
}
|
|
174
180
|
class ImATeapot extends HttpError {
|
|
175
181
|
name = 'HttpImATeapotError';
|
|
176
182
|
status = HTTP_STATUS.ERROR_CLIENT.IM_A_TEAPOT.CODE;
|
|
@@ -209,6 +215,7 @@ const HTTP_ERROR = {
|
|
|
209
215
|
Conflict,
|
|
210
216
|
Gone,
|
|
211
217
|
ImATeapot,
|
|
218
|
+
UnprocessableContent,
|
|
212
219
|
// server
|
|
213
220
|
InternalServerError,
|
|
214
221
|
NotImplemented,
|
|
@@ -225,12 +232,22 @@ const _wellKnownCtorMap = {
|
|
|
225
232
|
'409': Conflict,
|
|
226
233
|
'410': Gone,
|
|
227
234
|
'418': ImATeapot,
|
|
235
|
+
'422': UnprocessableContent,
|
|
228
236
|
//
|
|
229
237
|
'500': InternalServerError,
|
|
230
238
|
'501': NotImplemented,
|
|
231
239
|
'502': BadGateway,
|
|
232
240
|
'503': ServiceUnavailable,
|
|
233
241
|
};
|
|
242
|
+
const _maybeJsonParse = (v) => {
|
|
243
|
+
if (typeof v === 'string') {
|
|
244
|
+
try {
|
|
245
|
+
v = JSON.parse(v);
|
|
246
|
+
}
|
|
247
|
+
catch (e) { }
|
|
248
|
+
}
|
|
249
|
+
return v;
|
|
250
|
+
};
|
|
234
251
|
const createHttpError = (code, message,
|
|
235
252
|
// arbitrary content, typically http response body which threw this error
|
|
236
253
|
// (will be JSON.parse-d if the content is a valid json string)
|
|
@@ -243,21 +260,9 @@ cause) => {
|
|
|
243
260
|
if (isNaN(code) || !(code >= 400 && code < 600))
|
|
244
261
|
code = fallback.CODE;
|
|
245
262
|
// opinionated convention
|
|
246
|
-
|
|
247
|
-
// prettier-ignore
|
|
248
|
-
try {
|
|
249
|
-
body = JSON.parse(body);
|
|
250
|
-
}
|
|
251
|
-
catch (e) { }
|
|
252
|
-
}
|
|
263
|
+
body = _maybeJsonParse(body);
|
|
253
264
|
// opinionated convention
|
|
254
|
-
|
|
255
|
-
// prettier-ignore
|
|
256
|
-
try {
|
|
257
|
-
cause = JSON.parse(cause);
|
|
258
|
-
}
|
|
259
|
-
catch (e) { }
|
|
260
|
-
}
|
|
265
|
+
cause = _maybeJsonParse(cause);
|
|
261
266
|
// try to find the well known one, otherwise fallback to generic
|
|
262
267
|
const ctor = _wellKnownCtorMap[`${code}`] ?? HttpError;
|
|
263
268
|
//
|
|
@@ -270,6 +275,40 @@ cause) => {
|
|
|
270
275
|
e.body = body;
|
|
271
276
|
return e;
|
|
272
277
|
};
|
|
278
|
+
const getErrorMessage = (e, stripErrorPrefix = true) => {
|
|
279
|
+
if (!e)
|
|
280
|
+
return '';
|
|
281
|
+
// PROBLEM is that error may bubble from various sources which are not always under control
|
|
282
|
+
// and even if they were it still may not be trivial to keep similar structure on each error boundary...
|
|
283
|
+
// So, we'll just do what we can, it will not be perfect, but should handle most cases most of the time.
|
|
284
|
+
// Also, I'm relying on some of my own opinionated conventions as well...
|
|
285
|
+
const cause = _maybeJsonParse(e?.cause);
|
|
286
|
+
const body = _maybeJsonParse(e?.body);
|
|
287
|
+
let msg =
|
|
288
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause
|
|
289
|
+
// e.cause is the standard prop for error details, so should be considered as
|
|
290
|
+
// the most authoritative (if available)
|
|
291
|
+
// "code" and "message" are my own conventions
|
|
292
|
+
cause?.code ||
|
|
293
|
+
cause?.message ||
|
|
294
|
+
(typeof cause === 'string' ? cause : null) ||
|
|
295
|
+
// non-standard "body" is this package's HttpError prop
|
|
296
|
+
body?.error?.message ||
|
|
297
|
+
body?.message ||
|
|
298
|
+
(typeof body === 'string' ? body : null) ||
|
|
299
|
+
// the common message from Error ctor (e.g. "Foo" if new TypeError("Foo"))
|
|
300
|
+
e?.message ||
|
|
301
|
+
// the Error class name (e.g. TypeError)
|
|
302
|
+
e?.name ||
|
|
303
|
+
// this should handle (almost) everything else (mainly if e is not the Error instance)
|
|
304
|
+
e?.toString() ||
|
|
305
|
+
// very last fallback if `toString()` was not available (or returned empty)
|
|
306
|
+
'Unknown Error';
|
|
307
|
+
if (stripErrorPrefix) {
|
|
308
|
+
msg = msg.replace(/^[^:]*Error: /, '');
|
|
309
|
+
}
|
|
310
|
+
return msg;
|
|
311
|
+
};
|
|
273
312
|
|
|
274
313
|
const _fetchRaw = async ({ method, path, data = null, token = null, headers = null, signal = null, credentials, }) => {
|
|
275
314
|
headers = Object.entries(headers || {}).reduce((m, [k, v]) => ({ ...m, [k.toLowerCase()]: v }), {});
|
|
@@ -391,4 +430,4 @@ function createHttpApi(base, defaults, factoryErrorMessageExtractor) {
|
|
|
391
430
|
}
|
|
392
431
|
createHttpApi.defaultErrorMessageExtractor = null;
|
|
393
432
|
|
|
394
|
-
export { HTTP_ERROR, HTTP_STATUS, createHttpApi, createHttpError };
|
|
433
|
+
export { HTTP_ERROR, HTTP_STATUS, createHttpApi, createHttpError, getErrorMessage };
|
package/dist/status.d.ts
CHANGED
|
@@ -270,6 +270,7 @@ export declare class HTTP_STATUS {
|
|
|
270
270
|
static readonly METHOD_NOT_ALLOWED: number;
|
|
271
271
|
static readonly CONFLICT: number;
|
|
272
272
|
static readonly GONE: number;
|
|
273
|
+
static readonly UNPROCESSABLE_CONTENT: number;
|
|
273
274
|
static readonly INTERNAL_SERVER_ERROR: number;
|
|
274
275
|
static readonly NOT_IMPLEMENTED: number;
|
|
275
276
|
static readonly SERVICE_UNAVAILABLE: number;
|