-
Notifications
You must be signed in to change notification settings - Fork 199
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
fix(api): change request interceptors applying logic #3190
Conversation
baseRequest = applyCustomizeRequestHeaders( | ||
baseHeaders.merging(headers ?? [:], uniquingKeysWith: { _, new in new }), | ||
on: baseRequest | ||
) |
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 this flow (construct -> intercept -> apply customized header), do we still need to apply the request.headers
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.
As this method signature implicates, I think we still need to apply the headers.
static func constructURLRequest(with url: URL,
operationType: RESTOperationType,
headers: [String: String]?,
requestPayload: Data?) -> URLRequest
AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSRESTOperation.swift
Outdated
Show resolved
Hide resolved
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 customized request headers provided during the creation of the RESTRequest should take precedence over interceptors.
This is already happening here before the change.
var requestHeaders = ["content-type": "application/json"]
if let headers = headers {
for (key, value) in headers { // if there's a "content-type" key here
requestHeaders[key] = value // it will overwrite the default "application/json" value here
}
}
My understanding is that we need to change...
... to give precedence to callsite supplied headers.
Am I missing something?
The logic to build the URLRequest for RESTRequest happends here. In my opinion, as the interceptors are simply adjust the request to align with their specific requirements, we just need to ensure the customize headers are applied after applying all the interceptors. |
For my edification, can you point to some external documentation that says you need to set a There is probably a requirement to set A content type [citation needed], at which point would it be cleaner for the Interceptors to check if one has not already been set and then set it based on their individual requirements? Interceptors are passed in a URLRequest object, so should be easy to do. Concretely, something like this:
By introducing another method to set custom headers fields like this PR does, there's multiple places in this code where header fields could be set or overwritten, which makes it hard to reason or read. Thoughts? |
I don't think IAM or auth token need to be in json format. I beleive the
The new method is internal method. The key point of the PR is we respect the headers created with |
While this might be an internal method, correct me if I'm wrong- doesn't this have ramifications of the behavior of the library? Previously you could set a "default" value for a header while creating the RESTRequest object, while letting a later user-defined interceptor to dynamically change the value of the header. So something like this:
Now the behavior of the library is changing so that it the value of "customHeader" is going to be set to "default-value", as opposed to "new-value" previously. At the very least I would think this needs a documentation change to call out this new behavior, and perhaps even a MV bump (I'm new to this library so I'm not sure what constitutes a MV bump). Just my 2c. Thanks for looking into this. |
Thanks for your example @sandeepklr. I got your point. You are right. The current change could impact current users who rely on custom header fields to inform dynamic decisions within their user interceptors. The desired request decoration process should follow this sequence:
When we reach step 3, the custom headers should already be integrated into the URLRequest. |
Apologies in advance if I'm misunderstanding this.... While that may work for AuthTokenURLInterceptor, one thing to consider is if that breaks IAMURLRequestInterceptor? According to SigV4 specification[1], Content-Type header must included while computing signature, if present. With your approach if someone did the following while using IAM Auth (which is actually what I'm doing in my original bug report sans IAM Auth):
Assuming the library signs Content-Type header, IAMURLRequestInterceptor would sign with I haven't peeled enough layers of the library back to confirm the following:
|
More and more, I think the fact that the IAMURLRequestInterceptor and AuthTokenURLRequestInterceptor setting Content-Type is more headache than it is worth and not intuitive. They shouldn't need to care about the Content-Type, they should only care about setting the headers that they "own" (Authorization, x-Amz-Date, are examples of headers they could own). Content-Type is not a header they should own and blindly set. If the library cares about setting a default Content-Type, it should set it before the interceptors run, which it already is based on an earlier comment[1]. If the user chooses to change a signed Header value in their custom interceptor later, that is on the user and it's at least not the library doing something wrong. Ideally there'd be a way to detect that and emit a warning log to the user, but whatever. [1] #3190 (review) |
Yep, you and @atierian are correct. I didn't know the sigv4 calculate the signature including the |
Codecov Report
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. @@ Coverage Diff @@
## main #3190 +/- ##
==========================================
+ Coverage 64.56% 64.77% +0.21%
==========================================
Files 1090 1091 +1
Lines 37005 37051 +46
==========================================
+ Hits 23891 24000 +109
+ Misses 13114 13051 -63
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 18 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
AmplifyPlugins/API/Sources/AWSAPIPlugin/Configuration/AWSAPIEndpointInterceptors.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/API/Sources/AWSAPIPlugin/Configuration/AWSAPIEndpointInterceptors.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/API/Sources/AWSAPIPlugin/Configuration/AWSAPIEndpointInterceptors.swift
Show resolved
Hide resolved
AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSGraphQLOperation.swift
Show resolved
Hide resolved
...ugins/API/Sources/AWSAPIPlugin/Interceptor/RequestInterceptor/IAMURLRequestInterceptor.swift
Show resolved
Hide resolved
AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSRESTOperation.swift
Outdated
Show resolved
Hide resolved
* main: fix(core): add Foundation HTTP client for watchOS / tvOS (#3230) chore: finalize release 2.18.0 [skip ci] chore: release 2.18.0 [skip ci] feat: Setting mininum watchOS version to 9 (#3229) change swift-tools-version to 5.7 (#3193) chore: finalize release 2.17.2 [skip ci] chore: release 2.17.2 [skip ci] fix(datastore): use unwrapped storageEngine to perform datastore operations (#3204) fix(datastore): using URLProtocol monitor auth request headers (#3221) ci: add dependency review workflow (#3132) fix(api): change request interceptors applying logic (#3190)
Issue #
#3184
Description
The existing implementation of the URLRequest interceptor proceeds as follows:
However, this approach has certain issues. For instance, one of the Amplify predefined interceptors requires the calculation of the Sigv4 authentication header for the request. This calculation involves certain headers. Making it impossible for customers to modify these header fields within their own custom interceptors.
After some discussions, we have divided the library predefined interceptors into prelude and postlude interceptors, and the interceptor logic should be as follows:
This updated logic ensures that customer-defined interceptors will be applied with the expected customized headers and the postlude interceptors will operate on the correct request after customer-defined interceptors have been applied.
General Checklist
Given When Then
inline code documentation and are named accordinglytestThing_condition_expectation()
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.