Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sitecore-jss] Introduce separate flow for fetching streams #2022

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Our versioning strategy is as follows:
### 🐛 Bug Fixes

* `[sitecore-jss-nextjs]` Fix Chromes editing mode when rendering host URL is internally redirected in XMCloud ([#2019](https://github.com/Sitecore/jss/pull/2019))
* `[sitecore-jss]` NativeDataFetcher doesn't return stream response ([#2020](https://github.com/Sitecore/jss/pull/2020))
* `[sitecore-jss]` NativeDataFetcher doesn't return stream response ([#2020](https://github.com/Sitecore/jss/pull/2020)[#2022](https://github.com/Sitecore/jss/pull/2022))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be under the breaking change section?


## 22.4.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const sitemapApi = async (

try {
const fetcher = new NativeDataFetcher();
const response = await fetcher.fetch<ReadableStream<Uint8Array>>(sitemapUrl);
const response = await fetcher.fetchStream<Uint8Array>(sitemapUrl);

const reader = response.data.getReader();
if (reader) {
Expand Down
20 changes: 19 additions & 1 deletion packages/sitecore-jss/src/native-fetcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ describe('NativeDataFetcher', () => {
expect(fetchInit?.body).to.be.undefined;
});

it('should execute request with custom response parser', async () => {
const fetcher = new NativeDataFetcher();

spy.on(global, 'fetch', mockFetch(200, {}, { responseType: 'text' }));

const response = await fetcher.fetch('http://test.com/api', {}, () => 'response override');
art-alexeyenko marked this conversation as resolved.
Show resolved Hide resolved
expect(response.data).to.equal('response override');
});

it('fetchStream should return response.body', async () => {
const fetcher = new NativeDataFetcher();

spy.on(global, 'fetch', mockFetch(200, { body: 'response body' }, { responseType: 'text' }));

const response = await fetcher.fetchStream('http://test.com/api');
expect(response.data).to.equal('response body');
});

it('should execute request with stream response type', async () => {
const fetcher = new NativeDataFetcher();

Expand All @@ -151,7 +169,7 @@ describe('NativeDataFetcher', () => {
})
);

const response = await fetcher.fetch('http://test.com/api');
const response = await fetcher.fetchStream('http://test.com/api');

expect(response.status).to.equal(200);
expect(response.data instanceof ReadableStream).to.be.true;
Expand Down
40 changes: 32 additions & 8 deletions packages/sitecore-jss/src/native-fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ export type NativeDataFetcherFunction<T> = (
data?: RequestInit
) => Promise<NativeDataFetcherResponse<T>>;

/**
* Type describing oprional response parser for fetch requests
*/
export type ResponseParserFunc = (
art-alexeyenko marked this conversation as resolved.
Show resolved Hide resolved
response: Response,
debug: (message: string, ...optionalParams: any[]) => void
) => Promise<unknown> | unknown;

export type NativeDataFetcherConfig = NativeDataFetcherOptions & RequestInit;

export class NativeDataFetcher {
Expand All @@ -60,14 +68,19 @@ export class NativeDataFetcher {
* Implements a data fetcher.
* @param {string} url The URL to request (may include query string)
* @param {RequestInit} [options] Optional fetch options
* @param {ResponseParserFunc} [responseParser] Optionally specifies custom way to parse fetch response
* @returns {Promise<NativeDataFetcherResponse<T>>} response
*/
async fetch<T>(url: string, options: RequestInit = {}): Promise<NativeDataFetcherResponse<T>> {
async fetch<T>(
url: string,
options: RequestInit = {},
responseParser?: ResponseParserFunc
): Promise<NativeDataFetcherResponse<T>> {
const { debugger: debugOverride, fetch: fetchOverride, ...init } = this.config;
const startTimestamp = Date.now();
const fetchImpl = fetchOverride || fetch;
const debug = debugOverride || debuggers.http;

responseParser = responseParser || this.parseResponse;
const requestInit = this.getRequestInit({ ...init, ...options });

const fetchWithOptionalTimeout = [fetchImpl(url, requestInit)];
Expand All @@ -88,7 +101,7 @@ export class NativeDataFetcher {
return res;
});

const respData = await this.parseResponse(response, debug);
const respData = await responseParser(response, debug);
if (!response.ok) {
const error = this.createError(response, respData);
debug('Response error: %o', error.response);
Expand All @@ -111,6 +124,22 @@ export class NativeDataFetcher {
}
}

/**
* performs a fetch call with that returns fetch's response.body as a ReadableStream
* @param {string} url The URL to request (may include query string)
* @param {RequestInit} [options] Optional fetch options
* @returns {Promise<NativeDataFetcherResponse<ReadableStream<T>>>} response
*/
async fetchStream<T>(
art-alexeyenko marked this conversation as resolved.
Show resolved Hide resolved
url: string,
options: RequestInit = {}
): Promise<NativeDataFetcherResponse<ReadableStream<T>>> {
const parseStreamResponse = (response: Response) => {
art-alexeyenko marked this conversation as resolved.
Show resolved Hide resolved
return response.body;
};
return this.fetch<ReadableStream<T>>(url, options, parseStreamResponse);
}

/**
* Perform a GET request
* @param {string} url The URL to request (may include query string)
Expand Down Expand Up @@ -220,11 +249,6 @@ export class NativeDataFetcher {
if (contentType.includes('application/json')) {
return await response.json();
}

if (response.body instanceof ReadableStream) {
return response.body;
}

return await response.text();
} catch (error) {
debug('Response parsing error: %o', error);
Expand Down