-
Notifications
You must be signed in to change notification settings - Fork 26.6k
feat(http): new HttpClient API #17143
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
Conversation
I'm expecting this to have some issues on CI, but want to get the review started while I resolve them. I may need @jasonaden to help me debug the build process. |
a03de4d
to
8ac3fae
Compare
The angular.io preview for 8ac3fae7610574468704c54bc4f02c6c52da09a5 is available here. |
packages/http/client/src/request.ts
Outdated
return 'text/plain'; | ||
} | ||
// Arrays, objects, and numbers will be encoded as JSON. | ||
if (typeof this.body === 'object' || typeof this.body === 'number' || Array.isArray(this.body)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the check typeof this.body === 'boolean' maybe needed here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I'll add it (though the toString()
serialization of boolean values is the same as the JSON encoding).
expect((res as any)['data']).toEqual('hello world'); | ||
done(); | ||
}); | ||
backend.expectOne('/test').flush({'data': 'hello world'}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thats an awesome improvement over the current ConnectionBackend hoopla 👍
packages/http/client/public_api.ts
Outdated
*/ | ||
|
||
export {HttpBackend, HttpHandler} from './src/backend'; | ||
export * from './src/client_types'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please export things individually so that we don't accidentally expose API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
packages/http/client/src/jsonp.ts
Outdated
/** | ||
* Type for a map of JSONP callbacks. | ||
*/ | ||
export interface JsonpAdapterCallbackMap { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Convert this to abstract class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
packages/http/client/src/jsonp.ts
Outdated
* | ||
* In the browser, this should always be the `window` object. | ||
*/ | ||
export const JSONP_ADAPTER_CALLBACK_MAP = new InjectionToken<JsonpAdapterCallbackMap>('JSONP_ADAPTER_CALLBACK_MAP'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
packages/http/client/src/jsonp.ts
Outdated
*/ | ||
@Injectable() | ||
export class JsonpClientBackend implements HttpBackend { | ||
constructor(@Inject(JSONP_ADAPTER_CALLBACK_MAP) private callbackMap: JsonpAdapterCallbackMap, @Inject(DOCUMENT) private document: any) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for @Inject
packages/http/client/src/jsonp.ts
Outdated
|
||
// Remove the response callback from the callbackMap (window object in the | ||
// browser). | ||
delete this.callbackMap[callback]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you use delete
the object becomes slow forever. Consider this.callbackMap[...] = undefined
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in this case, because it's window
deleting is reasonable (and keeps from polluting it forever / leaking memory).
packages/http/client/src/client.ts
Outdated
export class HttpClient { | ||
constructor(private handler: HttpHandler) {} | ||
|
||
request<R>(req: HttpRequest<any>): Observable<HttpEvent<R>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
document these
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
The angular.io preview for c83299dabb2695bc2817c40b38cdcfcef18f7a6e is available here. |
packages/http/client/src/request.ts
Outdated
*/ | ||
function mightHaveBody(method: string): boolean { | ||
switch (method) { | ||
case 'DELETE': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case this is not on purpose: DELETE
is listed here as not having a body, but is in the HttpBodyMethod
type above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
packages/http/client/src/xhr.ts
Outdated
// Quick check to give a better error message when a user attempts to use | ||
// HttpClient.jsonp() without installing the JsonpClientModule | ||
if (req.method === 'JSONP') { | ||
throw new Error(`Attempted to construct Jsonp request without JsonpClientModule installed.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the module is HttpClientJsonpModule
instead of JsonpClientModule
The angular.io preview for b18bb9fe693bcc28a5d17b4587a59aced5a596a6 is available here. |
The angular.io preview for 4b770e260967b8802f058cb5f29446b8a82571ea is available here. |
The angular.io preview for 10db6e58ae76cf58fb1d9dac4610dfb491bccdf2 is available here. |
5a2fe05
to
27793b0
Compare
The angular.io preview for 5a2fe052c78d413313f2626aa085e4d8723e8e56 is available here. |
The angular.io preview for 27793b024fef212213dc9401f3d471e20164c2fd is available here. |
The angular.io preview for 0495b72f6c281fd3c45de246c1a2f23162f659ae is available here. |
} | ||
|
||
/** @experimental */ | ||
export declare type HttpSerializedBody = ArrayBuffer | Blob | FormData | string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
|
||
/** @experimental */ | ||
export declare type HttpMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET' | 'HEAD' | 'JSONP' | 'OPTIONS'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we make this type internal? the public apis that use this type also use | string
so the type is meaningless there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
c4ae85a
to
ef6d58d
Compare
You can preview c4ae85a at https://pr17143-c4ae85a.ngbuilds.io/. |
You can preview ef6d58d at https://pr17143-ef6d58d.ngbuilds.io/. |
You can preview 1097bf2 at https://pr17143-1097bf2.ngbuilds.io/. |
You can preview cd73359 at https://pr17143-cd73359.ngbuilds.io/. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expand the interceptor test and this is good to go.
🎉 🎈 🎆
You can preview 475a86c at https://pr17143-475a86c.ngbuilds.io/. |
HttpClient is an evolution of the existing Angular HTTP API, which exists alongside of it in a separate package, @angular/common/http. This structure ensures that existing codebases can slowly migrate to the new API. The new API improves significantly on the ergonomics and features of the legacy API. A partial list of new features includes: * Typed, synchronous response body access, including support for JSON body types * JSON is an assumed default and no longer needs to be explicitly parsed * Interceptors allow middleware logic to be inserted into the pipeline * Immutable request/response objects * Progress events for both request upload and response download * Post-request verification & flush based testing framework
You can preview e37f23f at https://pr17143-e37f23f.ngbuilds.io/. |
@alxhub @IgorMinar I've got a few remaining questions if you don't mind.
Currently testing a service doing a POST implies something like: http
.expectOne(req => {
expect(req.method).toBe('POST');
expect(req.url).toBe(`/api/users/1`);
expect(req.body).toEqual(user);
return true;
})
.flush(user); whereas we could have: http
.expectOne('POST', '/api/users/1', user)
.flush(user); or (even better?): http
.expectPOST('/api/users/1', user)
.flush(user);
If this is going to be merged soon, do you want me to open specific issues for some/all the points above? |
@cexbrayat thanks for the feedback!
|
@cexbrayat awesome feedback, thanks!
As Igor mentioned, this is coming to the API.
I'd rather not go down this route, actually. The new API considers request matching to be separate from assertion. I would write your POST body expectation as follows:
This example is actually broken:
The function taken by |
Merged manually. |
@alxhub @IgorMinar Thank you for listening and taking the time to answer! I followed with a few issues regarding params handling (potential bugs) and testing APIs (potential improvements :) ): |
Great work! I'm curious, why did you guys put the new HTTP client into Just interested in the overall strategy here :) |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
HttpClient is an evolution of the existing Angular HTTP API, which exists
alongside of it in a separate package, @angular/http/client. This structure
ensures that existing codebases can slowly migrate to the new API.
The new API improves significantly on the ergonomics and features of the legacy
API. A partial list of new features includes: