-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[core-http] avoid mutating global fetch #9880
Conversation
Use `import node_fetch from "node-fetch" instead of `import "node-fetch"`.
@@ -4,21 +4,20 @@ | |||
import * as tough from "tough-cookie"; | |||
import * as http from "http"; | |||
import * as https from "https"; | |||
import "node-fetch"; | |||
import node_fetch from "node-fetch"; |
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.
used node_fetch
to avoid conflict with the global fetch
} | ||
|
||
const globalWithFetch = global as GlobalWithFetch; | ||
if (typeof globalWithFetch.fetch !== "function") { | ||
const fetch = require("node-fetch").default; | ||
globalWithFetch.fetch = fetch; | ||
globalWithFetch.fetch = node_fetch; |
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.
but... why do this? Can't we just use node_fetch directly? This class is only used in node where fetch isn't defined.
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 actually tried that first, however, the Request
type defined in node-fetch isn't compatible with Request
from DOM because it defined additional properties. node-fetch
v3.0 doesn't seem to have these.
Can I safely suppress/ignore this error?
src/nodeFetchHttpClient.ts:91:23 - error TS2345: Argument of type 'RequestInfo' is not assignable to parameter of type 'import("/home/azuser/git/jssdk/common/temp/node_modules/.pnpm/@types/node-fetch@2.5.7/node_modules/@types/node-fetch/index").RequestInfo'.
Type 'Request' is not assignable to type 'RequestInfo'.
Type 'Request' is missing the following properties from type 'Request': context, compress, counter, follow, and 6 more.
91 return node_fetch(input, init);
I now realized that current PR still modifies global
so won't fix the issue.
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.
It seems like the trouble is export type CommonRequestInfo = Request | string;
in fetchHttpClient
yeah? I think we need to either define our own input interface or re-use node-fetch's
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.
Our base class FetchHttpClient
has this abstract method so we need to have two types that are compatible with both browsers and Node.
abstract async fetch(input: CommonRequestInfo, init?: RequestInit): Promise<Response>;
I could narrow down to common things that work for both DOM and NodeJs for input
: change to input: string
because it's the only type we ever use. However it seems harder to do similar for RequestInit
as many things are incompatible.
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.
url: string
is more accurate
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.
/cc @willmtemple who made changes around this previously.
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 returned type Response
is not compatible either between browser and Node. So we would need three types that are common/intersection of browser and Node.
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.
So I got rid of the type errors by defining common types with some of the properties as any
. Looks very hacky but not sure whether there are better ways.
32b210d
to
6d2b1fa
Compare
@@ -40,6 +40,7 @@ describe("defaultHttpClient (node)", function() { | |||
}); | |||
|
|||
const client = new DefaultHttpClient(); | |||
(client as any)._fetch = httpMock.getFetch(); |
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 originally added a DefaultHttpClient
constructor to allow passing in the mocked fetch, but felt changing public api just for testing seems too much.
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.
Honestly I think I'd like the constructor parameter better, since at the moment it's very hard to find all the places that set the secret property, since TS can't alias through any
and the language service will claim it's never set.
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.
Changed to allow passing in fetch as a constructor parameter.
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.
Changed again. Now mocking the fetch()
instance method.
6d2b1fa
to
4fbc638
Compare
// returns the locally mocked fetch instance | ||
getFetch(): typeof node_fetch { | ||
/// @ts-ignore | ||
return this._fetch as typeof node_fetch; |
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 had to ignore a type error here otherwise, the fetch-mock type is not compatible with node-fetch.
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.
Sorry that this review fell off my radar. I think if we can address the commented issue this PR should be mergeable.
@@ -167,10 +168,13 @@ export function createPipelineFromOptions(pipelineOptions: InternalPipelineOptio | |||
// | |||
// @public (undocumented) | |||
export class DefaultHttpClient extends FetchHttpClient { | |||
constructor(_fetch?: typeof node_fetch); |
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 is the only part that feels bad to me. I don't think we should have test-only stuff in the default constructor, especially not fetch-specific details.
If you already have getFetch
as a method of the class, can't you just use sinon to override that method during testing instead of passing the thing explicitly 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.
Agree. I didn't like changing the constructor. I will explore using sinon.
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.
getFetch()
was private I think. However I found fetch()
is simple enough so I mocked it instead.
thus get rid of the constructor parameter that is solely for testing purpose.
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.
Thanks for the update! This looks much nicer!
I feel like while we could still refactor this to be a little cleaner, it's not worth the effort since it's only test code that is messy now.
Yeah, I have duplicated the |
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.
Had a minor comment you can take or leave. Looks good, ship it!
Co-authored-by: chradek <51000525+chradek@users.noreply.github.com>
Porting fix from Azure/azure-sdk-for-js#9880. Use import node_fetch from "node-fetch" instead of import "node-fetch". Resolves Azure#383
Use
import node_fetch from "node-fetch"
instead ofimport "node-fetch"
.Resolves #5143.