Skip to content

Commit 0121b56

Browse files
committed
feat(http): Add reponseType property to HttpResponse and HttpErrorResponse
Add support for the Fetch API's responseType property in HttpResponse and HttpErrorResponse when using HttpClient with the withFetch provider.
1 parent 90b0227 commit 0121b56

File tree

4 files changed

+41
-1
lines changed

4 files changed

+41
-1
lines changed

goldens/public-api/common/http/index.api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,6 +2509,7 @@ export class HttpErrorResponse extends HttpResponseBase implements Error {
25092509
statusText?: string;
25102510
url?: string;
25112511
redirected?: boolean;
2512+
responseType?: ResponseType;
25122513
});
25132514
// (undocumented)
25142515
readonly error: any | null;
@@ -2933,6 +2934,7 @@ export class HttpResponse<T> extends HttpResponseBase {
29332934
statusText?: string;
29342935
url?: string;
29352936
redirected?: boolean;
2937+
responseType?: ResponseType;
29362938
});
29372939
readonly body: T | null;
29382940
// (undocumented)
@@ -2944,6 +2946,7 @@ export class HttpResponse<T> extends HttpResponseBase {
29442946
statusText?: string;
29452947
url?: string;
29462948
redirected?: boolean;
2949+
responseType?: ResponseType;
29472950
}): HttpResponse<T>;
29482951
// (undocumented)
29492952
clone<V>(update: {
@@ -2953,6 +2956,7 @@ export class HttpResponse<T> extends HttpResponseBase {
29532956
statusText?: string;
29542957
url?: string;
29552958
redirected?: boolean;
2959+
responseType?: ResponseType;
29562960
}): HttpResponse<V>;
29572961
// (undocumented)
29582962
readonly type: HttpEventType.Response;
@@ -2966,10 +2970,12 @@ export abstract class HttpResponseBase {
29662970
statusText?: string;
29672971
url?: string;
29682972
redirected?: boolean;
2973+
responseType?: ResponseType;
29692974
}, defaultStatus?: number, defaultStatusText?: string);
29702975
readonly headers: HttpHeaders;
29712976
readonly ok: boolean;
29722977
readonly redirected?: boolean;
2978+
readonly responseType?: ResponseType;
29732979
readonly status: number;
29742980
readonly statusText: string;
29752981
readonly type: HttpEventType.Response | HttpEventType.ResponseHeader;

packages/common/http/src/fetch.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ export class FetchBackend implements HttpBackend {
273273

274274
const redirected = response.redirected;
275275

276+
const responseType = response.type;
277+
276278
if (ok) {
277279
observer.next(
278280
new HttpResponse({
@@ -282,6 +284,7 @@ export class FetchBackend implements HttpBackend {
282284
statusText,
283285
url,
284286
redirected,
287+
responseType,
285288
}),
286289
);
287290

@@ -297,6 +300,7 @@ export class FetchBackend implements HttpBackend {
297300
statusText,
298301
url,
299302
redirected,
303+
responseType,
300304
}),
301305
);
302306
}

