@odata2ts/http-client-base 0.4.1 → 0.4.2
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 +4 -0
- package/lib/BaseHttpClient.d.ts +12 -2
- package/lib/BaseHttpClient.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
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.4.2](https://github.com/odata2ts/http-client/compare/@odata2ts/http-client-base@0.4.1...@odata2ts/http-client-base@0.4.2) (2023-09-13)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @odata2ts/http-client-base
|
|
9
|
+
|
|
6
10
|
## [0.4.1](https://github.com/odata2ts/http-client/compare/@odata2ts/http-client-base@0.4.0...@odata2ts/http-client-base@0.4.1) (2023-09-13)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @odata2ts/http-client-base
|
package/lib/BaseHttpClient.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HttpResponseModel
|
|
1
|
+
import { HttpResponseModel } from "@odata2ts/http-client-api";
|
|
2
2
|
import { ErrorMessageRetriever } from "./ErrorMessageRetriever";
|
|
3
3
|
import { HttpMethods } from "./HttpMethods";
|
|
4
4
|
export interface BaseHttpClientOptions {
|
|
@@ -13,8 +13,18 @@ export interface BaseHttpClientOptions {
|
|
|
13
13
|
*/
|
|
14
14
|
csrfTokenFetchUrl?: string;
|
|
15
15
|
}
|
|
16
|
+
export interface InternalHttpClientConfig {
|
|
17
|
+
/**
|
|
18
|
+
* Additional headers set internally by services or HttpClient implementation.
|
|
19
|
+
*/
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* Very special option needed for FetchClient to not evaluate the response body in certain situations.
|
|
23
|
+
*/
|
|
24
|
+
noBodyEvaluation?: boolean;
|
|
25
|
+
}
|
|
16
26
|
export declare const DEFAULT_CSRF_TOKEN_KEY = "x-csrf-token";
|
|
17
|
-
export declare abstract class BaseHttpClient<RequestConfigType>
|
|
27
|
+
export declare abstract class BaseHttpClient<RequestConfigType> {
|
|
18
28
|
private baseOptions;
|
|
19
29
|
private csrfToken;
|
|
20
30
|
private csrfTokenKey;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseHttpClient.js","sourceRoot":"","sources":["../src/BaseHttpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n HttpResponseModel,\r\n InternalHttpClientConfig,\r\n ODataClientError,\r\n ODataHttpClient,\r\n} from \"@odata2ts/http-client-api\";\r\n\r\nimport { ErrorMessageRetriever, retrieveErrorMessage } from \"./ErrorMessageRetriever\";\r\nimport { HttpMethods } from \"./HttpMethods\";\r\n\r\nexport interface BaseHttpClientOptions {\r\n /**\r\n * Enable automatic CSRF token handling.\r\n */\r\n useCsrfProtection?: boolean;\r\n /**\r\n * Specify the URL from which the token is fetched.\r\n * This could be any path to your OData service, since the token is exchanged via HTTP request headers.\r\n * However, it should be a fast response and usually the root URL to the OData service is a good choice.\r\n */\r\n csrfTokenFetchUrl?: string;\r\n}\r\n\r\nexport const DEFAULT_CSRF_TOKEN_KEY = \"x-csrf-token\";\r\n\r\nconst EDIT_METHODS = [HttpMethods.Post, HttpMethods.Put, HttpMethods.Patch, HttpMethods.Delete];\r\nconst FAILURE_MISSING_CSRF_URL =\r\n \"When automatic CSRF token handling is activated, the URL must be supplied via attribute [csrfTokenFetchUrl]!\";\r\nconst FAILURE_MISSING_URL = \"Value for URL must be provided!\";\r\nconst JSON_VALUE = \"application/json\";\r\n\r\nfunction getInternalConfig(headers?: Record<string, string>, setContentType: boolean = true) {\r\n return {\r\n headers: {\r\n Accept: JSON_VALUE,\r\n ...(setContentType ? { \"Content-Type\": JSON_VALUE } : undefined),\r\n ...headers,\r\n },\r\n };\r\n}\r\n\r\nexport abstract class BaseHttpClient<RequestConfigType> implements ODataHttpClient<RequestConfigType> {\r\n private csrfToken: string | undefined;\r\n private csrfTokenKey = DEFAULT_CSRF_TOKEN_KEY;\r\n\r\n protected retrieveErrorMessage: ErrorMessageRetriever = retrieveErrorMessage;\r\n\r\n protected constructor(private baseOptions: BaseHttpClientOptions = { useCsrfProtection: false }) {\r\n if (baseOptions.useCsrfProtection && !baseOptions.csrfTokenFetchUrl?.trim()) {\r\n throw new Error(FAILURE_MISSING_CSRF_URL);\r\n }\r\n }\r\n\r\n /**\r\n * Main function to implement by any extending http client.\r\n * As it name suggests, the request gets executed in this method.\r\n * Additionally, failures should be handled and errors of type <code>HttpClientError</code> should be thrown.\r\n *\r\n * @param method\r\n * @param url\r\n * @param data\r\n * @param config\r\n * @param internalConfig\r\n */\r\n protected abstract executeRequest<ResponseModel>(\r\n method: HttpMethods,\r\n url: string,\r\n data: any,\r\n config?: RequestConfigType,\r\n internalConfig?: InternalHttpClientConfig\r\n ): Promise<HttpResponseModel<ResponseModel>>;\r\n\r\n public getCsrfTokenKey() {\r\n return this.csrfTokenKey;\r\n }\r\n\r\n public setCsrfTokenKey(newKey: string) {\r\n this.csrfTokenKey = newKey || DEFAULT_CSRF_TOKEN_KEY;\r\n }\r\n\r\n public setErrorMessageRetriever(getErrorMsg: ErrorMessageRetriever) {\r\n this.retrieveErrorMessage = getErrorMsg;\r\n }\r\n\r\n protected async setupSecurityToken(): Promise<[string, string | undefined]> {\r\n if (!this.csrfToken) {\r\n this.csrfToken = await this.fetchSecurityToken();\r\n }\r\n return [this.csrfTokenKey, this.csrfToken];\r\n }\r\n\r\n protected async fetchSecurityToken(): Promise<string | undefined> {\r\n const fetchUrl = this.baseOptions!.csrfTokenFetchUrl!;\r\n const response = await this.sendRequest(HttpMethods.Get, fetchUrl, undefined, undefined, {\r\n noBodyEvaluation: true,\r\n headers: { [this.csrfTokenKey]: \"Fetch\", Accept: JSON_VALUE },\r\n });\r\n\r\n return response.headers[this.csrfTokenKey];\r\n }\r\n\r\n /**\r\n * Follows the template pattern.\r\n *\r\n * @param method\r\n * @param url\r\n * @param data\r\n * @param requestConfig\r\n * @param internalConfig\r\n * @private\r\n */\r\n private async sendRequest<ResponseModel>(\r\n method: HttpMethods,\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n internalConfig: InternalHttpClientConfig = {}\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n // noinspection SuspiciousTypeOfGuard\r\n if (typeof url !== \"string\") {\r\n throw new Error(FAILURE_MISSING_URL);\r\n }\r\n\r\n // setup automatic CSRF token handling\r\n if (this.baseOptions.useCsrfProtection && EDIT_METHODS.includes(method)) {\r\n const [tokenKey, tokenValue] = await this.setupSecurityToken();\r\n if (tokenValue) {\r\n if (!internalConfig.headers) {\r\n internalConfig.headers = {};\r\n }\r\n internalConfig.headers[tokenKey] = tokenValue;\r\n }\r\n }\r\n\r\n try {\r\n return await this.executeRequest<ResponseModel>(method, url, data, requestConfig, internalConfig);\r\n } catch (e) {\r\n const clientError = e as ODataClientError;\r\n\r\n // automatic CSRF token handling\r\n if (\r\n !!this.baseOptions.useCsrfProtection &&\r\n clientError.status === 403 &&\r\n !!clientError.headers &&\r\n clientError.headers[\"x-csrf-token\"] === \"Required\"\r\n ) {\r\n // token has expired: reset csrf token & perform the original request again\r\n this.csrfToken = undefined;\r\n return this.sendRequest<ResponseModel>(method, url, data, requestConfig);\r\n }\r\n\r\n throw e;\r\n }\r\n }\r\n\r\n public get<ResponseModel>(\r\n url: string,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Get,\r\n url,\r\n undefined,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders, false)\r\n );\r\n }\r\n\r\n public post<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Post,\r\n url,\r\n data,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders)\r\n );\r\n }\r\n\r\n public put<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Put,\r\n url,\r\n data,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders)\r\n );\r\n }\r\n\r\n public patch<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Patch,\r\n url,\r\n data,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders)\r\n );\r\n }\r\n\r\n public delete(\r\n url: string,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<void>> {\r\n return this.sendRequest<void>(HttpMethods.Delete, url, undefined, requestConfig, { headers: additionalHeaders });\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"BaseHttpClient.js","sourceRoot":"","sources":["../src/BaseHttpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpResponseModel, ODataClientError } from \"@odata2ts/http-client-api\";\r\n\r\nimport { ErrorMessageRetriever, retrieveErrorMessage } from \"./ErrorMessageRetriever\";\r\nimport { HttpMethods } from \"./HttpMethods\";\r\n\r\nexport interface BaseHttpClientOptions {\r\n /**\r\n * Enable automatic CSRF token handling.\r\n */\r\n useCsrfProtection?: boolean;\r\n /**\r\n * Specify the URL from which the token is fetched.\r\n * This could be any path to your OData service, since the token is exchanged via HTTP request headers.\r\n * However, it should be a fast response and usually the root URL to the OData service is a good choice.\r\n */\r\n csrfTokenFetchUrl?: string;\r\n}\r\n\r\nexport interface InternalHttpClientConfig {\r\n /**\r\n * Additional headers set internally by services or HttpClient implementation.\r\n */\r\n headers?: Record<string, string>;\r\n /**\r\n * Very special option needed for FetchClient to not evaluate the response body in certain situations.\r\n */\r\n noBodyEvaluation?: boolean;\r\n}\r\n\r\nexport const DEFAULT_CSRF_TOKEN_KEY = \"x-csrf-token\";\r\n\r\nconst EDIT_METHODS = [HttpMethods.Post, HttpMethods.Put, HttpMethods.Patch, HttpMethods.Delete];\r\nconst FAILURE_MISSING_CSRF_URL =\r\n \"When automatic CSRF token handling is activated, the URL must be supplied via attribute [csrfTokenFetchUrl]!\";\r\nconst FAILURE_MISSING_URL = \"Value for URL must be provided!\";\r\nconst JSON_VALUE = \"application/json\";\r\n\r\nfunction getInternalConfig(headers?: Record<string, string>, setContentType: boolean = true) {\r\n return {\r\n headers: {\r\n Accept: JSON_VALUE,\r\n ...(setContentType ? { \"Content-Type\": JSON_VALUE } : undefined),\r\n ...headers,\r\n },\r\n };\r\n}\r\n\r\nexport abstract class BaseHttpClient<RequestConfigType> {\r\n private csrfToken: string | undefined;\r\n private csrfTokenKey = DEFAULT_CSRF_TOKEN_KEY;\r\n\r\n protected retrieveErrorMessage: ErrorMessageRetriever = retrieveErrorMessage;\r\n\r\n protected constructor(private baseOptions: BaseHttpClientOptions = { useCsrfProtection: false }) {\r\n if (baseOptions.useCsrfProtection && !baseOptions.csrfTokenFetchUrl?.trim()) {\r\n throw new Error(FAILURE_MISSING_CSRF_URL);\r\n }\r\n }\r\n\r\n /**\r\n * Main function to implement by any extending http client.\r\n * As it name suggests, the request gets executed in this method.\r\n * Additionally, failures should be handled and errors of type <code>HttpClientError</code> should be thrown.\r\n *\r\n * @param method\r\n * @param url\r\n * @param data\r\n * @param config\r\n * @param internalConfig\r\n */\r\n protected abstract executeRequest<ResponseModel>(\r\n method: HttpMethods,\r\n url: string,\r\n data: any,\r\n config?: RequestConfigType,\r\n internalConfig?: InternalHttpClientConfig\r\n ): Promise<HttpResponseModel<ResponseModel>>;\r\n\r\n public getCsrfTokenKey() {\r\n return this.csrfTokenKey;\r\n }\r\n\r\n public setCsrfTokenKey(newKey: string) {\r\n this.csrfTokenKey = newKey || DEFAULT_CSRF_TOKEN_KEY;\r\n }\r\n\r\n public setErrorMessageRetriever(getErrorMsg: ErrorMessageRetriever) {\r\n this.retrieveErrorMessage = getErrorMsg;\r\n }\r\n\r\n protected async setupSecurityToken(): Promise<[string, string | undefined]> {\r\n if (!this.csrfToken) {\r\n this.csrfToken = await this.fetchSecurityToken();\r\n }\r\n return [this.csrfTokenKey, this.csrfToken];\r\n }\r\n\r\n protected async fetchSecurityToken(): Promise<string | undefined> {\r\n const fetchUrl = this.baseOptions!.csrfTokenFetchUrl!;\r\n const response = await this.sendRequest(HttpMethods.Get, fetchUrl, undefined, undefined, {\r\n noBodyEvaluation: true,\r\n headers: { [this.csrfTokenKey]: \"Fetch\", Accept: JSON_VALUE },\r\n });\r\n\r\n return response.headers[this.csrfTokenKey];\r\n }\r\n\r\n /**\r\n * Follows the template pattern.\r\n *\r\n * @param method\r\n * @param url\r\n * @param data\r\n * @param requestConfig\r\n * @param internalConfig\r\n * @private\r\n */\r\n private async sendRequest<ResponseModel>(\r\n method: HttpMethods,\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n internalConfig: InternalHttpClientConfig = {}\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n // noinspection SuspiciousTypeOfGuard\r\n if (typeof url !== \"string\") {\r\n throw new Error(FAILURE_MISSING_URL);\r\n }\r\n\r\n // setup automatic CSRF token handling\r\n if (this.baseOptions.useCsrfProtection && EDIT_METHODS.includes(method)) {\r\n const [tokenKey, tokenValue] = await this.setupSecurityToken();\r\n if (tokenValue) {\r\n if (!internalConfig.headers) {\r\n internalConfig.headers = {};\r\n }\r\n internalConfig.headers[tokenKey] = tokenValue;\r\n }\r\n }\r\n\r\n try {\r\n return await this.executeRequest<ResponseModel>(method, url, data, requestConfig, internalConfig);\r\n } catch (e) {\r\n const clientError = e as ODataClientError;\r\n\r\n // automatic CSRF token handling\r\n if (\r\n !!this.baseOptions.useCsrfProtection &&\r\n clientError.status === 403 &&\r\n !!clientError.headers &&\r\n clientError.headers[\"x-csrf-token\"] === \"Required\"\r\n ) {\r\n // token has expired: reset csrf token & perform the original request again\r\n this.csrfToken = undefined;\r\n return this.sendRequest<ResponseModel>(method, url, data, requestConfig);\r\n }\r\n\r\n throw e;\r\n }\r\n }\r\n\r\n public get<ResponseModel>(\r\n url: string,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Get,\r\n url,\r\n undefined,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders, false)\r\n );\r\n }\r\n\r\n public post<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Post,\r\n url,\r\n data,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders)\r\n );\r\n }\r\n\r\n public put<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Put,\r\n url,\r\n data,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders)\r\n );\r\n }\r\n\r\n public patch<ResponseModel>(\r\n url: string,\r\n data: any,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<ResponseModel>> {\r\n return this.sendRequest<ResponseModel>(\r\n HttpMethods.Patch,\r\n url,\r\n data,\r\n requestConfig,\r\n getInternalConfig(additionalHeaders)\r\n );\r\n }\r\n\r\n public delete(\r\n url: string,\r\n requestConfig?: RequestConfigType,\r\n additionalHeaders?: Record<string, string>\r\n ): Promise<HttpResponseModel<void>> {\r\n return this.sendRequest<void>(HttpMethods.Delete, url, undefined, requestConfig, { headers: additionalHeaders });\r\n }\r\n}\r\n"]}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,kEAAwC;AACxC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,kEAAwC;AACxC,mDAAmG;AAA1F,gHAAA,cAAc,OAAA;AACvB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA","sourcesContent":["export * from \"./ErrorMessageRetriever\";\r\nexport { BaseHttpClient, BaseHttpClientOptions, InternalHttpClientConfig } from \"./BaseHttpClient\";\r\nexport { HttpMethods } from \"./HttpMethods\";\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odata2ts/http-client-base",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"odata2ts"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@odata2ts/http-client-api": "^0.5.
|
|
32
|
+
"@odata2ts/http-client-api": "^0.5.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@odata2ts/odata-core": "^0.3.7",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"typescript": "5.0.4"
|
|
43
43
|
},
|
|
44
44
|
"types": "./lib/index.d.ts",
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "0886c9e292a84560001d4c4e4503babf3809e1d7"
|
|
46
46
|
}
|