api-def 0.6.0-alpha9 → 0.6.2-alpha.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.
Files changed (45) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +34 -34
  3. package/cjs/Api.d.ts +1 -0
  4. package/cjs/Api.js +2 -1
  5. package/cjs/ApiConstants.d.ts +1 -0
  6. package/cjs/ApiConstants.js +1 -0
  7. package/cjs/ApiUtils.d.ts +2 -3
  8. package/cjs/ApiUtils.js +13 -21
  9. package/cjs/Endpoint.js +4 -4
  10. package/cjs/MockingTypes.d.ts +1 -0
  11. package/cjs/RequestContext.d.ts +3 -0
  12. package/cjs/RequestContext.js +29 -2
  13. package/cjs/RequestError.js +4 -1
  14. package/cjs/Requester.js +52 -20
  15. package/cjs/backend/AxiosRequestBackend.d.ts +3 -3
  16. package/cjs/backend/AxiosRequestBackend.js +8 -15
  17. package/cjs/backend/FetchRequestBackend.d.ts +3 -3
  18. package/cjs/backend/FetchRequestBackend.js +27 -39
  19. package/cjs/backend/MockRequestBackend.js +15 -7
  20. package/cjs/backend/RequestBackend.d.ts +4 -1
  21. package/cjs/cache/Caching.d.ts +1 -1
  22. package/cjs/index.js +5 -1
  23. package/cjs/middleware/LoggingMiddleware.js +7 -7
  24. package/esm/Api.d.ts +1 -0
  25. package/esm/Api.js +2 -1
  26. package/esm/ApiConstants.d.ts +1 -0
  27. package/esm/ApiConstants.js +1 -0
  28. package/esm/ApiUtils.d.ts +2 -3
  29. package/esm/ApiUtils.js +12 -19
  30. package/esm/Endpoint.js +4 -4
  31. package/esm/MockingTypes.d.ts +1 -0
  32. package/esm/RequestContext.d.ts +3 -0
  33. package/esm/RequestContext.js +29 -2
  34. package/esm/RequestError.js +4 -1
  35. package/esm/Requester.js +46 -14
  36. package/esm/backend/AxiosRequestBackend.d.ts +3 -3
  37. package/esm/backend/AxiosRequestBackend.js +7 -14
  38. package/esm/backend/FetchRequestBackend.d.ts +3 -3
  39. package/esm/backend/FetchRequestBackend.js +26 -38
  40. package/esm/backend/MockRequestBackend.js +11 -3
  41. package/esm/backend/RequestBackend.d.ts +4 -1
  42. package/esm/cache/Caching.d.ts +1 -1
  43. package/esm/middleware/LoggingMiddleware.js +7 -7
  44. package/package.json +17 -5
  45. package/CHANGELOG.md +0 -71
@@ -55,7 +55,6 @@ var Utils = require("../Utils");
55
55
  var Utils_1 = require("../Utils");
56
56
  var ApiConstants_1 = require("../ApiConstants");
57
57
  var ApiUtils_1 = require("../ApiUtils");
