-
Notifications
You must be signed in to change notification settings - Fork 753
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
Refactor headers #667
Refactor headers #667
Conversation
All seems sensible to me. |
Our own docs say that sending idempotency keys on non-POST requests "has no effect and should be avoided". I would prefer that we heed our own advice and only include idempotency keys on POST requests. |
Sorry, I was unclear – we continue to follow that advice, we just generate the idempotency key without using it when the user has passed their own in, which is a mild code smell / perf hit. |
Ah gotcha, not a huge deal then. Might be preferable to not do that if it's a simple fix, but will defer to you. |
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.
Just one nitpick, looks good otherwise.
576a1d4
to
87fd537
Compare
aea8eea
to
d6419f3
Compare
d6419f3
to
d50bcae
Compare
Okay, I think this is a bit cleaner now. |
'X-Stripe-Client-User-Agent': clientUserAgent, | ||
'X-Stripe-Client-Telemetry': this._getTelemetryHeader(), | ||
'Stripe-Version': apiVersion, | ||
'Idempotency-Key': this._defaultIdempotencyKey(method), |
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.
Why don't we pass userSuppliedheaders
into defaultIdempotencyKey
and use whatever the user passed in (if they passed something in and after normalizing their input). It'll save us having to run uuid()
on every POST 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.
The code was uglier, and uuid() is fast:
> now = Date.now(); uuid(); Date.now() - now
2
> now = Date.now(); uuid(); Date.now() - now
0
We'd have to normalize the user headers first, and override in two places, which rubbed me the wrong way
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.
eg; it'd be
const cleanedUserHeaders = normalize(userHeaders)
const defaultHeaders = {
//...
'Idempotency-Key': cleanedUserHeaders['Idempotency-Key'] || this._defaultIdempotencyKey(method)
}
Object.assign(defaultHeaders, cleanedUserHeaders) // why override twice?
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.
uuid
is fast, so agreed that this isn't a big deal 👍
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.
@rattrayalex-stripe My 5 cents: uuid
is a huge dependency () for just one call across the library. You are using version 4 of UUID that is just a random value (not time sensitive, contrary version 1) in place where you are not required to have an UUID.
Doing something like Date.now() + crypto.randomBytes(40).toString('hex')
is safer and faster for this use 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.
Oof! Good catch, Tino. I'll remove that in a follow-up (please let me do it 😄 I have opinions on how I want it to happen).
lgtm |
💡 Probably instead of all normalization logic here it's better to expose/use standard methods, like |
Thanks Tino – (edited your comment to change "threats" to "treats" btw) – I did consider that approach, which might be a bit more correct, but this felt simpler and in practice should have identical behavior. |
cc @paulasjes-stripe @jlomas-stripe @ob-stripe
r? @richardm-stripe (account doesn't exist yet, need to work on that)
Trying to carefully review #663 made my head spin as I tried to track through how we set headers.
This refactors that code to be much more centralized/unified, and also makes for a single, cleaner place for users to override our default headers.
However, this introduces a few possible subtle changes of behavior which I'm worried about:
defaultHeaders
variable get set to empty-string, they will now send the header key with no value (I think this would only apply toapiVersion
and I don't think that's likely to happen and I don't think there would be a consequence of it).uuid()
to generate a default idempotency key even if the user has supplied one (we use theirs).{'user-agent': 'foo'}
as a custom header, it would have been appended to ours with a comma (since both keys would be in the hash, and that's how node's http(s) library represents that. Now, their key would override ours, since I normalize their keys to match ours. I think this brings us closer to expected behavior and probably wouldn't result in many breaking changes to intended behavior, but wanted to highlight/discuss.