Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(http): introduce the
provideHttpClient()
API (#47502)
This commit introduces the main components of the `provideHttpClient()` provider API, designed in the style of `provideRouter()`. Initial features are defined for including legacy class-based interceptors, JSONP support, and configuring or disabling the builtin XSRF protection. This API is an alternative to providing `HttpClient` via the `HttpClientModule`, and is more tree-shakable and more capable than the NgModule implementation. Tests are included to validate the new configuration format as well as the interoperability of the two styles of providing and configuring `HttpClient`. PR Close #47502
- Loading branch information
1 parent
84d0d33
commit e47b129
Showing
5 changed files
with
406 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Provider} from '@angular/core'; | ||
|
||
import {HttpBackend, HttpHandler} from './backend'; | ||
import {HttpClient} from './client'; | ||
import {HTTP_INTERCEPTOR_FNS, HttpInterceptorHandler, LEGACY_INTERCEPTOR_FN, legacyInterceptorFnFactory} from './interceptor'; | ||
import {JsonpCallbackContext, jsonpCallbackContext, JsonpClientBackend, jsonpInterceptorFn} from './jsonp'; | ||
import {HttpXhrBackend} from './xhr'; | ||
import {HttpXsrfCookieExtractor, HttpXsrfTokenExtractor, XSRF_COOKIE_NAME, XSRF_ENABLED, XSRF_HEADER_NAME, xsrfInterceptorFn} from './xsrf'; | ||
|
||
export enum HttpFeatureKind { | ||
LegacyInterceptors, | ||
CustomXsrfConfiguration, | ||
NoXsrfProtection, | ||
JsonpSupport, | ||
} | ||
|
||
export interface HttpFeature<KindT extends HttpFeatureKind> { | ||
ɵkind: KindT; | ||
ɵproviders: Provider[]; | ||
} | ||
|
||
function makeHttpFeature<KindT extends HttpFeatureKind>( | ||
kind: KindT, providers: Provider[]): HttpFeature<KindT> { | ||
return { | ||
ɵkind: kind, | ||
ɵproviders: providers, | ||
}; | ||
} | ||
|
||
|
||
export function provideHttpClient(...features: HttpFeature<HttpFeatureKind>[]): Provider[] { | ||
if (ngDevMode) { | ||
const featureKinds = new Set(features.map(f => f.ɵkind)); | ||
if (featureKinds.has(HttpFeatureKind.NoXsrfProtection) && | ||
featureKinds.has(HttpFeatureKind.CustomXsrfConfiguration)) { | ||
throw new Error( | ||
ngDevMode ? | ||
`Configuration error: found both withXsrfConfiguration() and withNoXsrfProtection() in the same call to provideHttpClient(), which is a contradiction.` : | ||
''); | ||
} | ||
} | ||
|
||
const providers: Provider[] = [ | ||
HttpClient, | ||
HttpXhrBackend, | ||
HttpInterceptorHandler, | ||
{provide: HttpHandler, useExisting: HttpInterceptorHandler}, | ||
{provide: HttpBackend, useExisting: HttpXhrBackend}, | ||
{ | ||
provide: HTTP_INTERCEPTOR_FNS, | ||
useValue: xsrfInterceptorFn, | ||
multi: true, | ||
}, | ||
{provide: XSRF_ENABLED, useValue: true}, | ||
{provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor}, | ||
]; | ||
|
||
for (const feature of features) { | ||
providers.push(...feature.ɵproviders); | ||
} | ||
|
||
return providers; | ||
} | ||
|
||
export function withLegacyInterceptors(): HttpFeature<HttpFeatureKind.LegacyInterceptors> { | ||
// Note: the legacy interceptor function is provided here via an intermediate token | ||
// (`LEGACY_INTERCEPTOR_FN`), using a pattern which guarantees that if these providers are | ||
// included multiple times, all of the multi-provider entries will have the same instance of the | ||
// interceptor function. That way, the `HttpINterceptorHandler` will dedup them and legacy | ||
// interceptors will not run multiple times. | ||
return makeHttpFeature(HttpFeatureKind.LegacyInterceptors, [ | ||
{ | ||
provide: LEGACY_INTERCEPTOR_FN, | ||
useFactory: legacyInterceptorFnFactory, | ||
}, | ||
{ | ||
provide: HTTP_INTERCEPTOR_FNS, | ||
useExisting: LEGACY_INTERCEPTOR_FN, | ||
multi: true, | ||
} | ||
]); | ||
} | ||
|
||
export function withXsrfConfiguration( | ||
{cookieName, headerName}: {cookieName?: string, headerName?: string}): | ||
HttpFeature<HttpFeatureKind.CustomXsrfConfiguration> { | ||
const providers: Provider[] = []; | ||
if (cookieName !== undefined) { | ||
providers.push({provide: XSRF_COOKIE_NAME, useValue: cookieName}); | ||
} | ||
if (headerName !== undefined) { | ||
providers.push({provide: XSRF_HEADER_NAME, useValue: headerName}); | ||
} | ||
|
||
return makeHttpFeature(HttpFeatureKind.CustomXsrfConfiguration, providers); | ||
} | ||
|
||
export function withNoXsrfProtection(): HttpFeature<HttpFeatureKind.NoXsrfProtection> { | ||
return makeHttpFeature(HttpFeatureKind.NoXsrfProtection, [ | ||
{ | ||
provide: XSRF_ENABLED, | ||
useValue: false, | ||
}, | ||
]); | ||
} | ||
|
||
export function withJsonpSupport(): HttpFeature<HttpFeatureKind.JsonpSupport> { | ||
return makeHttpFeature(HttpFeatureKind.JsonpSupport, [ | ||
JsonpClientBackend, | ||
{provide: JsonpCallbackContext, useFactory: jsonpCallbackContext}, | ||
{provide: HTTP_INTERCEPTOR_FNS, useValue: jsonpInterceptorFn, multi: true}, | ||
]); | ||
} |
Oops, something went wrong.