58
- var RequestError_1 = require("../RequestError");
59
58
  var FetchError = /** @class */ (function (_super) {
60
59
  __extends(FetchError, _super);
61
60
  function FetchError() {
@@ -65,7 +64,7 @@ var FetchError = /** @class */ (function (_super) {
65
64
  }(Error));
66
65
  var FetchRequestBackend = /** @class */ (function () {
67
66
  function FetchRequestBackend(fetchLibrary) {
68
- this.fetch = Utils_1.getGlobalFetch();
67
+ this.fetch = (0, Utils_1.getGlobalFetch)();
69
68
  this.id = "fetch";
70
69
  if (fetchLibrary !== undefined) {
71
70
  this.fetch = fetchLibrary;
@@ -83,59 +82,47 @@ var FetchRequestBackend = /** @class */ (function () {
83
82
  });
84
83
  });
85
84
  };
86
- FetchRequestBackend.prototype.convertResponse = function (context, response, error) {
85
+ FetchRequestBackend.prototype.convertResponse = function (context, response) {
87
86
  return __awaiter(this, void 0, void 0, function () {
88
- var data, contentType, inferredResponseType, responseType, _a, error_1, status;
87
+ var contentType, responseType, _a, data, status, headers, error_1;
89
88
  return __generator(this, function (_b) {
90
89
  switch (_b.label) {
91
90
  case 0:
92
91
  contentType = response.headers.get("Content-Type");
93
- inferredResponseType = ApiUtils_1.inferResponseType(contentType);
94
- responseType = error ? inferredResponseType : context.responseType;
95
- // expand to array buffer once we support that in inferResponseType
96
- if (inferredResponseType === "text" && context.responseType === "json") {
97
- throw RequestError_1.convertToRequestError({
98
- error: new Error("[api-def] Expected '" + context.responseType + "' response, got '" + inferredResponseType + "' (from 'Content-Type' of '" + contentType + "')"),
99
- code: RequestError_1.RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
100
- });
101
- }
102
- _b.label = 1;
103
- case 1:
104
- _b.trys.push([1, 8, , 9]);
105
- if (!!response.__text) return [3 /*break*/, 3];
92
+ responseType = (0, ApiUtils_1.inferResponseType)(contentType);
93
+ if (!!response.__text) return [3 /*break*/, 2];
106
94
  _a = response;
107
95
  return [4 /*yield*/, response.clone().text()];
108
- case 2:
96
+ case 1:
109
97
  _a.__text = _b.sent();
98
+ _b.label = 2;
99
+ case 2:
100
+ data = response.__text;
101
+ status = response.status, headers = response.headers;
110
102
  _b.label = 3;
111
103
  case 3:
112
- if (!(responseType === ApiConstants_1.ResponseType.Text)) return [3 /*break*/, 4];
113
- data = response.__text;
114
- return [3 /*break*/, 7];
115
- case 4:
116
- if (!(responseType === ApiConstants_1.ResponseType.ArrayBuffer)) return [3 /*break*/, 6];
104
+ _b.trys.push([3, 7, , 8]);
105
+ if (!(responseType === ApiConstants_1.ResponseType.ArrayBuffer)) return [3 /*break*/, 5];
117
106
  return [4 /*yield*/, response.clone().arrayBuffer()];
118
- case 5:
107
+ case 4:
119
108
  data = _b.sent();
120
- return [3 /*break*/, 7];
121
- case 6:
109
+ return [3 /*break*/, 6];
110
+ case 5:
122
111
  if (responseType === ApiConstants_1.ResponseType.Json) {
123
112
  data = JSON.parse(response.__text);
124
113
  }
125
- _b.label = 7;
126
- case 7: return [3 /*break*/, 9];
127
- case 8:
114
+ _b.label = 6;
115
+ case 6: return [3 /*break*/, 8];
116
+ case 7:
128
117
  error_1 = _b.sent();
129
- throw Object.assign(new Error("[api-def] Invalid '" + context.responseType + "' response, got: '" + response.__text + "'"), {
118
+ throw Object.assign(new Error("[api-def] Invalid '".concat(context.responseType, "' response, got: '").concat(response.__text, "'")), {
130
119
  response: response,
131
120
  });
132
- case 9:
133
- status = response.status;
134
- return [2 /*return*/, {
135
- data: data,
136
- status: status,
137
- headers: response.headers,
138
- }];
121
+ case 8: return [2 /*return*/, {
122
+ data: data,
123
+ status: status,
124
+ headers: headers,
125
+ }];
139
126
  }
140
127
  });
141
128
  });
@@ -174,7 +161,8 @@ var FetchRequestBackend = /** @class */ (function () {
174
161
  var abortSignal = abortController ? abortController.signal : undefined;
175
162
  var softAbort = false;
176
163
  var responded = false;
177
- var bodyJsonify = computedConfig.body !== null && typeof computedConfig.body === "object";
164
+ var body = context.getParsedBody();
165
+ var bodyJsonify = body !== null && typeof body === "object";
178
166
  var headers = Utils.assign({
179
167
  // logic from axios
180
168
  "Content-Type": bodyJsonify ? "application/json;charset=utf-8" : "application/x-www-form-urlencoded",
@@ -188,7 +176,7 @@ var FetchRequestBackend = /** @class */ (function () {
188
176
  }, {});
189
177
  var promise = this.fetch(url.href, {
190
178
  method: context.method,
191
- body: bodyJsonify ? JSON.stringify(computedConfig.body) : computedConfig.body,
179
+ body: bodyJsonify ? JSON.stringify(body) : body,
192
180
  headers: parsedHeaders,
193
181
  mode: "cors",
194
182
  signal: abortSignal,
@@ -65,25 +65,26 @@ var MockRequestBackend = /** @class */ (function () {
65
65
  MockRequestBackend.prototype.runRequest = function (context) {
66
66
  var _a, _b, _c, _d;
67
67
  return __awaiter(this, void 0, void 0, function () {
68
- var mockingFunc, req, res, delay, delayMs, min, max, _e;
68
+ var mockingFunc, req, res, delay, delayMs, min, max, _e, parsedHeaders;
69
69
  return __generator(this, function (_f) {
70
70
  switch (_f.label) {
71
71
  case 0:
72
72
  mockingFunc = (_a = context.mocking) === null || _a === void 0 ? void 0 : _a.handler;
73
73
  if (!mockingFunc) {
74
- throw RequestError_1.convertToRequestError({
74
+ throw (0, RequestError_1.convertToRequestError)({
75
75
  error: new Error("[api-def] Attempted to run mocked request without mocking function"),
76
76
  code: RequestError_1.RequestErrorCode.REQUEST_INVALID_CONFIG,
77
77
  });
78
78
  }
79
79
  req = {
80
- body: context.computedConfig.body,
80
+ body: context.getParsedBody(),
81
81
  params: (_b = context.computedConfig.params) !== null && _b !== void 0 ? _b : {},
82
82
  query: context.computedConfig.query,
83
83
  headers: (_c = context.computedConfig.headers) !== null && _c !== void 0 ? _c : {},
84
84
  };
85
85
  res = {
86
86
  statusCode: -1,
87
+ headers: {},
87
88
  response: undefined,
88
89
  status: function (statusCode) {
89
90
  res.statusCode = statusCode;
@@ -91,6 +92,9 @@ var MockRequestBackend = /** @class */ (function () {
91
92
  },
92
93
  send: function (response) {
93
94
  res.response = response;
95
+ if (response && typeof response === "object") {
96
+ res.headers["Content-Type"] = "application/json";
97
+ }
94
98
  return res;
95
99
  },
96
100
  };
@@ -103,12 +107,12 @@ var MockRequestBackend = /** @class */ (function () {
103
107
  else {
104
108
  min = delay[0], max = delay[1];
105
109
  if (min > max) {
106
- throw RequestError_1.convertToRequestError({
110
+ throw (0, RequestError_1.convertToRequestError)({
107
111
  error: new Error("[api-def] Min delay cannot be greater than max delay"),
108
112
  code: RequestError_1.RequestErrorCode.REQUEST_INVALID_CONFIG,
109
113
  });
110
114
  }
111
- delayMs = Utils_1.randInt(min, max);
115
+ delayMs = (0, Utils_1.randInt)(min, max);
112
116
  }
113
117
  _e = Utils_1.delayThenReturn;
114
118
  return [4 /*yield*/, mockingFunc(req, res)];
@@ -122,13 +126,17 @@ var MockRequestBackend = /** @class */ (function () {
122
126
  _f.label = 5;
123
127
  case 5:
124
128
  if (res.response === undefined) {
125
- throw RequestError_1.convertToRequestError({
129
+ throw (0, RequestError_1.convertToRequestError)({
126
130
  error: new Error("[api-def] Mocked API did not respond"),
127
131
  code: RequestError_1.RequestErrorCode.REQUEST_INVALID_CONFIG,
128
132
  });
129
133
  }
134
+ parsedHeaders = Object.keys(res.headers).reduce(function (parsedHeaders, key) {
135
+ parsedHeaders[key] = res.headers[key].toString();
136
+ return parsedHeaders;
137
+ }, {});
130
138
  return [2 /*return*/, {
131
- headers: {},
139
+ headers: parsedHeaders,
132
140
  data: res.response,
133
141
  status: res.statusCode,
134
142
  }];
@@ -7,10 +7,13 @@ export interface RequestOperation<R> {
7
7
  export interface RequestBackendErrorInfo {
8
8
  code: string;
9
9
  }
10
+ export declare type ConvertedApiResponse<T> = ApiResponse<T> & {
11
+ __lowercaseHeaders?: any;
12
+ };
10
13
  export default interface RequestBackend<R = any> {
11
14
  readonly id: string;
12
15
  makeRequest(context: RequestContext): RequestOperation<R>;
13
- convertResponse<T>(context: RequestContext, response: R, error?: boolean): Promise<ApiResponse<T>>;
16
+ convertResponse<T>(context: RequestContext, response: R): Promise<ConvertedApiResponse<T>>;
14
17
  extractResponseFromError(error: Error): Promise<R | null | undefined>;
15
18
  getErrorInfo(error: Error, response: ApiResponse | undefined | null): RequestBackendErrorInfo | undefined;
16
19
  }
@@ -6,5 +6,5 @@ export interface CacheEntry {
6
6
  data: any;
7
7
  expiry: number | null;
8
8
  }
9
- export declare const setCachedItem: <T>(key: string, value: T, expiry?: number | undefined) => Promise<T>;
9
+ export declare const setCachedItem: <T>(key: string, value: T, expiry?: number) => Promise<T>;
10
10
  export declare const getCachedItem: <T = any>(key: string) => Promise<T | undefined>;
package/cjs/index.js CHANGED
@@ -2,7 +2,11 @@
2
2
  "use strict";
3
3
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
4
  if (k2 === undefined) k2 = k;
5
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
6
10
  }) : (function(o, m, k, k2) {
7
11
  if (k2 === undefined) k2 = k;
8
12
  o[k2] = m[k];
@@ -30,12 +30,12 @@ var diagnoseError = function (error) {
30
30
  var _a = error.response, status = _a.status, data = _a.data;
31
31
  var code = data === null || data === void 0 ? void 0 : data.code;
32
32
  return {
33
- message: "responded with " + status + (code ? " (" + code + ")" : ""),
33
+ message: "responded with ".concat(status).concat(code ? " (".concat(code, ")") : ""),
34
34
  response: error.response,
35
35
  };
36
36
  };
37
37
  var formatTime = function (time) {
38
- return Utils.padNumber(time.getHours(), 2) + ":" + Utils.padNumber(time.getMinutes(), 2) + ":" + Utils.padNumber(time.getSeconds(), 2) + "." + Utils.padNumber(time.getMilliseconds(), 3);
38
+ return "".concat(Utils.padNumber(time.getHours(), 2), ":").concat(Utils.padNumber(time.getMinutes(), 2), ":").concat(Utils.padNumber(time.getSeconds(), 2), ".").concat(Utils.padNumber(time.getMilliseconds(), 3));
39
39
  };
40
40
  var log = function (context, type, message, config, objects) {
41
41
  if (typeof config.predicate === "function" && !config.predicate()) {
@@ -45,10 +45,10 @@ var log = function (context, type, message, config, objects) {
45
45
  var color = COLOR_MAP[type];
46
46
  var timestamp = formatTime(new Date());
47
47
  var args = [
48
- "%cnetwork %c[" + context.api.name + "] " + context.method.toUpperCase() + " " + computedPath + " %c" + message + " %c@ " + timestamp,
48
+ "%cnetwork %c[".concat(context.api.name, "] ").concat(context.method.toUpperCase(), " ").concat(computedPath, " %c").concat(message, " %c@ ").concat(timestamp),
49
49
  "color:gray",
50
50
  "color:auto",
51
- "color:" + color,
51
+ "color:".concat(color),
52
52
  "color:gray",
53
53
  ];
54
54
  /* eslint-disable-next-line no-console */
@@ -68,18 +68,18 @@ var LoggingMiddleware = function (config) {
68
68
  _a[ApiConstants_1.RequestEvent.Success] = function (context) {
69
69
  var _a;
70
70
  var cacheSource = context.cacheInfo.source;
71
- log(context, LogType.Success, "responded with " + ((_a = context.response) === null || _a === void 0 ? void 0 : _a.status) + (cacheSource ? " (cached by " + cacheSource + ")" : ""), config);
71
+ log(context, LogType.Success, "responded with ".concat((_a = context.response) === null || _a === void 0 ? void 0 : _a.status).concat(cacheSource ? " (cached by ".concat(cacheSource, ")") : ""), config);
72
72
  },
73
73
  _a[ApiConstants_1.RequestEvent.Error] = function (context) {
74
74
  if (context.error) {
75
75
  var _a = diagnoseError(context.error), error = _a.error, message = _a.message;
76
- log(context, LogType.Warn, "error on attempt " + context.stats.attempt + " - " + message, config, { error: error });
76
+ log(context, LogType.Warn, "error on attempt ".concat(context.stats.attempt, " - ").concat(message), config, { error: error });
77
77
  }
78
78
  },
79
79
  _a[ApiConstants_1.RequestEvent.UnrecoverableError] = function (context) {
80
80
  if (context.error) {
81
81
  var _a = diagnoseError(context.error), error = _a.error, message = _a.message;
82
- log(context, LogType.Error, "failed - " + message, config, {
82
+ log(context, LogType.Error, "failed - ".concat(message), config, {
83
83
  error: error,
84
84
  });
85
85
  }
package/esm/Api.d.ts CHANGED
@@ -28,4 +28,5 @@ export declare class Api implements ApiInfo {
28
28
  post: <R = unknown>(path: string, config: RequestConfig) => Promise<ApiResponse<R>>;
29
29
  put: <R = unknown>(path: string, config: RequestConfig) => Promise<ApiResponse<R>>;
30
30
  delete: <R = unknown>(path: string, config: RequestConfig) => Promise<ApiResponse<R>>;
31
+ patch: <R = unknown>(path: string, config: RequestConfig) => Promise<ApiResponse<R>>;
31
32
  }
package/esm/Api.js CHANGED
@@ -71,7 +71,7 @@ var HotRequestHost = /** @class */ (function () {
71
71
  return Utils.assign({}, apiDefaults, config);
72
72
  };
73
73
  HotRequestHost.prototype.computePath = function (path, config) {
74
- return path.startsWith("/") ? path : "/" + path;
74
+ return path.startsWith("/") ? path : "/".concat(path);
75
75
  };
76
76
  return HotRequestHost;
77
77
  }());
@@ -92,6 +92,7 @@ var Api = /** @class */ (function () {
92
92
  this.post = this.hotRequest(RequestMethod.POST);
93
93
  this.put = this.hotRequest(RequestMethod.PUT);
94
94
  this.delete = this.hotRequest(RequestMethod.DELETE);
95
+ this.patch = this.hotRequest(RequestMethod.PATCH);
95
96
  this.name = info.name;
96
97
  this.baseUrl = info.baseUrl;
97
98
  this.middleware = info.middleware || [];
@@ -8,6 +8,7 @@ export declare const RequestMethod: {
8
8
  readonly GET: "get";
9
9
  readonly PUT: "put";
10
10
  readonly DELETE: "delete";
11
+ readonly PATCH: "patch";
11
12
  };
12
13
  export declare type RequestMethod = EnumOf<typeof RequestMethod>;
13
14
  export declare const RequestEvent: {
@@ -7,6 +7,7 @@ export var RequestMethod = {
7
7
  GET: "get",
8
8
  PUT: "put",
9
9
  DELETE: "delete",
10
+ PATCH: "patch",
10
11
  };
11
12
  export var RequestEvent = {
12
13
  /** @deprecated use 'BEFORE_SEND' */
package/esm/ApiUtils.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import { AcceptableStatus, ApiResponse, CancelledRequestError } from "./ApiTypes";
1
+ import { AcceptableStatus, CancelledRequestError } from "./ApiTypes";
2
2
  import { ResponseType } from "./ApiConstants";
3
3
  export declare const isCancelledError: (error: Error) => error is CancelledRequestError;
4
4
  export declare const isNetworkError: (error: Error) => boolean;
5
- export declare const parseResponseDataToObject: (response: ApiResponse) => void;
6
- export declare const isAcceptableStatus: (status: number, acceptableStatus?: AcceptableStatus[] | undefined) => boolean;
5
+ export declare const isAcceptableStatus: (status: number, acceptableStatus?: AcceptableStatus[]) => boolean;
7
6
  export declare const inferResponseType: (contentType: string | null | undefined) => ResponseType;
package/esm/ApiUtils.js CHANGED
@@ -1,4 +1,3 @@
1
- import { textDecode } from "./TextDecoding";
2
1
  export var isCancelledError = function (error) {
3
2
  return "isCancelledRequest" in error;
4
3
  };
@@ -8,22 +7,6 @@ export var isNetworkError = function (error) {
8
7
  error.message === "Network Error" ||
9
8
  ((_a = error.constructor) === null || _a === void 0 ? void 0 : _a.name) === "NetworkError");
10
9
  };
11
- export var parseResponseDataToObject = function (response) {
12
- if (response.data &&
13
- typeof response.data === "object") {
14
- var data = response.data;
15
- if (data.constructor && data.constructor.name === "ArrayBuffer") {
16
- try {
17
- var decodedData = (response.data = textDecode(data));
18
- response.data = JSON.parse(decodedData);
19
- }
20
- catch (e) {
21
- // eslint-disable-next-line
22
- console.warn("[api-def] Couldn't parse array buffer content to JSON response", e);
23
- }
24
- }
25
- }
26
- };
27
10
  var DEFAULT_ACCEPTABLE_STATUS = [[200, 299], 304];
28
11
  export var isAcceptableStatus = function (status, acceptableStatus) {
29
12
  var acceptable = acceptableStatus !== null && acceptableStatus !== void 0 ? acceptableStatus : DEFAULT_ACCEPTABLE_STATUS;
@@ -43,11 +26,21 @@ export var isAcceptableStatus = function (status, acceptableStatus) {
43
26
  }
44
27
  return (false);
45
28
  };
29
+ var TEXT_CONTENT_TYPES = ["text/plain"];
46
30
  var JSON_CONTENT_TYPES = ["text/json", "application/json"];
31
+ var ARRRAY_BUFFER_CONTENT_TYPES = ["application/octet-stream"];
47
32
  export var inferResponseType = function (contentType) {
48
33
  var contentTypePart = contentType === null || contentType === void 0 ? void 0 : contentType.split(";")[0].trim();
49
- if (contentTypePart && JSON_CONTENT_TYPES.includes(contentTypePart)) {
50
- return "json";
34
+ if (contentTypePart) {
35
+ if (TEXT_CONTENT_TYPES.includes(contentTypePart)) {
36
+ return "text";
37
+ }
38
+ else if (JSON_CONTENT_TYPES.includes(contentTypePart)) {
39
+ return "json";
40
+ }
41
+ else if (ARRRAY_BUFFER_CONTENT_TYPES.includes(contentTypePart)) {
42
+ return "arraybuffer";
43
+ }
51
44
  }
52
45
  return "text";
53
46
  };
package/esm/Endpoint.js CHANGED
@@ -60,7 +60,7 @@ var Endpoint = /** @class */ (function () {
60
60
  mockingEnabled = (_a = (typeof apiMocking.enabled === "function" ? apiMocking.enabled() : apiMocking.enabled)) !== null && _a !== void 0 ? _a : false;
61
61
  if (mockingEnabled) {
62
62
  if (!((_b = this.mocking) === null || _b === void 0 ? void 0 : _b.handler)) {
63
- throw new Error("[api-def] Endpoint for '" + this.path + "' has no mocking");
63
+ throw new Error("[api-def] Endpoint for '".concat(this.path, "' has no mocking"));
64
64
  }
65
65
  mock = true;
66
66
  }
@@ -70,16 +70,16 @@ var Endpoint = /** @class */ (function () {
70
70
  });
71
71
  };
72
72
  Endpoint.prototype.computePath = function (path, request) {
73
- var computedPath = path.startsWith("/") ? path : "/" + path;
73
+ var computedPath = path.startsWith("/") ? path : "/".concat(path);
74
74
  if (request.params) {
75
75
  var keys = Object.keys(request.params);
76
76
  for (var i = 0; i < keys.length; i++) {
77
77
  var argName = keys[i];
78
- computedPath = computedPath.replace(":" + argName, request.params[argName]);
78
+ computedPath = computedPath.replace(":".concat(argName), request.params[argName]);
79
79
  }
80
80
  }
81
81
  if (computedPath.includes(":")) {
82
- throw new Error("[api-def] Not all path params have been resolved: '" + computedPath + "'");
82
+ throw new Error("[api-def] Not all path params have been resolved: '".concat(computedPath, "'"));
83
83
  }
84
84
  return computedPath;
85
85
  };
@@ -11,6 +11,7 @@ export interface MockRequest<R = any, P extends Params | undefined = Params | un
11
11
  export interface MockResponse<R = any, P extends Params | undefined = Params | undefined, Q extends Query | undefined = Query | undefined, B extends Body | undefined = Body | undefined> {
12
12
  statusCode: number;
13
13
  response: R | undefined;
14
+ headers: Headers;
14
15
  status(statusCode: number): this;
15
16
  send(response: R): this;
16
17
  }
@@ -19,6 +19,7 @@ export default class RequestContext<R = any, P extends Params | undefined = Para
19
19
  cancelled: boolean;
20
20
  readonly computedConfig: RequestConfig<P, Q, B>;
21
21
  readonly mocking: EndpointMockingConfig<R, P, Q, B> | null | undefined;
22
+ private parsedBody;
22
23
  constructor(backend: RequestBackend, host: RequestHost, config: RequestConfig<P, Q, B>, computedPath: string, mocking: EndpointMockingConfig<R, P, Q, B> | null | undefined);
23
24
  get method(): RequestMethod;
24
25
  get api(): Api;
@@ -27,6 +28,8 @@ export default class RequestContext<R = any, P extends Params | undefined = Para
27
28
  private initMiddleware;
28
29
  private generateKey;
29
30
  updateHeaders(newHeaders: Headers): this;
31
+ private parseRequestBody;
32
+ getParsedBody(): any;
30
33
  updateQuery(newQuery: Partial<Q>): this;
31
34
  triggerEvent(eventType: RequestEvent): Promise<EventResult<R> | undefined>;
32
35
  addCanceller(canceler: () => void): void;
@@ -35,6 +35,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
35
  }
36
36
  };
37
37
  import * as Utils from "./Utils";
38
+ import { URLSearchParams } from "url";
38
39
  var contextIdCounter = 0;
39
40
  var RequestContext = /** @class */ (function () {
40
41
  function RequestContext(backend, host, config, computedPath, mocking) {
@@ -47,7 +48,7 @@ var RequestContext = /** @class */ (function () {
47
48
  this.id = contextIdCounter++;
48
49
  this.host = host;
49
50
  this.computedConfig = config;
50
- Utils.assign({}, this.computedConfig.headers, { "Request-Id": this.id });
51
+ Utils.assign({}, this.computedConfig.headers);
51
52
  this.computedPath = computedPath;
52
53
  this.key = this.generateKey();
53
54
  this.stats = {
@@ -57,6 +58,7 @@ var RequestContext = /** @class */ (function () {
57
58
  this.eventHandlers = {};
58
59
  this.mocking = mocking;
59
60
  this.initMiddleware();
61
+ this.parseRequestBody();
60
62
  }
61
63
  Object.defineProperty(RequestContext.prototype, "method", {
62
64
  get: function () {
@@ -109,7 +111,7 @@ var RequestContext = /** @class */ (function () {
109
111
  var queryKeys = Object.keys(computedConfig.query);
110
112
  for (var i = 0; i < queryKeys.length; i++) {
111
113
  var queryKey = queryKeys[i];
112
- queryStrings.push(queryKey + "=" + computedConfig.query[queryKey]);
114
+ queryStrings.push("".concat(queryKey, "=").concat(computedConfig.query[queryKey]));
113
115
  }
114
116
  }
115
117
  if (queryStrings.length > 0) {
@@ -119,8 +121,33 @@ var RequestContext = /** @class */ (function () {
119
121
  };
120
122
  RequestContext.prototype.updateHeaders = function (newHeaders) {
121
123
  this.computedConfig.headers = Utils.assign({}, this.computedConfig.headers, newHeaders);
124
+ this.parseRequestBody();
122
125
  return this;
123
126
  };
127
+ RequestContext.prototype.parseRequestBody = function () {
128
+ if (this.computedConfig.body && this.computedConfig.headers) {
129
+ var contentTypeKey = Object.keys(this.computedConfig.headers).find(function (key) { return key.toLowerCase() === "content-type"; });
130
+ var contentType = contentTypeKey && this.computedConfig.headers[contentTypeKey];
131
+ if (typeof contentType === "string" && contentType.toLowerCase() === "multipart/form-data") {
132
+ var searchParams = new URLSearchParams();
133
+ for (var _i = 0, _a = Object.keys(this.computedConfig.body); _i < _a.length; _i++) {
134
+ var key = _a[_i];
135
+ var value = this.computedConfig.body[key];
136
+ searchParams.set(key, value === null || value === void 0 ? void 0 : value.toString());
137
+ }
138
+ this.parsedBody = searchParams.toString();
139
+ }
140
+ else {
141
+ this.parsedBody = this.computedConfig.body;
142
+ }
143
+ }
144
+ else {
145
+ this.parsedBody = undefined;
146
+ }
147
+ };
148
+ RequestContext.prototype.getParsedBody = function () {
149
+ return this.parsedBody;
150
+ };
124
151
  RequestContext.prototype.updateQuery = function (newQuery) {
125
152
  this.computedConfig.query = Utils.assign(this.computedConfig.query || {}, newQuery);
126
153
  return this;
@@ -11,9 +11,12 @@ export var isRequestError = function (error) {
11
11
  export var convertToRequestError = function (config) {
12
12
  var error = config.error, response = config.response, code = config.code;
13
13
  return Object.assign(error, {
14
- name: error.name === "Error" ? "RequestError" : error.name,
14
+ name: "RequestError",
15
15
  response: response,
16
16
  code: code,
17
17
  isRequestError: true,
18
+ config: undefined,
19
+ request: undefined,
20
+ toJSON: undefined,
18
21
  });
19
22
  };
package/esm/Requester.js CHANGED
@@ -46,13 +46,14 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
46
46
  }
47
47
  };
48
48
  import * as ApiUtils from "./ApiUtils";
49
- import { isAcceptableStatus, isNetworkError } from "./ApiUtils";
49
+ import { inferResponseType, isAcceptableStatus, isNetworkError } from "./ApiUtils";
50
50
  import RequestContext from "./RequestContext";
51
51
  import * as Api from "./Api";
52
52
  import { EventResultType, RequestEvent } from "./ApiConstants";
53
53
  import retry from "./util/retry";
54
54
  import MockRequestBackend from "./backend/MockRequestBackend";
55
55
  import { convertToRequestError, isRequestError, RequestErrorCode } from "./RequestError";
56
+ import { textDecode } from "./TextDecoding";
56
57
  var locks = {};
57
58
  var runningOperations = {};
58
59
  var MOCK_REQUEST_BACKEND = new MockRequestBackend();
@@ -153,7 +154,7 @@ var makeRequest = function (context) { return __awaiter(void 0, void 0, void 0,
153
154
  parsedResponse = (_b.sent());
154
155
  if (!isAcceptableStatus(parsedResponse.status, context.computedConfig.acceptableStatus)) {
155
156
  throw convertToRequestError({
156
- error: new Error("[api-def] Invalid response status code '" + parsedResponse.status + "'"),
157
+ error: new Error("[api-def] Invalid response status code '".concat(parsedResponse.status, "'")),
157
158
  response: parsedResponse,
158
159
  code: RequestErrorCode.REQUEST_INVALID_STATUS,
159
160
  });
@@ -170,10 +171,6 @@ var makeRequest = function (context) { return __awaiter(void 0, void 0, void 0,
170
171
  error = _b.sent();
171
172
  context.error = error;
172
173
  context.response = error.response;
173
- // transform array buffer responses to objs
174
- if (context.response) {
175
- ApiUtils.parseResponseDataToObject(context.response);
176
- }
177
174
  return [4 /*yield*/, context.triggerEvent(RequestEvent.Error)];
178
175
  case 6:
179
176
  errorEventResult = _b.sent();
@@ -210,18 +207,53 @@ var makeRequest = function (context) { return __awaiter(void 0, void 0, void 0,
210
207
  });
211
208
  }); };
212
209
  var parseResponse = function (context, response, error) { return __awaiter(void 0, void 0, void 0, function () {
213
- var parsedResponse;
214
- return __generator(this, function (_a) {
215
- switch (_a.label) {
210
+ var parsedResponse_1, contentType, inferredResponseType, data, decodedData;
211
+ var _a;
212
+ return __generator(this, function (_b) {
213
+ switch (_b.label) {
216
214
  case 0:
217
215
  if (!response) return [3 /*break*/, 2];
218
- return [4 /*yield*/, context.backend.convertResponse(context, response, error)];
216
+ return [4 /*yield*/, context.backend.convertResponse(context, response)];
219
217
  case 1:
220
- parsedResponse = _a.sent();
221
- if (parsedResponse) {
222
- ApiUtils.parseResponseDataToObject(parsedResponse);
218
+ parsedResponse_1 = _b.sent();
219
+ // lowercase all header names
220
+ parsedResponse_1.headers = parsedResponse_1.__lowercaseHeaders || Object.keys(parsedResponse_1.headers).reduce(function (headers, header) {
221
+ headers[header.toLowerCase()] = parsedResponse_1.headers[header];
222
+ return headers;
223
+ }, {});
224
+ contentType = parsedResponse_1.headers["content-type"];
225
+ inferredResponseType = inferResponseType(contentType);
226
+ if (!error) {
227
+ // expand to array buffer once we support that in inferResponseType
228
+ if (inferredResponseType === "text" && context.responseType === "json") {
229
+ throw convertToRequestError({
230
+ error: new Error("[api-def] Expected '".concat(context.responseType, "' response, got '").concat(inferredResponseType, "' (from 'Content-Type' of '").concat(contentType, "')")),
231
+ code: RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
232
+ response: parsedResponse_1,
233
+ });
234
+ }
235
+ // transform arrayBuffer to json
236
+ if (inferredResponseType === "arraybuffer" && context.responseType === "json") {
237
+ if (parsedResponse_1.data &&
238
+ typeof parsedResponse_1.data === "object") {
239
+ data = response.data;
240
+ if (((_a = data.constructor) === null || _a === void 0 ? void 0 : _a.name) === "ArrayBuffer") {
241
+ try {
242
+ decodedData = (response.data = textDecode(data));
243
+ response.data = JSON.parse(decodedData);
244
+ }
245
+ catch (e) {
246
+ throw convertToRequestError({
247
+ error: new Error("[api-def] Expected '".concat(context.responseType, "' response, got '").concat(inferredResponseType, "' (from 'Content-Type' of '").concat(contentType, "')")),
248
+ code: RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
249
+ response: parsedResponse_1,
250
+ });
251
+ }
252
+ }
253
+ }
254
+ }
223
255
  }
224
- return [2 /*return*/, parsedResponse];
256
+ return [2 /*return*/, parsedResponse_1];
225
257
  case 2: return [2 /*return*/, response];
226
258
  }
227
259
  });