core-services-sdk 1.0.0 → 1.1.1

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.
@@ -12,5 +12,5 @@
12
12
  },
13
13
  "javascript.preferences.importModuleSpecifierEnding": "js",
14
14
  "js/ts.implicitProjectConfig.checkJs": true,
15
- "javascript.validate.enable": false
15
+ "javascript.validate.enable": true
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core-services-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -20,7 +20,10 @@
20
20
  "description": "",
21
21
  "dependencies": {
22
22
  "amqplib": "^0.10.8",
23
- "uuid": "^11.1.0"
23
+ "http-status": "^2.1.0",
24
+ "node-fetch": "^3.3.2",
25
+ "uuid": "^11.1.0",
26
+ "xml2js": "^0.6.2"
24
27
  },
25
28
  "devDependencies": {
26
29
  "@vitest/coverage-v8": "^3.2.4",
@@ -28,4 +31,4 @@
28
31
  "url": "^0.11.4",
29
32
  "vitest": "^3.2.4"
30
33
  }
31
- }
34
+ }
@@ -0,0 +1,47 @@
1
+ import * as httpStatus from 'http-status'
2
+
3
+ const DEFAULT_ERROR = {
4
+ httpStatusCode: httpStatus.INTERNAL_SERVER_ERROR,
5
+ code: 'UNKNOWN',
6
+ httpStatusText: httpStatus[httpStatus.INTERNAL_SERVER_ERROR],
7
+ }
8
+
9
+ /**
10
+ *
11
+ */
12
+ export class HttpError extends Error {
13
+ /** @type {number} */
14
+ httpStatusCode
15
+ /** @type {string} */
16
+ code
17
+ /** @type {string} */
18
+ httpStatusText
19
+
20
+ /** @type {Array} */
21
+ details
22
+ constructor({
23
+ httpStatusCode,
24
+ code,
25
+ httpStatusText,
26
+ details = [],
27
+ } = DEFAULT_ERROR) {
28
+ super(`${code || httpStatus[httpStatusCode]}`)
29
+ this.httpStatusCode = httpStatusCode
30
+ this.code = code
31
+ this.httpStatusText = httpStatusText
32
+ this.details = details
33
+
34
+ if (typeof Error.captureStackTrace === 'function') {
35
+ Error.captureStackTrace(this, this.constructor)
36
+ }
37
+ }
38
+
39
+ /**
40
+ *
41
+ * @param {object} instance
42
+ * @returns {boolean}
43
+ */
44
+ static isInstanceOf(instance) {
45
+ return instance instanceof HttpError
46
+ }
47
+ }
@@ -0,0 +1,7 @@
1
+ export const HTTP_METHODS = Object.freeze({
2
+ GET: 'GET',
3
+ POST: 'POST',
4
+ PUT: 'PUT',
5
+ PATCH: 'PATCH',
6
+ DELETE: 'DELETE',
7
+ })
@@ -0,0 +1,203 @@
1
+ import fetch from 'node-fetch'
2
+ import httpStatus from 'http-status'
3
+ import { parseStringPromise } from 'xml2js'
4
+
5
+ import { HttpError } from './HttpError.js'
6
+ import { HTTP_METHODS } from './http-method.js'
7
+ import { ResponseType } from './responseType.js'
8
+
9
+ const JSON_HEADER = {
10
+ 'Content-Type': 'application/json',
11
+ }
12
+
13
+ const isOkStatus = ({ status }) =>
14
+ // Range of response OK
15
+ status >= httpStatus.OK && status < httpStatus.MULTIPLE_CHOICES
16
+
17
+ const checkStatus = async (res) => {
18
+ if (!isOkStatus(res)) {
19
+ const text = await res.text()
20
+ const info = tryConvertJsonResponse(text)
21
+ const { status, statusText } = res
22
+
23
+ throw new HttpError({
24
+ code: status,
25
+ httpStatusCode: status,
26
+ httpStatusText: statusText,
27
+ details: info,
28
+ })
29
+ }
30
+ return res
31
+ }
32
+
33
+ const getTextResponse = async (response) => {
34
+ const text = await response.text()
35
+ return text
36
+ }
37
+
38
+ const tryConvertJsonResponse = (responseText) => {
39
+ try {
40
+ const obj = JSON.parse(responseText)
41
+ return obj
42
+ } catch (error) {
43
+ error.responseText = responseText
44
+ throw error
45
+ }
46
+ }
47
+
48
+ const tryGetJsonResponse = async (response) => {
49
+ let jsonText
50
+ try {
51
+ jsonText = getTextResponse(response)
52
+ const obj = tryConvertJsonResponse(jsonText)
53
+ return obj
54
+ } catch (error) {
55
+ if (!jsonText) {
56
+ throw error
57
+ }
58
+ return jsonText
59
+ }
60
+ }
61
+
62
+ const tryGetXmlResponse = async (response) => {
63
+ let xmlText
64
+ try {
65
+ xmlText = await getTextResponse(response)
66
+ const xml = await parseStringPromise(xmlText)
67
+ return xml
68
+ } catch (error) {
69
+ if (!xmlText) {
70
+ throw error
71
+ }
72
+ return xmlText
73
+ }
74
+ }
75
+
76
+ const getResponsePayload = async (response, responseType) => {
77
+ switch (responseType) {
78
+ case ResponseType.json:
79
+ return tryGetJsonResponse(response)
80
+
81
+ case ResponseType.xml:
82
+ return tryGetXmlResponse(response)
83
+
84
+ default:
85
+ case ResponseType.text:
86
+ return getTextResponse(response)
87
+ }
88
+ }
89
+
90
+ export const get = async ({
91
+ url,
92
+ headers = {},
93
+ credentials = 'include',
94
+ expectedType = ResponseType.json,
95
+ }) => {
96
+ const response = await fetch(url, {
97
+ method: HTTP_METHODS.GET,
98
+ headers: {
99
+ ...JSON_HEADER,
100
+ ...headers,
101
+ },
102
+ ...(credentials ? { credentials } : {}),
103
+ })
104
+
105
+ await checkStatus(response)
106
+ const data = await getResponsePayload(response, expectedType)
107
+ return data
108
+ }
109
+
110
+ export const post = async ({
111
+ url,
112
+ body,
113
+ headers,
114
+ credentials = 'include',
115
+ expectedType = ResponseType.json,
116
+ }) => {
117
+ const response = await fetch(url, {
118
+ method: HTTP_METHODS.POST,
119
+ headers: {
120
+ ...JSON_HEADER,
121
+ ...headers,
122
+ },
123
+ body: JSON.stringify(body),
124
+ ...(credentials ? { credentials } : {}),
125
+ })
126
+ await checkStatus(response)
127
+ const data = await getResponsePayload(response, expectedType)
128
+ return data
129
+ }
130
+
131
+ export const put = async ({
132
+ url,
133
+ body,
134
+ headers = {},
135
+ credentials = 'include',
136
+ expectedType = ResponseType.json,
137
+ }) => {
138
+ const response = await fetch(url, {
139
+ method: HTTP_METHODS.PUT,
140
+ headers: {
141
+ ...JSON_HEADER,
142
+ ...headers,
143
+ },
144
+ body: JSON.stringify(body),
145
+ ...(credentials ? { credentials } : {}),
146
+ })
147
+
148
+ await checkStatus(response)
149
+ const data = await getResponsePayload(response, expectedType)
150
+ return data
151
+ }
152
+
153
+ export const patch = async ({
154
+ url,
155
+ body,
156
+ headers,
157
+ credentials = 'include',
158
+ expectedType = ResponseType.json,
159
+ }) => {
160
+ const response = await fetch(url, {
161
+ method: HTTP_METHODS.PATCH,
162
+ headers: {
163
+ ...JSON_HEADER,
164
+ ...headers,
165
+ },
166
+ body: JSON.stringify(body),
167
+ ...(credentials ? { credentials } : {}),
168
+ })
169
+
170
+ await checkStatus(response)
171
+ const data = await getResponsePayload(response, expectedType)
172
+ return data
173
+ }
174
+
175
+ export const deleteApi = async ({
176
+ url,
177
+ body,
178
+ headers,
179
+ credentials = 'include',
180
+ expectedType = ResponseType.json,
181
+ }) => {
182
+ const response = await fetch(url, {
183
+ method: HTTP_METHODS.DELETE,
184
+ headers: {
185
+ ...JSON_HEADER,
186
+ ...headers,
187
+ },
188
+ ...(body ? { body: JSON.stringify(body) } : {}),
189
+ ...(credentials ? { credentials } : {}),
190
+ })
191
+
192
+ await checkStatus(response)
193
+ const data = await getResponsePayload(response, expectedType)
194
+ return data
195
+ }
196
+
197
+ export const http = {
198
+ get,
199
+ put,
200
+ post,
201
+ patch,
202
+ deleteApi,
203
+ }
@@ -0,0 +1,6 @@
1
+ export const ResponseType = Object.freeze({
2
+ xml: 'xml',
3
+ json: 'json',
4
+ text: 'text',
5
+ file: 'file',
6
+ })
package/src/index.js CHANGED
@@ -1 +1,4 @@
1
1
  export * from './rabbit-mq/index.js'
2
+ export * as http from './http/http.js'
3
+ export * from './http/responseType.js'
4
+ export { HttpError } from './http/HttpError.js'