@ps-aux/api-client-angular 0.1.0-rc1

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.
@@ -0,0 +1,5 @@
1
+ import { HttpClient as AngularHttpClient } from '@angular/common/http';
2
+ import { UrlConverter, ObservableHttpClient } from '@ps-aux/api-client-common';
3
+ export declare const qsUrlConverter: () => UrlConverter;
4
+ export declare const springBootUrlConverter: () => UrlConverter;
5
+ export declare const createHttpClient: (client: AngularHttpClient, urlConverter?: UrlConverter) => ObservableHttpClient;
@@ -0,0 +1,3 @@
1
+ import { HttpClient as AngularHttpClient } from '@angular/common/http';
2
+ import { HttpClient } from './types';
3
+ export declare const createHttpClient: (client: AngularHttpClient) => HttpClient;
@@ -0,0 +1 @@
1
+ export { createHttpClient } from './AngularApiHttpClient';
@@ -0,0 +1,2 @@
1
+ export declare const serializeQuery: (obj: any) => any;
2
+ export declare const flattenObject: (obj: any, prefix?: string) => any;
@@ -0,0 +1,20 @@
1
+ import { Observable } from 'rxjs';
2
+ export type ContentType = {};
3
+ export type RequestParams = {};
4
+ export declare const ContentType: {
5
+ Json: string;
6
+ FormData: string;
7
+ };
8
+ export type Request = {
9
+ path: string;
10
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
11
+ format?: 'json';
12
+ query?: any;
13
+ body?: any;
14
+ type?: string;
15
+ secure?: boolean;
16
+ responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
17
+ };
18
+ export type HttpClient<Any = any> = {
19
+ request: <Data, A = any>(req: Request) => Observable<Data>;
20
+ };
@@ -0,0 +1 @@
1
+ export declare const myFun: (f: string) => string;
@@ -0,0 +1 @@
1
+ export { createHttpClient, springBootUrlConverter, qsUrlConverter } from './AngularApiHttpClient';
@@ -0,0 +1,334 @@
1
+ import { map } from 'rxjs';
2
+ import qs from 'qs';
3
+
4
+ const { isArray } = Array;
5
+
6
+ function fromPairs(listOfPairs){
7
+ const toReturn = {};
8
+ listOfPairs.forEach(([ prop, value ]) => toReturn[ prop ] = value);
9
+
10
+ return toReturn
11
+ }
12
+
13
+ function partitionObject(predicate, iterable){
14
+ const yes = {};
15
+ const no = {};
16
+ Object.entries(iterable).forEach(([ prop, value ]) => {
17
+ if (predicate(value, prop)){
18
+ yes[ prop ] = value;
19
+ } else {
20
+ no[ prop ] = value;
21
+ }
22
+ });
23
+
24
+ return [ yes, no ]
25
+ }
26
+
27
+ function partitionArray(
28
+ predicate, list, indexed = false
29
+ ){
30
+ const yes = [];
31
+ const no = [];
32
+ let counter = -1;
33
+
34
+ while (counter++ < list.length - 1){
35
+ if (
36
+ indexed ? predicate(list[ counter ], counter) : predicate(list[ counter ])
37
+ ){
38
+ yes.push(list[ counter ]);
39
+ } else {
40
+ no.push(list[ counter ]);
41
+ }
42
+ }
43
+
44
+ return [ yes, no ]
45
+ }
46
+
47
+ function partition(predicate, iterable){
48
+ if (arguments.length === 1){
49
+ return listHolder => partition(predicate, listHolder)
50
+ }
51
+ if (!isArray(iterable)) return partitionObject(predicate, iterable)
52
+
53
+ return partitionArray(predicate, iterable)
54
+ }
55
+
56
+ var flat = flatten$1;
57
+ flatten$1.flatten = flatten$1;
58
+ flatten$1.unflatten = unflatten;
59
+
60
+ function isBuffer (obj) {
61
+ return obj &&
62
+ obj.constructor &&
63
+ (typeof obj.constructor.isBuffer === 'function') &&
64
+ obj.constructor.isBuffer(obj)
65
+ }
66
+
67
+ function keyIdentity (key) {
68
+ return key
69
+ }
70
+
71
+ function flatten$1 (target, opts) {
72
+ opts = opts || {};
73
+
74
+ const delimiter = opts.delimiter || '.';
75
+ const maxDepth = opts.maxDepth;
76
+ const transformKey = opts.transformKey || keyIdentity;
77
+ const output = {};
78
+
79
+ function step (object, prev, currentDepth) {
80
+ currentDepth = currentDepth || 1;
81
+ Object.keys(object).forEach(function (key) {
82
+ const value = object[key];
83
+ const isarray = opts.safe && Array.isArray(value);
84
+ const type = Object.prototype.toString.call(value);
85
+ const isbuffer = isBuffer(value);
86
+ const isobject = (
87
+ type === '[object Object]' ||
88
+ type === '[object Array]'
89
+ );
90
+
91
+ const newKey = prev
92
+ ? prev + delimiter + transformKey(key)
93
+ : transformKey(key);
94
+
95
+ if (!isarray && !isbuffer && isobject && Object.keys(value).length &&
96
+ (!opts.maxDepth || currentDepth < maxDepth)) {
97
+ return step(value, newKey, currentDepth + 1)
98
+ }
99
+
100
+ output[newKey] = value;
101
+ });
102
+ }
103
+
104
+ step(target);
105
+
106
+ return output
107
+ }
108
+
109
+ function unflatten (target, opts) {
110
+ opts = opts || {};
111
+
112
+ const delimiter = opts.delimiter || '.';
113
+ const overwrite = opts.overwrite || false;
114
+ const transformKey = opts.transformKey || keyIdentity;
115
+ const result = {};
116
+
117
+ const isbuffer = isBuffer(target);
118
+ if (isbuffer || Object.prototype.toString.call(target) !== '[object Object]') {
119
+ return target
120
+ }
121
+
122
+ // safely ensure that the key is
123
+ // an integer.
124
+ function getkey (key) {
125
+ const parsedKey = Number(key);
126
+
127
+ return (
128
+ isNaN(parsedKey) ||
129
+ key.indexOf('.') !== -1 ||
130
+ opts.object
131
+ ) ? key
132
+ : parsedKey
133
+ }
134
+
135
+ function addKeys (keyPrefix, recipient, target) {
136
+ return Object.keys(target).reduce(function (result, key) {
137
+ result[keyPrefix + delimiter + key] = target[key];
138
+
139
+ return result
140
+ }, recipient)
141
+ }
142
+
143
+ function isEmpty (val) {
144
+ const type = Object.prototype.toString.call(val);
145
+ const isArray = type === '[object Array]';
146
+ const isObject = type === '[object Object]';
147
+
148
+ if (!val) {
149
+ return true
150
+ } else if (isArray) {
151
+ return !val.length
152
+ } else if (isObject) {
153
+ return !Object.keys(val).length
154
+ }
155
+ }
156
+
157
+ target = Object.keys(target).reduce(function (result, key) {
158
+ const type = Object.prototype.toString.call(target[key]);
159
+ const isObject = (type === '[object Object]' || type === '[object Array]');
160
+ if (!isObject || isEmpty(target[key])) {
161
+ result[key] = target[key];
162
+ return result
163
+ } else {
164
+ return addKeys(
165
+ key,
166
+ result,
167
+ flatten$1(target[key], opts)
168
+ )
169
+ }
170
+ }, {});
171
+
172
+ Object.keys(target).forEach(function (key) {
173
+ const split = key.split(delimiter).map(transformKey);
174
+ let key1 = getkey(split.shift());
175
+ let key2 = getkey(split[0]);
176
+ let recipient = result;
177
+
178
+ while (key2 !== undefined) {
179
+ if (key1 === '__proto__') {
180
+ return
181
+ }
182
+
183
+ const type = Object.prototype.toString.call(recipient[key1]);
184
+ const isobject = (
185
+ type === '[object Object]' ||
186
+ type === '[object Array]'
187
+ );
188
+
189
+ // do not write over falsey, non-undefined values if overwrite is false
190
+ if (!overwrite && !isobject && typeof recipient[key1] !== 'undefined') {
191
+ return
192
+ }
193
+
194
+ if ((overwrite && !isobject) || (!overwrite && recipient[key1] == null)) {
195
+ recipient[key1] = (
196
+ typeof key2 === 'number' &&
197
+ !opts.object ? [] : {}
198
+ );
199
+ }
200
+
201
+ recipient = recipient[key1];
202
+ if (split.length > 0) {
203
+ key1 = getkey(split.shift());
204
+ key2 = getkey(split[0]);
205
+ }
206
+ }
207
+
208
+ // unflatten again for 'messy objects'
209
+ recipient[key1] = unflatten(target[key], opts);
210
+ });
211
+
212
+ return result
213
+ }
214
+
215
+ /**
216
+ * Brings the 1st level to the 0th level.
217
+ * Flats the object by nesting with '.' path separator.
218
+ */
219
+ const serializeQueryForSpringBoot = (obj) => {
220
+ const parts = [];
221
+ Object.entries(obj).forEach(([key, val]) => {
222
+ if (Array.isArray(val)) {
223
+ val.forEach((v) => {
224
+ parts.push([key, v]);
225
+ });
226
+ }
227
+ else if (typeof val === 'object') {
228
+ objectToParams(val).forEach(([key, val]) => {
229
+ parts.push([key, val.toString()]);
230
+ });
231
+ }
232
+ else {
233
+ parts.push([key, val]);
234
+ }
235
+ });
236
+ return parts.map((p) => `${p[0]}=${p[1]}`).join('&');
237
+ };
238
+ const flatten = (obj) => {
239
+ const r = flat.flatten(obj);
240
+ // { empty: {} } would be { empty: {} } instead of empty array
241
+ return Object.entries(r).filter(([k, v]) => typeof v !== 'object');
242
+ };
243
+ const objectToParams = (obj) => {
244
+ const [arrayProps, nonArrayProps] = partition((e) => Array.isArray(e[1]), Object.entries(obj));
245
+ const withoutArrayProps = fromPairs(nonArrayProps);
246
+ const res = flatten(withoutArrayProps);
247
+ arrayProps.forEach(([k, vals]) => {
248
+ vals.forEach((v) => res.push([k, v]));
249
+ });
250
+ return res;
251
+ };
252
+
253
+ // @ts-ignore
254
+ const serializeQueryWithQs = (obj) => {
255
+ return qs.stringify(obj);
256
+ };
257
+
258
+ const fileResFilenameRegex = /filename="([^"]+)"/;
259
+ const getFileNameFromContentDispositionHeader = (contentDispositionHeader) => {
260
+ if (!contentDispositionHeader)
261
+ return 'download-file';
262
+ const match = contentDispositionHeader.match(fileResFilenameRegex);
263
+ const fileName = match ? match[1] : 'downloaded-file';
264
+ return fileName;
265
+ };
266
+
267
+ const ContentType = {
268
+ Json: 'application/json',
269
+ FormData: 'multipart/form-data',
270
+ };
271
+
272
+ const qsUrlConverter = () => ({ query, path }) => {
273
+ return {
274
+ url: path + (query ? `?${serializeQueryWithQs(query)}` : ''),
275
+ };
276
+ };
277
+ const springBootUrlConverter = () => ({ query, path }) => {
278
+ return {
279
+ url: path + (query ? `?${serializeQueryForSpringBoot(query)}` : ''),
280
+ };
281
+ };
282
+ const createHttpClient = (client, urlConverter = qsUrlConverter()) => {
283
+ return {
284
+ request: (req) => {
285
+ const { url, params } = urlConverter(req);
286
+ const isBlob = req.format = 'document';
287
+ const obs = client.request(req.method, url, {
288
+ params,
289
+ body: prepareBody(req.body, req.type),
290
+ responseType: (isBlob ? 'blob' : 'json'),
291
+ observe: 'response',
292
+ });
293
+ return obs.pipe(map((r) => {
294
+ const { body } = r;
295
+ if (!isBlob)
296
+ return body;
297
+ const data = body;
298
+ const contDisp = r.headers.get('content-disposition');
299
+ return new File([data], getFileNameFromContentDispositionHeader(contDisp), {
300
+ type: data.type
301
+ });
302
+ }));
303
+ },
304
+ };
305
+ };
306
+ const prepareBody = (payload, type) => {
307
+ if (type === ContentType.FormData) {
308
+ return convertToFormData(payload);
309
+ }
310
+ return payload;
311
+ };
312
+ const convertToFormData = (payload) => {
313
+ const formData = new FormData();
314
+ const addProp = (key, val) => {
315
+ if (Array.isArray(val) || val instanceof FileList) {
316
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
317
+ // @ts-ignore - seems that FileList is iterable despite the warning
318
+ // TODO change to other iteration method if this is not true
319
+ for (const valItem of val) {
320
+ addProp(key, valItem);
321
+ }
322
+ }
323
+ else if (typeof val === 'object' && val != null && !(val instanceof File)) {
324
+ throw new Error('Object serialization into FormData not supported');
325
+ }
326
+ else {
327
+ formData.append(key, val);
328
+ }
329
+ };
330
+ Object.entries(payload).forEach(([key, val]) => addProp(key, val));
331
+ return formData;
332
+ };
333
+
334
+ export { createHttpClient, qsUrlConverter, springBootUrlConverter };
package/dist/index.js ADDED
@@ -0,0 +1,338 @@
1
+ 'use strict';
2
+
3
+ var rxjs = require('rxjs');
4
+ var qs = require('qs');
5
+
6
+ const { isArray } = Array;
7
+
8
+ function fromPairs(listOfPairs){
9
+ const toReturn = {};
10
+ listOfPairs.forEach(([ prop, value ]) => toReturn[ prop ] = value);
11
+
12
+ return toReturn
13
+ }
14
+
15
+ function partitionObject(predicate, iterable){
16
+ const yes = {};
17
+ const no = {};
18
+ Object.entries(iterable).forEach(([ prop, value ]) => {
19
+ if (predicate(value, prop)){
20
+ yes[ prop ] = value;
21
+ } else {
22
+ no[ prop ] = value;
23
+ }
24
+ });
25
+
26
+ return [ yes, no ]
27
+ }
28
+
29
+ function partitionArray(
30
+ predicate, list, indexed = false
31
+ ){
32
+ const yes = [];
33
+ const no = [];
34
+ let counter = -1;
35
+
36
+ while (counter++ < list.length - 1){
37
+ if (
38
+ indexed ? predicate(list[ counter ], counter) : predicate(list[ counter ])
39
+ ){
40
+ yes.push(list[ counter ]);
41
+ } else {
42
+ no.push(list[ counter ]);
43
+ }
44
+ }
45
+
46
+ return [ yes, no ]
47
+ }
48
+
49
+ function partition(predicate, iterable){
50
+ if (arguments.length === 1){
51
+ return listHolder => partition(predicate, listHolder)
52
+ }
53
+ if (!isArray(iterable)) return partitionObject(predicate, iterable)
54
+
55
+ return partitionArray(predicate, iterable)
56
+ }
57
+
58
+ var flat = flatten$1;
59
+ flatten$1.flatten = flatten$1;
60
+ flatten$1.unflatten = unflatten;
61
+
62
+ function isBuffer (obj) {
63
+ return obj &&
64
+ obj.constructor &&
65
+ (typeof obj.constructor.isBuffer === 'function') &&
66
+ obj.constructor.isBuffer(obj)
67
+ }
68
+
69
+ function keyIdentity (key) {
70
+ return key
71
+ }
72
+
73
+ function flatten$1 (target, opts) {
74
+ opts = opts || {};
75
+
76
+ const delimiter = opts.delimiter || '.';
77
+ const maxDepth = opts.maxDepth;
78
+ const transformKey = opts.transformKey || keyIdentity;
79
+ const output = {};
80
+
81
+ function step (object, prev, currentDepth) {
82
+ currentDepth = currentDepth || 1;
83
+ Object.keys(object).forEach(function (key) {
84
+ const value = object[key];
85
+ const isarray = opts.safe && Array.isArray(value);
86
+ const type = Object.prototype.toString.call(value);
87
+ const isbuffer = isBuffer(value);
88
+ const isobject = (
89
+ type === '[object Object]' ||
90
+ type === '[object Array]'
91
+ );
92
+
93
+ const newKey = prev
94
+ ? prev + delimiter + transformKey(key)
95
+ : transformKey(key);
96
+
97
+ if (!isarray && !isbuffer && isobject && Object.keys(value).length &&
98
+ (!opts.maxDepth || currentDepth < maxDepth)) {
99
+ return step(value, newKey, currentDepth + 1)
100
+ }
101
+
102
+ output[newKey] = value;
103
+ });
104
+ }
105
+
106
+ step(target);
107
+
108
+ return output
109
+ }
110
+
111
+ function unflatten (target, opts) {
112
+ opts = opts || {};
113
+
114
+ const delimiter = opts.delimiter || '.';
115
+ const overwrite = opts.overwrite || false;
116
+ const transformKey = opts.transformKey || keyIdentity;
117
+ const result = {};
118
+
119
+ const isbuffer = isBuffer(target);
120
+ if (isbuffer || Object.prototype.toString.call(target) !== '[object Object]') {
121
+ return target
122
+ }
123
+
124
+ // safely ensure that the key is
125
+ // an integer.
126
+ function getkey (key) {
127
+ const parsedKey = Number(key);
128
+
129
+ return (
130
+ isNaN(parsedKey) ||
131
+ key.indexOf('.') !== -1 ||
132
+ opts.object
133
+ ) ? key
134
+ : parsedKey
135
+ }
136
+
137
+ function addKeys (keyPrefix, recipient, target) {
138
+ return Object.keys(target).reduce(function (result, key) {
139
+ result[keyPrefix + delimiter + key] = target[key];
140
+
141
+ return result
142
+ }, recipient)
143
+ }
144
+
145
+ function isEmpty (val) {
146
+ const type = Object.prototype.toString.call(val);
147
+ const isArray = type === '[object Array]';
148
+ const isObject = type === '[object Object]';
149
+
150
+ if (!val) {
151
+ return true
152
+ } else if (isArray) {
153
+ return !val.length
154
+ } else if (isObject) {
155
+ return !Object.keys(val).length
156
+ }
157
+ }
158
+
159
+ target = Object.keys(target).reduce(function (result, key) {
160
+ const type = Object.prototype.toString.call(target[key]);
161
+ const isObject = (type === '[object Object]' || type === '[object Array]');
162
+ if (!isObject || isEmpty(target[key])) {
163
+ result[key] = target[key];
164
+ return result
165
+ } else {
166
+ return addKeys(
167
+ key,
168
+ result,
169
+ flatten$1(target[key], opts)
170
+ )
171
+ }
172
+ }, {});
173
+
174
+ Object.keys(target).forEach(function (key) {
175
+ const split = key.split(delimiter).map(transformKey);
176
+ let key1 = getkey(split.shift());
177
+ let key2 = getkey(split[0]);
178
+ let recipient = result;
179
+
180
+ while (key2 !== undefined) {
181
+ if (key1 === '__proto__') {
182
+ return
183
+ }
184
+
185
+ const type = Object.prototype.toString.call(recipient[key1]);
186
+ const isobject = (
187
+ type === '[object Object]' ||
188
+ type === '[object Array]'
189
+ );
190
+
191
+ // do not write over falsey, non-undefined values if overwrite is false
192
+ if (!overwrite && !isobject && typeof recipient[key1] !== 'undefined') {
193
+ return
194
+ }
195
+
196
+ if ((overwrite && !isobject) || (!overwrite && recipient[key1] == null)) {
197
+ recipient[key1] = (
198
+ typeof key2 === 'number' &&
199
+ !opts.object ? [] : {}
200
+ );
201
+ }
202
+
203
+ recipient = recipient[key1];
204
+ if (split.length > 0) {
205
+ key1 = getkey(split.shift());
206
+ key2 = getkey(split[0]);
207
+ }
208
+ }
209
+
210
+ // unflatten again for 'messy objects'
211
+ recipient[key1] = unflatten(target[key], opts);
212
+ });
213
+
214
+ return result
215
+ }
216
+
217
+ /**
218
+ * Brings the 1st level to the 0th level.
219
+ * Flats the object by nesting with '.' path separator.
220
+ */
221
+ const serializeQueryForSpringBoot = (obj) => {
222
+ const parts = [];
223
+ Object.entries(obj).forEach(([key, val]) => {
224
+ if (Array.isArray(val)) {
225
+ val.forEach((v) => {
226
+ parts.push([key, v]);
227
+ });
228
+ }
229
+ else if (typeof val === 'object') {
230
+ objectToParams(val).forEach(([key, val]) => {
231
+ parts.push([key, val.toString()]);
232
+ });
233
+ }
234
+ else {
235
+ parts.push([key, val]);
236
+ }
237
+ });
238
+ return parts.map((p) => `${p[0]}=${p[1]}`).join('&');
239
+ };
240
+ const flatten = (obj) => {
241
+ const r = flat.flatten(obj);
242
+ // { empty: {} } would be { empty: {} } instead of empty array
243
+ return Object.entries(r).filter(([k, v]) => typeof v !== 'object');
244
+ };
245
+ const objectToParams = (obj) => {
246
+ const [arrayProps, nonArrayProps] = partition((e) => Array.isArray(e[1]), Object.entries(obj));
247
+ const withoutArrayProps = fromPairs(nonArrayProps);
248
+ const res = flatten(withoutArrayProps);
249
+ arrayProps.forEach(([k, vals]) => {
250
+ vals.forEach((v) => res.push([k, v]));
251
+ });
252
+ return res;
253
+ };
254
+
255
+ // @ts-ignore
256
+ const serializeQueryWithQs = (obj) => {
257
+ return qs.stringify(obj);
258
+ };
259
+
260
+ const fileResFilenameRegex = /filename="([^"]+)"/;
261
+ const getFileNameFromContentDispositionHeader = (contentDispositionHeader) => {
262
+ if (!contentDispositionHeader)
263
+ return 'download-file';
264
+ const match = contentDispositionHeader.match(fileResFilenameRegex);
265
+ const fileName = match ? match[1] : 'downloaded-file';
266
+ return fileName;
267
+ };
268
+
269
+ const ContentType = {
270
+ Json: 'application/json',
271
+ FormData: 'multipart/form-data',
272
+ };
273
+
274
+ const qsUrlConverter = () => ({ query, path }) => {
275
+ return {
276
+ url: path + (query ? `?${serializeQueryWithQs(query)}` : ''),
277
+ };
278
+ };
279
+ const springBootUrlConverter = () => ({ query, path }) => {
280
+ return {
281
+ url: path + (query ? `?${serializeQueryForSpringBoot(query)}` : ''),
282
+ };
283
+ };
284
+ const createHttpClient = (client, urlConverter = qsUrlConverter()) => {
285
+ return {
286
+ request: (req) => {
287
+ const { url, params } = urlConverter(req);
288
+ const isBlob = req.format = 'document';
289
+ const obs = client.request(req.method, url, {
290
+ params,
291
+ body: prepareBody(req.body, req.type),
292
+ responseType: (isBlob ? 'blob' : 'json'),
293
+ observe: 'response',
294
+ });
295
+ return obs.pipe(rxjs.map((r) => {
296
+ const { body } = r;
297
+ if (!isBlob)
298
+ return body;
299
+ const data = body;
300
+ const contDisp = r.headers.get('content-disposition');
301
+ return new File([data], getFileNameFromContentDispositionHeader(contDisp), {
302
+ type: data.type
303
+ });
304
+ }));
305
+ },
306
+ };
307
+ };
308
+ const prepareBody = (payload, type) => {
309
+ if (type === ContentType.FormData) {
310
+ return convertToFormData(payload);
311
+ }
312
+ return payload;
313
+ };
314
+ const convertToFormData = (payload) => {
315
+ const formData = new FormData();
316
+ const addProp = (key, val) => {
317
+ if (Array.isArray(val) || val instanceof FileList) {
318
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
319
+ // @ts-ignore - seems that FileList is iterable despite the warning
320
+ // TODO change to other iteration method if this is not true
321
+ for (const valItem of val) {
322
+ addProp(key, valItem);
323
+ }
324
+ }
325
+ else if (typeof val === 'object' && val != null && !(val instanceof File)) {
326
+ throw new Error('Object serialization into FormData not supported');
327
+ }
328
+ else {
329
+ formData.append(key, val);
330
+ }
331
+ };
332
+ Object.entries(payload).forEach(([key, val]) => addProp(key, val));
333
+ return formData;
334
+ };
335
+
336
+ exports.createHttpClient = createHttpClient;
337
+ exports.qsUrlConverter = qsUrlConverter;
338
+ exports.springBootUrlConverter = springBootUrlConverter;
@@ -0,0 +1,2 @@
1
+ export declare const serializeQuery: (obj: any) => any;
2
+ export declare const flattenObject: (obj: any, prefix?: string) => any;
@@ -0,0 +1,19 @@
1
+ import { Observable } from 'rxjs';
2
+ export type ContentType = {};
3
+ export type RequestParams = {};
4
+ export declare const ContentType: {
5
+ Json: string;
6
+ FormData: string;
7
+ };
8
+ export type Request = {
9
+ path: string;
10
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
11
+ format?: 'json';
12
+ query?: any;
13
+ body?: any;
14
+ type?: string;
15
+ secure?: boolean;
16
+ };
17
+ export type HttpClient<Any = any> = {
18
+ request: <Data, A = any>(req: Request) => Observable<Data>;
19
+ };
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@ps-aux/api-client-angular",
3
+ "version": "0.1.0-rc1",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "module": "dist/index.esm.js",
7
+ "scripts": {
8
+ "build": "rollup -c",
9
+ "dev": "rollup -c --watch",
10
+ "publish": "npm run build && npm --access public publish",
11
+ "tc": "tsc"
12
+ },
13
+ "author": "",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "qs": "^6.11.2",
17
+ "rxjs": "^7.8.1"
18
+ },
19
+ "devDependencies": {
20
+ "@angular/common": "^16.2.12"
21
+ }
22
+ }
@@ -0,0 +1,29 @@
1
+ import typescript from 'rollup-plugin-typescript2'
2
+ import resolve from '@rollup/plugin-node-resolve'
3
+ import commonjs from '@rollup/plugin-commonjs'
4
+
5
+ /**
6
+ * @type {import('rollup').RollupOptions}
7
+ */
8
+ const config = {
9
+ input: 'src/index.ts',
10
+ output: [
11
+ {
12
+ file: `dist/index.js`,
13
+ format: 'cjs',
14
+ },
15
+ {
16
+ file: `dist/index.esm.js`,
17
+ format: 'es',
18
+ },
19
+ ],
20
+ plugins: [
21
+ typescript(),
22
+ resolve(),
23
+ commonjs(),
24
+ ],
25
+ external: ['qs', 'rxjs'],
26
+
27
+ }
28
+ export default config
29
+
@@ -0,0 +1,87 @@
1
+ import { HttpClient as AngularHttpClient, HttpResponse } from '@angular/common/http'
2
+ import { map, Observable } from 'rxjs'
3
+ import {
4
+ serializeQueryForSpringBoot,
5
+ serializeQueryWithQs,
6
+ UrlConverter,
7
+ ObservableHttpClient,
8
+ Request, ContentType, getFileNameFromContentDispositionHeader,
9
+ } from '@ps-aux/api-client-common'
10
+
11
+ export const qsUrlConverter: () => UrlConverter = () => ({ query, path }) => {
12
+ return {
13
+ url: path + (query ? `?${serializeQueryWithQs(query)}` : ''),
14
+ }
15
+ }
16
+
17
+ export const springBootUrlConverter: () => UrlConverter = () => ({ query, path }) => {
18
+ return {
19
+ url: path + (query ? `?${serializeQueryForSpringBoot(query)}` : ''),
20
+ }
21
+ }
22
+
23
+
24
+ export const createHttpClient = (client: AngularHttpClient, urlConverter: UrlConverter = qsUrlConverter()): ObservableHttpClient => {
25
+ return {
26
+ request: <D>(req: Request): Observable<D> => {
27
+ const { url, params } = urlConverter(req)
28
+
29
+ const isBlob = req.format = 'document'
30
+
31
+ const obs = client.request<D>(
32
+ req.method,
33
+ url,
34
+ {
35
+ params,
36
+ body: prepareBody(req.body, req.type),
37
+ responseType: (isBlob ? 'blob' : 'json') as any,
38
+ observe: 'response',
39
+ })
40
+
41
+ return obs.pipe(
42
+ map((r: HttpResponse<D>) => {
43
+ const { body } = r
44
+
45
+ if (!isBlob)
46
+ return body as D
47
+
48
+ const data = body as Blob
49
+
50
+ const contDisp = r.headers.get('content-disposition')
51
+ return new File([data], getFileNameFromContentDispositionHeader(contDisp), {
52
+ type: data.type
53
+ }) as D
54
+ }),
55
+ )
56
+ },
57
+ }
58
+ }
59
+
60
+ const prepareBody = (payload: any, type?: string): any => {
61
+ if (type === ContentType.FormData) {
62
+ return convertToFormData(payload)
63
+ }
64
+
65
+ return payload
66
+ }
67
+
68
+ const convertToFormData = (payload: Record<string, any>): FormData => {
69
+ const formData = new FormData()
70
+ const addProp = (key: string, val: any) => {
71
+ if (Array.isArray(val) || val instanceof FileList) {
72
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
73
+ // @ts-ignore - seems that FileList is iterable despite the warning
74
+ // TODO change to other iteration method if this is not true
75
+ for (const valItem of val) {
76
+ addProp(key, valItem)
77
+ }
78
+ } else if (typeof val === 'object' && val != null && !(val instanceof File)) {
79
+ throw new Error('Object serialization into FormData not supported')
80
+ } else {
81
+ formData.append(key, val)
82
+ }
83
+ }
84
+
85
+ Object.entries(payload).forEach(([key, val]) => addProp(key, val))
86
+ return formData
87
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { createHttpClient, springBootUrlConverter, qsUrlConverter } from './AngularApiHttpClient'
2
+
@@ -0,0 +1,45 @@
1
+ // @ts-nocheck
2
+
3
+ // TODO improve typings and check implementation
4
+ export const serializeQuery = (obj: any): any => {
5
+ let result = {};
6
+ if (obj) {
7
+ Object.entries(obj).forEach(([key, val]) => {
8
+ if (Array.isArray(val)) {
9
+ val.map(v => {
10
+ if (result[key]) {
11
+ result[key] += `&${key}=${v}`;
12
+ } else {
13
+ result[key] = v;
14
+ }
15
+ });
16
+ } else if (typeof val === 'object') {
17
+ result = { ...result, ...flattenObject(val) };
18
+ } else {
19
+ result[key] = val;
20
+ }
21
+ });
22
+ }
23
+ return result;
24
+ };
25
+
26
+ export const flattenObject = (obj: any, prefix?: string): any => {
27
+ let str = {};
28
+ const pfix = prefix ? prefix + '.' : '';
29
+
30
+ for (const p in obj) {
31
+ if (obj.hasOwnProperty(p)) {
32
+ if (Array.isArray(obj[p])) {
33
+ str[pfix + p] = obj[p];
34
+ } else if (obj[p] === null) {
35
+ str[pfix + p] = null;
36
+ } else if (typeof obj[p] === 'object') {
37
+ str = { ...str, ...flattenObject(obj[p], pfix + p) };
38
+ } else if (obj[p] !== undefined) {
39
+ str[pfix + p] = obj[p];
40
+ }
41
+ }
42
+ }
43
+
44
+ return str;
45
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "moduleResolution": "node",
4
+ "resolveJsonModule": true,
5
+ "allowJs": true
6
+ },
7
+ "extends": "../../tsconfig.json",
8
+ "include": [
9
+ "src/**/*.ts"
10
+ ]
11
+ }