packages/common/http/src/response.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,21 @@ export abstract class HttpResponseBase {
192192
*/
193193
readonly redirected?: boolean;
194194

195+
/**
196+
* Indicates the type of the HTTP response, based on how the request was made and how the browser handles the response.
197+
*
198+
* This corresponds to the `type` property of the Fetch API's `Response` object, which can indicate values such as:
199+
* - `'basic'`: A same-origin response, allowing full access to the body and headers.
200+
* - `'cors'`: A cross-origin response with CORS enabled, exposing only safe response headers.
201+
* - `'opaque'`: A cross-origin response made with `no-cors`, where the response body and headers are inaccessible.
202+
* - `'opaqueredirect'`: A response resulting from a redirect followed in `no-cors` mode.
203+
* - `'error'`: A response representing a network error or similar failure.
204+
*
205+
* This property is only available when using the Fetch-based backend (via `withFetch()`).
206+
* When using Angular's (XHR) backend, this value will be `undefined`.
207+
*/
208+
readonly responseType?: ResponseType;
209+
195210
/**
196211
* Super-constructor for all responses.
197212
*
@@ -205,6 +220,7 @@ export abstract class HttpResponseBase {
205220
statusText?: string;
206221
url?: string;
207222
redirected?: boolean;
223+
responseType?: ResponseType;
208224
},
209225
defaultStatus: number = 200,
210226
defaultStatusText: string = 'OK',
@@ -216,7 +232,7 @@ export abstract class HttpResponseBase {
216232
this.statusText = init.statusText || defaultStatusText;
217233
this.url = init.url || null;
218234
this.redirected = init.redirected;
219-
235+
this.responseType = init.responseType;
220236
// Cache the ok value to avoid defining a getter.
221237
this.ok = this.status >= 200 && this.status < 300;
222238
}
@@ -297,6 +313,7 @@ export class HttpResponse<T> extends HttpResponseBase {
297313
statusText?: string;
298314
url?: string;
299315
redirected?: boolean;
316+
responseType?: ResponseType;
300317
} = {},
301318
) {
302319
super(init);
@@ -312,6 +329,7 @@ export class HttpResponse<T> extends HttpResponseBase {
312329
statusText?: string;
313330
url?: string;
314331
redirected?: boolean;
332+
responseType?: ResponseType;
315333
}): HttpResponse<T>;
316334
clone<V>(update: {
317335
body?: V | null;
@@ -320,6 +338,7 @@ export class HttpResponse<T> extends HttpResponseBase {
320338
statusText?: string;
321339
url?: string;
322340
redirected?: boolean;
341+
responseType?: ResponseType;
323342
}): HttpResponse<V>;
324343
clone(
325344
update: {
@@ -329,6 +348,7 @@ export class HttpResponse<T> extends HttpResponseBase {
329348
statusText?: string;
330349
url?: string;
331350
redirected?: boolean;
351+
responseType?: ResponseType;
332352
} = {},
333353
): HttpResponse<any> {
334354
return new HttpResponse<any>({
@@ -338,6 +358,7 @@ export class HttpResponse<T> extends HttpResponseBase {
338358
statusText: update.statusText || this.statusText,
339359
url: update.url || this.url || undefined,
340360
redirected: update.redirected ?? this.redirected,
361+
responseType: update.responseType ?? this.responseType,
341362
});
342363
}
343364
}
@@ -372,6 +393,7 @@ export class HttpErrorResponse extends HttpResponseBase implements Error {
372393
statusText?: string;
373394
url?: string;
374395
redirected?: boolean;
396+
responseType?: ResponseType;
375397
}) {
376398
// Initialize with a default status of 0 / Unknown Error.
377399
super(init, 0, 'Unknown Error');

packages/common/http/test/response_spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ describe('HttpResponse', () => {
2121
statusText: 'Created',
2222
url: '/test',
2323
redirected: true,
24+
responseType: 'cors',
2425
});
2526
expect(resp.body).toBe('test body');
2627
expect(resp.headers instanceof HttpHeaders).toBeTruthy();
@@ -29,6 +30,7 @@ describe('HttpResponse', () => {
2930
expect(resp.statusText).toBe('Created');
3031
expect(resp.url).toBe('/test');
3132
expect(resp.redirected).toBe(true);
33+
expect(resp.responseType).toBe('cors');
3234
});
3335
it('uses defaults if no args passed', () => {
3436
const resp = new HttpResponse({});
@@ -39,6 +41,7 @@ describe('HttpResponse', () => {
3941
expect(resp.ok).toBeTruthy();
4042
expect(resp.url).toBeNull();
4143
expect(resp.redirected).toBeUndefined();
44+
expect(resp.responseType).toBeUndefined();
4245
});
4346
it('accepts a falsy body', () => {
4447
expect(new HttpResponse({body: false}).body).toEqual(false);
@@ -63,13 +66,15 @@ describe('HttpResponse', () => {
6366
statusText: 'created',
6467
url: '/test',
6568
redirected: false,
69+
responseType: 'cors',
6670
}).clone();
6771
expect(clone.body).toBe('test');
6872
expect(clone.status).toBe(HttpStatusCode.Created);
6973
expect(clone.statusText).toBe('created');
7074
expect(clone.url).toBe('/test');
7175
expect(clone.headers).not.toBeNull();
7276
expect(clone.redirected).toBe(false);
77+
expect(clone.responseType).toBe('cors');
7378
});
7479
it('overrides the original', () => {
7580
const orig = new HttpResponse({
@@ -78,20 +83,23 @@ describe('HttpResponse', () => {
7883
statusText: 'created',
7984
url: '/test',
8085
redirected: true,
86+
responseType: 'cors',
8187
});
8288
const clone = orig.clone({
8389
body: {data: 'test'},
8490
status: HttpStatusCode.Ok,
8591
statusText: 'Okay',
8692
url: '/bar',
8793
redirected: false,
94+
responseType: 'opaque',
8895
});
8996
expect(clone.body).toEqual({data: 'test'});
9097
expect(clone.status).toBe(HttpStatusCode.Ok);
9198
expect(clone.statusText).toBe('Okay');
9299
expect(clone.url).toBe('/bar');
93100
expect(clone.headers).toBe(orig.headers);
94101
expect(clone.redirected).toBe(false);
102+
expect(clone.responseType).toBe('opaque');
95103
});
96104
});
97105
});

0 commit comments

Comments
 (0)