diff --git a/docs/diagrams/architecture/http.md b/docs/diagrams/architecture/http.md index 29a76b0b6..7cca9dbe4 100644 --- a/docs/diagrams/architecture/http.md +++ b/docs/diagrams/architecture/http.md @@ -1,9 +1,5 @@ ```mermaid classDiagram - class SimpleHttpClient { - number DEFAULT_TIMEOUT$ - number timeout; - } class HttpClient { <> string baseUrl @@ -23,6 +19,11 @@ classDiagram Record~string, string~ query validateResponse(Record~string, string~ headers) } + class SimpleHttpClient { + number DEFAULT_TIMEOUT$ + HeadersInit headers + number timeout + } HttpMethod o-- HttpClient HttpParams *-- HttpClient HttpClient <|.. SimpleHttpClient diff --git a/packages/network/src/http/SimpleHttpClient.ts b/packages/network/src/http/SimpleHttpClient.ts index b8e8e0cbe..93009263d 100644 --- a/packages/network/src/http/SimpleHttpClient.ts +++ b/packages/network/src/http/SimpleHttpClient.ts @@ -20,6 +20,8 @@ class SimpleHttpClient implements HttpClient { */ public readonly baseURL: string; + public readonly headers: HeadersInit; + /** * Return the amount of time in milliseconds before a timeout occurs * when requesting with HTTP methods. @@ -27,24 +29,32 @@ class SimpleHttpClient implements HttpClient { public readonly timeout: number; /** - * Constructs an instance of SimpleHttpClient with the given base URL and timeout period. + * Constructs an instance of SimpleHttpClient with the given base URL, + * timeout period and HTTP headers. + * The HTTP headers are used each time this client send a request to the URL, + * if not overwritten by the {@link HttpParams} of the method sending the request. * - * @param {string} baseURL - The base URL for the HTTP client. - * @param {number} [timeout=SimpleHttpClient.DEFAULT_TIMEOUT] - The timeout period for requests in milliseconds. + * @param {string} baseURL - The base URL for HTTP requests. + * @param {HeadersInit} [headers=new Headers()] - The default headers for HTTP requests. + * @param {number} [timeout=SimpleHttpClient.DEFAULT_TIMEOUT] - The timeout duration in milliseconds. */ constructor( baseURL: string, + headers: HeadersInit = new Headers(), timeout: number = SimpleHttpClient.DEFAULT_TIMEOUT ) { this.baseURL = baseURL; this.timeout = timeout; + this.headers = headers; } /** * Sends an HTTP GET request to the specified path with optional query parameters. * * @param {string} path - The endpoint path to which the HTTP GET request is sent. - * @param {HttpParams} [params] - Optional query parameters to include in the request. + * @param {HttpParams} [params] - Optional parameters for the request, + * including query parameters, headers, body, and response validation. + * {@link HttpParams.headers} override {@link SimpleHttpClient.headers}. * @return {Promise} A promise that resolves with the response of the GET request. */ public async get(path: string, params?: HttpParams): Promise { @@ -56,7 +66,9 @@ class SimpleHttpClient implements HttpClient { * * @param {HttpMethod} method - The HTTP method to use for the request (e.g., GET, POST). * @param {string} path - The URL path for the request. - * @param {HttpParams} [params] - Optional parameters for the request, including query parameters, headers, body, and response validation. + * @param {HttpParams} [params] - Optional parameters for the request, + * including query parameters, headers, body, and response validation. + * {@link HttpParams.headers} override {@link SimpleHttpClient.headers}. * @return {Promise} A promise that resolves to the response of the HTTP request. * @throws {InvalidHTTPRequest} Throws an error if the HTTP request fails. */ @@ -76,6 +88,12 @@ class SimpleHttpClient implements HttpClient { url.searchParams.append(key, String(value)); }); } + const headers = new Headers(this.headers); + if (params?.headers !== undefined && params?.headers != null) { + Object.entries(params.headers).forEach(([key, value]) => { + headers.append(key, String(value)); + }); + } const response = await fetch(url, { method, headers: params?.headers as HeadersInit, @@ -120,7 +138,9 @@ class SimpleHttpClient implements HttpClient { * Makes an HTTP POST request to the specified path with optional parameters. * * @param {string} path - The endpoint to which the POST request is made. - * @param {HttpParams} [params] - An optional object containing query parameters or data to be sent with the request. + * @param {HttpParams} [params] - Optional parameters for the request, + * including query parameters, headers, body, and response validation. + * {@link HttpParams.headers} override {@link SimpleHttpClient.headers}. * @return {Promise} A promise that resolves with the response from the server. */ public async post(path: string, params?: HttpParams): Promise { diff --git a/packages/network/tests/http/SimpleHttpClient.solo.test.ts b/packages/network/tests/http/SimpleHttpClient.solo.test.ts index 80a429e6e..eeaf9d711 100644 --- a/packages/network/tests/http/SimpleHttpClient.solo.test.ts +++ b/packages/network/tests/http/SimpleHttpClient.solo.test.ts @@ -63,7 +63,9 @@ describe('SimpleHttpClient solo tests', () => { query: {}, body: {}, headers: { - 'X-Custom-Header': 'custom-value' + 'X-Custom-Header': 'custom-value', + 'Cache-Control': + 'no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate' }, validateResponseHeader: function ( headers: Record @@ -107,7 +109,11 @@ describe('SimpleHttpClient solo tests', () => { */ test('timeout test - 100 ms', async () => { const timeout = 100; // 100ms timeout - const httpClient = new SimpleHttpClient(THOR_SOLO_URL, timeout); + const httpClient = new SimpleHttpClient( + THOR_SOLO_URL, + new Headers(), + timeout + ); // Create a mock server that delays response const mockServer = jest.fn().mockImplementation(async () => { diff --git a/packages/network/tests/thor-client/ThorClient.unit.test.ts b/packages/network/tests/thor-client/ThorClient.unit.test.ts new file mode 100644 index 000000000..8aa1a5cba --- /dev/null +++ b/packages/network/tests/thor-client/ThorClient.unit.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, test } from '@jest/globals'; +import { TESTNET_URL, ThorClient } from '../../src'; + +/** + * ThorClient module tests. + * + * @group unit/clients/thor-client + */ +describe('ThorClient deprecated methods', () => { + test('ok <- fromUrl', () => { + const expected = ThorClient.at(TESTNET_URL); + // eslint-disable-next-line sonarjs/deprecation + const actual = ThorClient.fromUrl(TESTNET_URL); + expect(actual.httpClient.baseURL).toEqual(expected.httpClient.baseURL); + }); +});