-
Notifications
You must be signed in to change notification settings - Fork 1
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
Browser support #2
Conversation
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!
This requires a major version bump?
Missing features:
- unknown performance (so I'm a bit wary of
node-fetch
) - alternative
fetch
implementation in constructor - need to extend the AbortError on timeouts to provide info on which method timed out
body: JSON.stringify(body), | ||
method: 'POST', | ||
}); | ||
const isJSON = (response.headers.get('content-type') || '').startsWith('application/json'); |
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 actually prefer this explicit error handling instead of the "simple" request-promise-native
.
{{/throws}} | ||
throw new InternalServerError(body.message); | ||
} else if (!isJSON) { | ||
throw new Error(`${response.status} - ${response.statusText}`); |
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.
Should we have partial body if available (e.g. slice(0,256))? Also headers might tell us the server/load-balancer the error response came from.
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.
Let's add this in a separate commit #4
| 'window' | ||
> { | ||
headers?: Record<string, 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.
Can options include a fetch
implementation, with node-fetch
being the default, so it's possible to pass a wrapped fetch
for tracing similar to https://github.com/openzipkin/zipkin-js/blob/master/packages/zipkin-instrumentation-fetch/src/wrapFetch.js ?
// tslint:disable | ||
import fetch from 'node-fetch'; | ||
import { RequestInit } from 'node-fetch'; | ||
import AbortController from 'abort-controller'; |
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 not implemented on browser?
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.
Not yet, #3
|
||
if (mergedOptions.timeoutMs) { | ||
const controller = new AbortController(); | ||
const timeout = setTimeout(() => controller.abort(), mergedOptions.timeoutMs); |
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.
Note that this timeout is much more crude than https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback - it's a global timeout and not timeout between consecutive bytes received.
This might not matter for small messages, but highlights the lack of control of the low level request when using fetch 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.
I think this is usually the expected behavior.
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.
Both behaviors are interesting (and the interval between bytes is used by Node.js and NGINX), but I think it might be enough for now.
@@ -0,0 +1,124 @@ | |||
// tslint:disable | |||
import 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.
Did you see any benchmark comparisons with request
(and request-promise
)?
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.
As discussed F2F transition to fetch should not slow us down.
src/test/test_rpc.ts
Outdated
import { TestClient } from './client'; | ||
|
||
export default async function test(client: TestClient) { | ||
await expect(client.bar('yay', { timeoutMs: 100 })).to.eventually.be.rejectedWith(Error, 'The user aborted a request.'); |
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 this is a confusing error, can we catch the AbortError
and throw a TimeoutError
with details "call to bar
timed out"?
reject(); | ||
}); | ||
webpack.stdout.on('data', (buff: Buffer) => { | ||
const data = buff.toString(); |
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.
Ouch.. there is no nicer API for 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.
I'll add a comment that this is ugly
ValidationError, | ||
}; | ||
|
||
export interface Options extends Pick<RequestInit, 'agent' | 'redirect' | 'follow' | 'compress'> { |
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.
Perhaps we shouldn't expose node-fetch
options at all, and only provide our own, so that we can switch implementation easily?
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 will consider but I think for now it's best not to limit our users.
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!
reject(); | ||
}); | ||
webpack.stdout.on('data', (buff: Buffer) => { | ||
const data = buff.toString(); |
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'll add a comment that this is ugly
{{/throws}} | ||
throw new InternalServerError(body.message); | ||
} else if (!isJSON) { | ||
throw new Error(`${response.status} - ${response.statusText}`); |
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.
Let's add this in a separate commit #4
@@ -0,0 +1,124 @@ | |||
// tslint:disable | |||
import 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.
As discussed F2F transition to fetch should not slow us down.
ValidationError, | ||
}; | ||
|
||
export interface Options extends Pick<RequestInit, 'agent' | 'redirect' | 'follow' | 'compress'> { |
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 will consider but I think for now it's best not to limit our users.
|
||
if (mergedOptions.timeoutMs) { | ||
const controller = new AbortController(); | ||
const timeout = setTimeout(() => controller.abort(), mergedOptions.timeoutMs); |
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 this is usually the expected behavior.
// tslint:disable | ||
import fetch from 'node-fetch'; | ||
import { RequestInit } from 'node-fetch'; | ||
import AbortController from 'abort-controller'; |
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.
Not yet, #3
@vogre PTAL |
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!
WDYT about passing the fetch
implementation as part of options / setting it via some setFetch
method for tracing?
|
||
if (mergedOptions.timeoutMs) { | ||
const controller = new AbortController(); | ||
const timeout = setTimeout(() => controller.abort(), mergedOptions.timeoutMs); |
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.
Both behaviors are interesting (and the interval between bytes is used by Node.js and NGINX), but I think it might be enough for now.
Thanks! Didn't really understand the comment about passing the fetch implementation in options, was what I did not good enough? |
@bergundy: what I want is some way to provide instrumentation (e.g. counters, timings, logs, etc. for the requests). One option is instead of |
} | ||
|
||
try { | ||
const response = await (mergedOptions.fetchImplementation || fetch)(`${this.serverUrl}/{{name}}`, { |
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.
@vogre was this what you were looking for?
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.
Separation of client-browser
and client-node
got me there.
There's some duplication in the client template ATM, I'll handle it later.