-
Notifications
You must be signed in to change notification settings - Fork 26.9k
fix(common): stricter type for http methods #44328
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
packages/common/http/public_api.ts
Outdated
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 exposed the type to reuse it in common/http/testing for RequestMatch, but maybe there is a better way?
packages/common/http/src/client.ts
Outdated
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.
Rather than having this union everywhere, how about making the HttpMethod type cover both upper and lower case?
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 agree with @petebacondarwin. This would really simplify things.
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 went back and forth on how to declare this, I've changed it to remove the union type 👍
jessicajaniuk
left a comment
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.
This looks very breaking to me as this service is used by everyone and would require everyone to change to a type. We'd definitely need a migration.
packages/common/http/src/client.ts
Outdated
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 agree with @petebacondarwin. This would really simplify things.
The current API accepts `string` for the HTTP method.
This commit tightens the API to only accept one of the possible HTTP verb, either in lowercase or in uppercase (to preserve the existing behavior).
BREAKING CHANGE: The HTTP method must now be one of `'GET'|'HEAD'|'POST'|'PUT'|'DELETE'|'CONNECT'|'OPTIONS'|'TRACE'|'PATCH'|'JSONP'` (or one of these in lowercase) instead of a `string`. This helps developers to catch possible typos like `http.request('POTS', ...)`, but can result in compilation errors when updating if you have such typos in your code. In the rare cases where developers used a temporary string variable to store the method, the type of this variable must be updated to be a string literal, for example `const method = 'GET' as const`.
79a0060 to
8fc399e
Compare
|
@jessicajaniuk yeah, we were wondering on Slack with Pete and Andrew how much that would be breaking: if you or another Googler can run a presubmit, that would be great! It might not be that bad as most people are probably not using |
|
@cexbrayat I ran a presubmit and it's definitely breaking. The presubmit failed pretty significantly. |
| }): Observable<T>; | ||
| request<R>(req: HttpRequest<any>): Observable<HttpEvent<R>>; | ||
| request(method: string, url: string, options: { | ||
| request(method: HttpMethod, url: string, 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.
To avoid this being breaking, this should really be string|HttpMethod anywhere HttpMethod would be accepted. This would ensure everything currently still works, but also can be typed.
| withCredentials?: boolean; | ||
| }); | ||
| constructor(method: string, url: string, body: T | null, init?: { | ||
| constructor(method: HttpMethod, url: string, body: T | null, init?: { |
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 suggest changing method to be string|HttpMethod and then attempting to coerce the string version to the proper HttpMethod option. If it can't be coerced, then we throw. That would be the least breaky and would still allow for strong typing.
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.
That's the same as being just string which kind of defeats the point (types arithmetic)
| * The outgoing HTTP request method. | ||
| */ | ||
| readonly method: string; | ||
| readonly method: HttpMethod; |
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.
Same thing here with string|HttpMethod
|
@cexbrayat just wanted to provide a quick update after team's discussion:
Once we get more info based on the items above, we can make a final decision on how to proceed. |
|
@AndrewKushnir Sure
The IANA registry defines a lot of other methods with their own RFC, see https://www.iana.org/assignments/http-methods/http-methods.xhtml If this is too breaking, we can definitely settle for a union type |
|
@AndrewKushnir @jessicajaniuk I opened #44363 as an alternative based on a union type, if you want to check how less breaky it is. |
|
Just a quick update on:
We've ran all affected tests and there are ~23 places that would require a cleanup in Google's codebase. It looks feasible to prepare Google's codebase to this change, but we are trying to evaluate the impact on 3rd party libraries as well. We'll keep this thread updated. |
|
Catching up on some triage -- it seems we could provide a schematic which adds a cast anywhere one of these methods is called, WDYT?
We'd probably want to land #44363 first, then the migration and eliminate the |
|
@cexbrayat We're going to close this and #44363 for now. We totally see the benefit of the type strictness, but it's just too challenging for us to prioritize landing. As usual, thanks for the effort! |
|
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. |
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
It's currently possible to use any string as the HTTP method.
As discussed with Pete and @AndrewKushnir it could be interesting to have a more strictly typed API,
and only allow valid HTTP methods (both in lowercase and uppercase to preserve the existing behavior)
What is the new behavior?
This commit tightens the API to only accept one of the possible HTTP verb, either in lowercase or in uppercase (to preserve the existing behavior).
Does this PR introduce a breaking change?
The HTTP method must now be one of
'GET'|'HEAD'|'POST'|'PUT'|'DELETE'|'CONNECT'|'OPTIONS'|'TRACE'|'PATCH'|'JSONP'(or one of these in lowercase) instead of astring. This helps developers to catch possible typos likehttp.request('POTS', ...), but can result in compilation errors when updating if you have such typos in your code. In the rare cases where developers used a temporary string variable to store the method, the type of this variable must be updated to be a string literal, for exampleconst method = 'GET' as const.Other information