-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy patherrorResponseInterceptor.ts
More file actions
117 lines (112 loc) · 3.89 KB
/
errorResponseInterceptor.ts
File metadata and controls
117 lines (112 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* © Copyright IBM Corporation 2024. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { pipeline } = require('node:stream/promises');
const { Writable, Readable } = require('node:stream');
export function errorResponseInterceptor(axiosError) {
if (
axiosError.response && // must have a response
axiosError.response.status >= 400 &&
// must have data:
axiosError.response.data &&
// must be a JSON request
// which also implies Content-Type starts with application/json:
(axiosError.config.responseType === 'json' ||
// or a stream request with application/json
// that has had the response converted to an object
(axiosError.config.responseType === 'stream' &&
axiosError.response.headers['content-type'].startsWith(
'application/json'
) &&
!(axiosError.response.data instanceof Readable))) &&
// must be a valid JSON:
// which also implies it is not a HEAD method:
axiosError.response.data instanceof Object &&
!axiosError.response.data.trace
) {
// Map the error/reason if available
// and not already have errors array:
if (!axiosError.response.data.errors && axiosError.response.data.error) {
const error = {
code: axiosError.response.data.error,
message: axiosError.response.data.error,
};
if (axiosError.response.data.reason) {
error.message += `: ${axiosError.response.data.reason}`;
}
// Add the new error as part of an errors array.
axiosError.response.data.errors = [error];
}
if (axiosError.response.data.errors) {
// Map x-request-id or x-couch-request-id if available to the trace field
const trace =
axiosError.response.headers['x-request-id'] ||
axiosError.response.headers['x-couch-request-id'];
if (trace) {
// Trace should be omitted if there is no value
axiosError.response.data.trace = trace;
}
}
}
return Promise.reject(axiosError);
}
/**
* Axios interceptor to convert errors for streaming cases into
* JSON objects.
*
* This means users can handle rejections for AsStream cases in
* the same way as normal error rejections and we can apply the
* errorResponseInterceptor to augment the errors.
*
* @param axiosError
* @returns rejected promise with the stream body transoformed
*/
export async function errorResponseStreamConverter(axiosError) {
if (
axiosError.response && // must have a response
axiosError.response.status >= 400 &&
// must have data:
axiosError.response.data &&
// Must be a JSON response
axiosError.response.headers['content-type']?.startsWith(
'application/json'
) &&
// this is for streaming requests
axiosError.config.responseType === 'stream' &&
// must be a stream
axiosError.response.data instanceof Readable
) {
let data = '';
await pipeline(
axiosError.response.data,
new Writable({
write: (c, e, cb) => {
data += c;
cb();
},
})
);
try {
axiosError.response.data = JSON.parse(data);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
// JSON parse failure, just use the original
// error stream as a string, matching axios behavior
// for broken JSON
axiosError.response.data = data;
}
}
return Promise.reject(axiosError);
}