@odata2ts/http-client-axios 0.7.0 → 0.8.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.8.1](https://github.com/odata2ts/http-client/compare/@odata2ts/http-client-axios@0.8.0...@odata2ts/http-client-axios@0.8.1) (2023-07-26)
7
+
8
+ **Note:** Version bump only for package @odata2ts/http-client-axios
9
+
10
+ # [0.8.0](https://github.com/odata2ts/http-client/compare/@odata2ts/http-client-axios@0.7.0...@odata2ts/http-client-axios@0.8.0) (2023-06-10)
11
+
12
+ ### Features
13
+
14
+ * conventionalize client errors ([#5](https://github.com/odata2ts/http-client/issues/5)) ([a8e8912](https://github.com/odata2ts/http-client/commit/a8e89125eeda47436d48507d6a71efc90953f878))
15
+
6
16
  # 0.7.0 (2023-06-03)
7
17
 
8
18
  ### Features
@@ -1,26 +1,15 @@
1
- import { HttpResponseModel, ODataHttpClient } from "@odata2ts/http-client-api";
1
+ import { HttpResponseModel } from "@odata2ts/http-client-api";
2
+ import { BaseHttpClient, BaseHttpClientOptions, HttpMethods } from "@odata2ts/http-client-base";
3
+ import { AxiosInstance, AxiosResponseHeaders, RawAxiosResponseHeaders } from "axios";
2
4
  import { AxiosRequestConfig } from "./AxiosRequestConfig";
3
- export type ErrorMessageRetriever<ResponseType = any> = (error: any) => string | null | undefined;
4
- export interface ClientOptions {
5
- useCsrfProtection?: boolean;
6
- csrfTokenFetchUrl?: string;
5
+ export interface ClientOptions extends BaseHttpClientOptions {
7
6
  }
8
7
  export declare const DEFAULT_ERROR_MESSAGE = "No error message!";
9
- export declare const getV2OrV4ErrorMessage: ErrorMessageRetriever;
10
- export declare class AxiosClient implements ODataHttpClient<AxiosRequestConfig> {
8
+ export declare class AxiosClient extends BaseHttpClient<AxiosRequestConfig> {
11
9
  private clientOptions?;
12
- private readonly client;
13
- private csrfToken;
14
- private getErrorMessage;
10
+ protected readonly client: AxiosInstance;
15
11
  constructor(config?: AxiosRequestConfig, clientOptions?: ClientOptions | undefined);
16
- setErrorMessageRetriever<T = any>(getErrorMsg: ErrorMessageRetriever<T>): void;
17
- private setupSecurityToken;
18
- private fetchSecurityToken;
19
- private sendRequest;
20
- post<ResponseModel>(url: string, data: any, requestConfig?: AxiosRequestConfig): Promise<HttpResponseModel<ResponseModel>>;
21
- get<ResponseModel>(url: string, requestConfig?: AxiosRequestConfig): Promise<HttpResponseModel<ResponseModel>>;
22
- put<ResponseModel>(url: string, data: any, requestConfig?: AxiosRequestConfig): Promise<HttpResponseModel<ResponseModel>>;
23
- patch<ResponseModel>(url: string, data: any, requestConfig?: AxiosRequestConfig): Promise<HttpResponseModel<ResponseModel>>;
24
- merge<ResponseModel>(url: string, data: any, requestConfig?: AxiosRequestConfig): Promise<HttpResponseModel<ResponseModel>>;
25
- delete(url: string, requestConfig?: AxiosRequestConfig): Promise<HttpResponseModel<void>>;
12
+ protected addHeaderToRequestConfig(headers: Record<string, string>, config: AxiosRequestConfig | undefined): AxiosRequestConfig;
13
+ protected executeRequest<ResponseModel>(method: HttpMethods, url: string, data: any, requestConfig?: AxiosRequestConfig | undefined): Promise<HttpResponseModel<ResponseModel>>;
14
+ protected mapHeaders(headers: AxiosResponseHeaders | RawAxiosResponseHeaders): Record<string, string>;
26
15
  }
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AxiosClient = exports.getV2OrV4ErrorMessage = exports.DEFAULT_ERROR_MESSAGE = void 0;
3
+ exports.AxiosClient = exports.DEFAULT_ERROR_MESSAGE = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const http_client_base_1 = require("@odata2ts/http-client-base");
5
6
  const axios_1 = tslib_1.__importDefault(require("axios"));
6
7
  const AxiosClientError_1 = require("./AxiosClientError");
7
8
  const AxiosRequestConfig_1 = require("./AxiosRequestConfig");
8
9
  exports.DEFAULT_ERROR_MESSAGE = "No error message!";
9
- const FAILURE_MISSING_CSRF_URL = "When automatic CSRF token handling is activated, the URL must be supplied via attribute [csrfTokenFetchUrl]!";
10
10
  const FAILURE_NO_RESPONSE = "No response from server! Failure: ";
11
11
  const FAILURE_NO_REQUEST = "No request was sent! Failure: ";
12
12
  const FAILURE_RESPONSE_MESSAGE = "OData server responded with error: ";
@@ -15,56 +15,21 @@ function buildErrorMessage(prefix, error) {
15
15
  const msg = typeof error === "string" ? error : error === null || error === void 0 ? void 0 : error.message;
16
16
  return prefix + (msg || exports.DEFAULT_ERROR_MESSAGE);
17
17
  }
18
- const getV2OrV4ErrorMessage = (responseData) => {
19
- var _a;
20
- const eMsg = (_a = responseData === null || responseData === void 0 ? void 0 : responseData.error) === null || _a === void 0 ? void 0 : _a.message;
21
- return typeof (eMsg === null || eMsg === void 0 ? void 0 : eMsg.value) === "string" ? eMsg.value : eMsg;
22
- };
23
- exports.getV2OrV4ErrorMessage = getV2OrV4ErrorMessage;
24
- class AxiosClient {
18
+ class AxiosClient extends http_client_base_1.BaseHttpClient {
25
19
  constructor(config, clientOptions) {
26
- var _a;
20
+ super(clientOptions);
27
21
  this.clientOptions = clientOptions;
28
- this.getErrorMessage = exports.getV2OrV4ErrorMessage;
29
22
  this.client = axios_1.default.create((0, AxiosRequestConfig_1.getDefaultConfig)(config));
30
- if (clientOptions && clientOptions.useCsrfProtection && !((_a = clientOptions.csrfTokenFetchUrl) === null || _a === void 0 ? void 0 : _a.trim())) {
31
- throw new Error(FAILURE_MISSING_CSRF_URL);
32
- }
33
23
  }
34
- setErrorMessageRetriever(getErrorMsg) {
35
- this.getErrorMessage = getErrorMsg;
24
+ addHeaderToRequestConfig(headers, config) {
25
+ return (0, AxiosRequestConfig_1.mergeConfig)(config, { headers });
36
26
  }
37
- setupSecurityToken() {
27
+ executeRequest(method, url, data, requestConfig = {}) {
38
28
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
39
- if (!this.csrfToken) {
40
- this.csrfToken = yield this.fetchSecurityToken();
41
- }
42
- return this.csrfToken;
43
- });
44
- }
45
- fetchSecurityToken() {
46
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
47
- const fetchUrl = this.clientOptions.csrfTokenFetchUrl;
48
- const response = yield this.get(fetchUrl, { headers: { "x-csrf-token": "Fetch" } });
49
- return response.headers["x-csrf-token"];
50
- });
51
- }
52
- sendRequest(config) {
53
- var _a, _b, _c;
54
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
55
- if (typeof config.url !== "string") {
56
- throw new Error("Value for URL must be provided!");
57
- }
58
- // setup automatic CSRF token handling
59
- if (((_a = this.clientOptions) === null || _a === void 0 ? void 0 : _a.useCsrfProtection) &&
60
- ["POST", "PUT", "PATCH", "DELETE"].includes(config.method.toUpperCase())) {
61
- const csrfToken = yield this.setupSecurityToken();
62
- if (typeof csrfToken === "string") {
63
- if (!config.headers) {
64
- config.headers = {};
65
- }
66
- config.headers["x-csrf-token"] = csrfToken;
67
- }
29
+ // add URL and HTTP method to the request config
30
+ const config = (0, AxiosRequestConfig_1.mergeConfig)(requestConfig, { url, method });
31
+ if (typeof data !== "undefined") {
32
+ config.data = data;
68
33
  }
69
34
  try {
70
35
  return yield this.client.request(config);
@@ -72,51 +37,24 @@ class AxiosClient {
72
37
  catch (error) {
73
38
  if (error.isAxiosError) {
74
39
  const axiosError = error;
75
- // automatic CSRF token handling
76
- // csrf token expired, let's reset it and perform the original request again
77
- if (((_b = this.clientOptions) === null || _b === void 0 ? void 0 : _b.useCsrfProtection) &&
78
- ((_c = axiosError.response) === null || _c === void 0 ? void 0 : _c.status) === 403 &&
79
- axiosError.response.headers["x-csrf-token"] === "Required") {
80
- this.csrfToken = undefined;
81
- return this.sendRequest(config);
82
- }
83
40
  // regular failure handling
84
41
  if (axiosError.response) {
85
- const msg = buildErrorMessage(FAILURE_RESPONSE_MESSAGE, this.getErrorMessage(axiosError.response.data));
86
- throw new AxiosClientError_1.AxiosClientError(msg, axiosError.response.status, axiosError);
42
+ const errMsg = this.retrieveErrorMessage(axiosError.response.data);
43
+ const msg = buildErrorMessage(FAILURE_RESPONSE_MESSAGE, errMsg);
44
+ throw new AxiosClientError_1.AxiosClientError(msg, axiosError.response.status, this.mapHeaders(axiosError.response.headers), new Error(errMsg || exports.DEFAULT_ERROR_MESSAGE), axiosError);
87
45
  }
88
46
  // fatal failure without response
89
47
  else {
90
- throw new AxiosClientError_1.AxiosClientError(buildErrorMessage(axiosError.request ? FAILURE_NO_RESPONSE : FAILURE_NO_REQUEST, axiosError), undefined, axiosError);
48
+ throw new AxiosClientError_1.AxiosClientError(buildErrorMessage(axiosError.request ? FAILURE_NO_RESPONSE : FAILURE_NO_REQUEST, axiosError), undefined, undefined, error, axiosError);
91
49
  }
92
50
  }
93
51
  // not an Axios error
94
- throw new AxiosClientError_1.AxiosClientError(buildErrorMessage(FAILURE_AXIOS, error), undefined, error);
52
+ throw new AxiosClientError_1.AxiosClientError(buildErrorMessage(FAILURE_AXIOS, error), undefined, undefined, error);
95
53
  }
96
54
  });
97
55
  }
98
- post(url, data, requestConfig) {
99
- return this.sendRequest(Object.assign(Object.assign({}, requestConfig), { url, data, method: "POST" }));
100
- }
101
- get(url, requestConfig) {
102
- return this.sendRequest(Object.assign(Object.assign({}, requestConfig), { url, method: "GET" }));
103
- }
104
- put(url, data, requestConfig) {
105
- return this.sendRequest(Object.assign(Object.assign({}, requestConfig), { url, data, method: "PUT" }));
106
- }
107
- patch(url, data, requestConfig) {
108
- return this.sendRequest(Object.assign(Object.assign({}, requestConfig), { url, data, method: "PATCH" }));
109
- }
110
- merge(url, data, requestConfig) {
111
- return this.sendRequest((0, AxiosRequestConfig_1.mergeConfig)(requestConfig, {
112
- url,
113
- method: "POST",
114
- headers: { "X-Http-Method": "MERGE" },
115
- data,
116
- }));
117
- }
118
- delete(url, requestConfig) {
119
- return this.sendRequest(Object.assign(Object.assign({}, requestConfig), { url, method: "DELETE" }));
56
+ mapHeaders(headers) {
57
+ return headers;
120
58
  }
121
59
  }
122
60
  exports.AxiosClient = AxiosClient;
@@ -1 +1 @@
1
- {"version":3,"file":"AxiosClient.js","sourceRoot":"","sources":["../src/AxiosClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpResponseModel, ODataHttpClient } from \"@odata2ts/http-client-api\";\nimport axios, { AxiosError, AxiosInstance, AxiosRequestConfig as OriginalRequestConfig } from \"axios\";\n\nimport { AxiosClientError } from \"./AxiosClientError\";\nimport { AxiosRequestConfig, InternalRequestConfig, getDefaultConfig, mergeConfig } from \"./AxiosRequestConfig\";\n\nexport type ErrorMessageRetriever<ResponseType = any> = (error: any) => string | null | undefined;\n\nexport interface ClientOptions {\n useCsrfProtection?: boolean;\n csrfTokenFetchUrl?: string;\n}\n\nexport const DEFAULT_ERROR_MESSAGE = \"No error message!\";\nconst FAILURE_MISSING_CSRF_URL =\n \"When automatic CSRF token handling is activated, the URL must be supplied via attribute [csrfTokenFetchUrl]!\";\nconst FAILURE_NO_RESPONSE = \"No response from server! Failure: \";\nconst FAILURE_NO_REQUEST = \"No request was sent! Failure: \";\nconst FAILURE_RESPONSE_MESSAGE = \"OData server responded with error: \";\nconst FAILURE_AXIOS = \"Fatal Axios failure: \";\n\nfunction buildErrorMessage(prefix: string, error: any) {\n const msg = typeof error === \"string\" ? error : (error as Error)?.message;\n return prefix + (msg || DEFAULT_ERROR_MESSAGE);\n}\n\nexport const getV2OrV4ErrorMessage: ErrorMessageRetriever = (responseData: any): string | undefined => {\n const eMsg = responseData?.error?.message;\n return typeof eMsg?.value === \"string\" ? eMsg.value : eMsg;\n};\n\nexport class AxiosClient implements ODataHttpClient<AxiosRequestConfig> {\n private readonly client: AxiosInstance;\n private csrfToken: string | undefined;\n private getErrorMessage: ErrorMessageRetriever = getV2OrV4ErrorMessage;\n\n constructor(config?: AxiosRequestConfig, private clientOptions?: ClientOptions) {\n this.client = axios.create(getDefaultConfig(config));\n\n if (clientOptions && clientOptions.useCsrfProtection && !clientOptions.csrfTokenFetchUrl?.trim()) {\n throw new Error(FAILURE_MISSING_CSRF_URL);\n }\n }\n\n public setErrorMessageRetriever<T = any>(getErrorMsg: ErrorMessageRetriever<T>) {\n this.getErrorMessage = getErrorMsg;\n }\n\n private async setupSecurityToken() {\n if (!this.csrfToken) {\n this.csrfToken = await this.fetchSecurityToken();\n }\n return this.csrfToken;\n }\n\n private async fetchSecurityToken(): Promise<string | undefined> {\n const fetchUrl = this.clientOptions!.csrfTokenFetchUrl!;\n const response = await this.get(fetchUrl, { headers: { \"x-csrf-token\": \"Fetch\" } });\n\n return response.headers[\"x-csrf-token\"];\n }\n\n private async sendRequest<ResponseType>(config: InternalRequestConfig): Promise<HttpResponseModel<ResponseType>> {\n if (typeof config.url !== \"string\") {\n throw new Error(\"Value for URL must be provided!\");\n }\n\n // setup automatic CSRF token handling\n if (\n this.clientOptions?.useCsrfProtection &&\n [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"].includes(config.method!.toUpperCase())\n ) {\n const csrfToken = await this.setupSecurityToken();\n if (typeof csrfToken === \"string\") {\n if (!config.headers) {\n config.headers = {};\n }\n config.headers![\"x-csrf-token\"] = csrfToken;\n }\n }\n\n try {\n return await this.client.request(config as OriginalRequestConfig);\n } catch (error: any) {\n if ((error as AxiosError).isAxiosError) {\n const axiosError = error as AxiosError;\n\n // automatic CSRF token handling\n // csrf token expired, let's reset it and perform the original request again\n if (\n this.clientOptions?.useCsrfProtection &&\n axiosError.response?.status === 403 &&\n axiosError.response.headers[\"x-csrf-token\"] === \"Required\"\n ) {\n this.csrfToken = undefined;\n return this.sendRequest<ResponseType>(config);\n }\n\n // regular failure handling\n if (axiosError.response) {\n const msg = buildErrorMessage(FAILURE_RESPONSE_MESSAGE, this.getErrorMessage(axiosError.response.data));\n throw new AxiosClientError(msg, axiosError.response.status, axiosError);\n }\n // fatal failure without response\n else {\n throw new AxiosClientError(\n buildErrorMessage(axiosError.request ? FAILURE_NO_RESPONSE : FAILURE_NO_REQUEST, axiosError),\n undefined,\n axiosError\n );\n }\n }\n // not an Axios error\n throw new AxiosClientError(buildErrorMessage(FAILURE_AXIOS, error), undefined, error);\n }\n }\n\n public post<ResponseModel>(\n url: string,\n data: any,\n requestConfig?: AxiosRequestConfig\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest({ ...requestConfig, url, data, method: \"POST\" });\n }\n public get<ResponseModel>(\n url: string,\n requestConfig?: AxiosRequestConfig\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest({ ...requestConfig, url, method: \"GET\" });\n }\n public put<ResponseModel>(\n url: string,\n data: any,\n requestConfig?: AxiosRequestConfig\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest({ ...requestConfig, url, data, method: \"PUT\" });\n }\n public patch<ResponseModel>(\n url: string,\n data: any,\n requestConfig?: AxiosRequestConfig\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest({ ...requestConfig, url, data, method: \"PATCH\" });\n }\n public merge<ResponseModel>(\n url: string,\n data: any,\n requestConfig?: AxiosRequestConfig\n ): Promise<HttpResponseModel<ResponseModel>> {\n return this.sendRequest(\n mergeConfig(requestConfig, {\n url,\n method: \"POST\",\n headers: { \"X-Http-Method\": \"MERGE\" },\n data,\n })\n );\n }\n public delete(url: string, requestConfig?: AxiosRequestConfig): Promise<HttpResponseModel<void>> {\n return this.sendRequest({ ...requestConfig, url, method: \"DELETE\" });\n }\n}\n"]}
1
+ {"version":3,"file":"AxiosClient.js","sourceRoot":"","sources":["../src/AxiosClient.ts"],"names":[],"mappings":";;;;AACA,iEAAgG;AAChG,0DAMe;AAEf,yDAAsD;AACtD,6DAAyF;AAI5E,QAAA,qBAAqB,GAAG,mBAAmB,CAAC;AACzD,MAAM,mBAAmB,GAAG,oCAAoC,CAAC;AACjE,MAAM,kBAAkB,GAAG,gCAAgC,CAAC;AAC5D,MAAM,wBAAwB,GAAG,qCAAqC,CAAC;AACvE,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAE9C,SAAS,iBAAiB,CAAC,MAAc,EAAE,KAAU;IACnD,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,KAAe,aAAf,KAAK,uBAAL,KAAK,CAAY,OAAO,CAAC;IAC1E,OAAO,MAAM,GAAG,CAAC,GAAG,IAAI,6BAAqB,CAAC,CAAC;AACjD,CAAC;AAED,MAAa,WAAY,SAAQ,iCAAkC;IAGjE,YAAY,MAA2B,EAAU,aAA6B;QAC5E,KAAK,CAAC,aAAa,CAAC,CAAC;QAD0B,kBAAa,GAAb,aAAa,CAAgB;QAE5E,IAAI,CAAC,MAAM,GAAG,eAAK,CAAC,MAAM,CAAC,IAAA,qCAAgB,EAAC,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IAES,wBAAwB,CAChC,OAA+B,EAC/B,MAAsC;QAEtC,OAAO,IAAA,gCAAW,EAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1C,CAAC;IAEe,cAAc,CAC5B,MAAmB,EACnB,GAAW,EACX,IAAS,EACT,gBAAgD,EAAE;;YAElD,gDAAgD;YAChD,MAAM,MAAM,GAA0B,IAAA,gCAAW,EAAC,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YAClF,IAAI,OAAO,IAAI,KAAK,WAAW,EAAE;gBAC/B,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;aACpB;YAED,IAAI;gBACF,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;aAC1C;YAAC,OAAO,KAAU,EAAE;gBACnB,IAAK,KAAoB,CAAC,YAAY,EAAE;oBACtC,MAAM,UAAU,GAAG,KAAmB,CAAC;oBAEvC,2BAA2B;oBAC3B,IAAI,UAAU,CAAC,QAAQ,EAAE;wBACvB,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;wBACnE,MAAM,GAAG,GAAG,iBAAiB,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;wBAChE,MAAM,IAAI,mCAAgB,CACxB,GAAG,EACH,UAAU,CAAC,QAAQ,CAAC,MAAM,EAC1B,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC5C,IAAI,KAAK,CAAC,MAAM,IAAI,6BAAqB,CAAC,EAC1C,UAAU,CACX,CAAC;qBACH;oBACD,iCAAiC;yBAC5B;wBACH,MAAM,IAAI,mCAAgB,CACxB,iBAAiB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,kBAAkB,EAAE,UAAU,CAAC,EAC5F,SAAS,EACT,SAAS,EACT,KAAK,EACL,UAAU,CACX,CAAC;qBACH;iBACF;gBACD,qBAAqB;gBACrB,MAAM,IAAI,mCAAgB,CAAC,iBAAiB,CAAC,aAAa,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;aAClG;QACH,CAAC;KAAA;IAES,UAAU,CAAC,OAAuD;QAC1E,OAAO,OAAiC,CAAC;IAC3C,CAAC;CACF;AAhED,kCAgEC","sourcesContent":["import { HttpResponseModel } from \"@odata2ts/http-client-api\";\r\nimport { BaseHttpClient, BaseHttpClientOptions, HttpMethods } from \"@odata2ts/http-client-base\";\r\nimport axios, {\r\n AxiosError,\r\n AxiosInstance,\r\n AxiosResponseHeaders,\r\n AxiosRequestConfig as OriginalRequestConfig,\r\n RawAxiosResponseHeaders,\r\n} from \"axios\";\r\n\r\nimport { AxiosClientError } from \"./AxiosClientError\";\r\nimport { AxiosRequestConfig, getDefaultConfig, mergeConfig } from \"./AxiosRequestConfig\";\r\n\r\nexport interface ClientOptions extends BaseHttpClientOptions {}\r\n\r\nexport const DEFAULT_ERROR_MESSAGE = \"No error message!\";\r\nconst FAILURE_NO_RESPONSE = \"No response from server! Failure: \";\r\nconst FAILURE_NO_REQUEST = \"No request was sent! Failure: \";\r\nconst FAILURE_RESPONSE_MESSAGE = \"OData server responded with error: \";\r\nconst FAILURE_AXIOS = \"Fatal Axios failure: \";\r\n\r\nfunction buildErrorMessage(prefix: string, error: any) {\r\n const msg = typeof error === \"string\" ? error : (error as Error)?.message;\r\n return prefix + (msg || DEFAULT_ERROR_MESSAGE);\r\n}\r\n\r\nexport class AxiosClient extends BaseHttpClient<AxiosRequestConfig> {\r\n protected readonly client: AxiosInstance;\r\n\r\n constructor(config?: AxiosRequestConfig, private clientOptions?: ClientOptions) {\r\n super(clientOptions);\r\n this.client = axios.create(getDefaultConfig(config));\r\n }\r\n\r\n protected addHeaderToRequestConfig(\r\n headers: Record<string, string>,\r\n config: AxiosRequestConfig | undefined\r\n ): AxiosRequestConfig {\r\n return mergeConfig(config, { headers });\r\n }\r\n\r\n protected async executeRequest<ResponseModel>(\r\n method: HttpMethods,\r\n url: string,\r\n data: any,\r\n requestConfig: AxiosRequestConfig | undefined = {}\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n // add URL and HTTP method to the request config\r\n const config: OriginalRequestConfig = mergeConfig(requestConfig, { url, method });\r\n if (typeof data !== \"undefined\") {\r\n config.data = data;\r\n }\r\n\r\n try {\r\n return await this.client.request(config);\r\n } catch (error: any) {\r\n if ((error as AxiosError).isAxiosError) {\r\n const axiosError = error as AxiosError;\r\n\r\n // regular failure handling\r\n if (axiosError.response) {\r\n const errMsg = this.retrieveErrorMessage(axiosError.response.data);\r\n const msg = buildErrorMessage(FAILURE_RESPONSE_MESSAGE, errMsg);\r\n throw new AxiosClientError(\r\n msg,\r\n axiosError.response.status,\r\n this.mapHeaders(axiosError.response.headers),\r\n new Error(errMsg || DEFAULT_ERROR_MESSAGE),\r\n axiosError\r\n );\r\n }\r\n // fatal failure without response\r\n else {\r\n throw new AxiosClientError(\r\n buildErrorMessage(axiosError.request ? FAILURE_NO_RESPONSE : FAILURE_NO_REQUEST, axiosError),\r\n undefined,\r\n undefined,\r\n error,\r\n axiosError\r\n );\r\n }\r\n }\r\n // not an Axios error\r\n throw new AxiosClientError(buildErrorMessage(FAILURE_AXIOS, error), undefined, undefined, error);\r\n }\r\n }\r\n\r\n protected mapHeaders(headers: AxiosResponseHeaders | RawAxiosResponseHeaders): Record<string, string> {\r\n return headers as Record<string, string>;\r\n }\r\n}\r\n"]}
@@ -1,6 +1,9 @@
1
+ import { ODataClientError } from "@odata2ts/http-client-api";
1
2
  import type { AxiosError } from "axios";
2
- export declare class AxiosClientError extends Error {
3
- readonly status: number | undefined;
4
- readonly cause: Error | AxiosError | undefined;
5
- constructor(msg: string, status: number | undefined, cause: Error | AxiosError | undefined);
3
+ export declare class AxiosClientError extends Error implements ODataClientError {
4
+ readonly status?: number | undefined;
5
+ readonly headers?: Record<string, string> | undefined;
6
+ readonly cause?: Error | undefined;
7
+ readonly axiosError?: AxiosError<unknown, any> | undefined;
8
+ constructor(msg: string, status?: number | undefined, headers?: Record<string, string> | undefined, cause?: Error | undefined, axiosError?: AxiosError<unknown, any> | undefined);
6
9
  }
@@ -2,10 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AxiosClientError = void 0;
4
4
  class AxiosClientError extends Error {
5
- constructor(msg, status, cause) {
5
+ constructor(msg, status, headers, cause, axiosError) {
6
+ // @ts-ignore: fetch requires lib "dom" or "webworker", but then the "cause" property becomes unknown to TS
6
7
  super(msg, { cause });
7
8
  this.status = status;
9
+ this.headers = headers;
8
10
  this.cause = cause;
11
+ this.axiosError = axiosError;
9
12
  this.name = this.constructor.name;
10
13
  }
11
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AxiosClientError.js","sourceRoot":"","sources":["../src/AxiosClientError.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAiB,SAAQ,KAAK;IACzC,YACE,GAAW,EACK,MAA0B,EAC1B,KAAqC;QAErD,KAAK,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAHN,WAAM,GAAN,MAAM,CAAoB;QAC1B,UAAK,GAAL,KAAK,CAAgC;QAGrD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IACpC,CAAC;CACF;AATD,4CASC","sourcesContent":["import type { AxiosError } from \"axios\";\n\nexport class AxiosClientError extends Error {\n constructor(\n msg: string,\n public readonly status: number | undefined,\n public readonly cause: Error | AxiosError | undefined\n ) {\n super(msg, { cause });\n this.name = this.constructor.name;\n }\n}\n"]}
1
+ {"version":3,"file":"AxiosClientError.js","sourceRoot":"","sources":["../src/AxiosClientError.ts"],"names":[],"mappings":";;;AAGA,MAAa,gBAAiB,SAAQ,KAAK;IACzC,YACE,GAAW,EACK,MAAe,EACf,OAAgC,EAChC,KAAa,EACb,UAAuB;QAEvC,2GAA2G;QAC3G,KAAK,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QANN,WAAM,GAAN,MAAM,CAAS;QACf,YAAO,GAAP,OAAO,CAAyB;QAChC,UAAK,GAAL,KAAK,CAAQ;QACb,eAAU,GAAV,UAAU,CAAa;QAIvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IACpC,CAAC;CACF;AAZD,4CAYC","sourcesContent":["import { ODataClientError } from \"@odata2ts/http-client-api\";\r\nimport type { AxiosError } from \"axios\";\r\n\r\nexport class AxiosClientError extends Error implements ODataClientError {\r\n constructor(\r\n msg: string,\r\n public readonly status?: number,\r\n public readonly headers?: Record<string, string>,\r\n public readonly cause?: Error,\r\n public readonly axiosError?: AxiosError\r\n ) {\r\n // @ts-ignore: fetch requires lib \"dom\" or \"webworker\", but then the \"cause\" property becomes unknown to TS\r\n super(msg, { cause });\r\n this.name = this.constructor.name;\r\n }\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@odata2ts/http-client-axios",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,7 +34,7 @@
34
34
  "axios": "^0.27.0 || ^1.0.0"
35
35
  },
36
36
  "dependencies": {
37
- "@odata2ts/http-client-api": "^0.1.0"
37
+ "@odata2ts/http-client-base": "^0.2.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/jest": "^27.4.1",
@@ -47,5 +47,5 @@
47
47
  "typescript": "5.0.4"
48
48
  },
49
49
  "types": "./lib/index.d.ts",
50
- "gitHead": "a93b726286ef9a118fda63b0e7900d6b3e739dd2"
50
+ "gitHead": "9babd2df3010673249e7e3fa26705a8ba84f2cef"
51
51
  }