Skip to content
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

Feature/decoder interceptor to response interceptor #2116

Conversation

iain-henderson
Copy link
Contributor

@iain-henderson iain-henderson commented Jul 3, 2023

I utilize Feign to implement REST clients and have a need to extract the location header from some 300 series HTTP responses.

So far, we have found four ways to implement this behavior:

  • Return a Response object and extract the header information. This is the current method I am using, but it short circuits the retry logic contained in Feign for 429 and 503 HTTP responses. I have re-implemented this logic, but that is less than ideal.
  • Implement a custom client and map 3xx responses to a 2xx response (perhaps 204). This is effective, but it is a lie (albeit a white lie) and leads to an unexpected Decoder implementation that pulls the location header from 204 HTTP responses. This will not immediately make sense.
  • Update Feign to allow a configurable RedirectionDecoder. This would be effective but seems to have limited usefulness.
  • Update Feign to change when the ResponseInterceptor is called. Currently the ResponseInterceptor is wrapped around the decode operations. This means that the ResponseInterceptor is not called if the HTTP response is not in the 200 series (or a 404). It is also not called if the return type is Response. Functionally, the ResponseInterceptor is a decode interceptor, rather than a response interceptor. This solution is more flexible than a Redirectiondecoder would be and should enable many workflows.

This pull request updates when ResponseInterceptor is called to intercept responses before they are processed (much as RequestInterceptor does).

Because this change requires changing the signature of the functional method of ResponseInterceptor, that signature has been updated to match the parallel method in RequestInterceptor (method name changed as well as the exception thrown).

Summary by CodeRabbit

  • New Feature: Added RedirectionInterceptor class to handle redirection responses, extracting the "Location" header and returning it as a result.
  • Refactor: Updated InvocationContext class with new constructor parameters and methods for improved error handling and response decoding.
  • Refactor: Modified ResponseHandler class to incorporate logic from removed methods into handleResponse method.
  • Refactor: Updated ResponseInterceptor interface to use InvocationContext parameter instead of Context.
  • Test: Added new test cases in FeignTest for decoding void responses, handling redirection and error responses.
  • Chore: Updated Maven compiler plugin configuration to ensure Java 11 compatibility.

iain-henderson and others added 2 commits June 29, 2023 15:09
…same manner that RequestInterceptor does) rather than intercepting the decoding process.

Signed-off-by: Iain Henderson <Iain.henderson@mac.com>
Copy link
Member

@velo velo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the change, is a massive change on current behavior, but seems a step on the right way, thanks for it.

Can we just restore the original name to avoid breaking any implementations out there...

Also, can we get a test for "error" interception?

core/src/main/java/feign/ResponseInterceptor.java Outdated Show resolved Hide resolved
@iain-henderson
Copy link
Contributor Author

Sorry for the delay, I will undo the rename and throw together a test

@iain-henderson
Copy link
Contributor Author

Tests have been added and README updated

@coderabbitai
Copy link

coderabbitai bot commented Aug 14, 2023

Walkthrough

This pull request introduces significant changes to the Feign library, primarily focusing on enhancing response handling. A new RedirectionInterceptor class is added for redirection responses, and the InvocationContext class is expanded with additional parameters and methods. The ResponseHandler class is refactored for improved control flow and error handling. Test coverage is also extended with new test cases.

Changes

File(s) Summary
README.md Added a new section on Response Interceptors in the Feign documentation.
core/src/main/java/feign/InvocationContext.java
core/src/main/java/feign/ResponseHandler.java
Enhanced InvocationContext with new parameters and methods. Refactored ResponseHandler for better control flow and error handling.
core/src/main/java/feign/RedirectionInterceptor.java Introduced a new RedirectionInterceptor class to handle redirection responses.
core/src/test/java/feign/FeignTest.java Extended test coverage with new test cases for decoding void responses, response interceptors, and error handling.
core/pom.xml Updated Maven compiler plugin configuration to ensure Java 11 compatibility.
core/src/main/java/feign/... (miscellaneous files) Minor formatting and organization changes in various classes.

🐇💻

Code hopping through the fields of change,

Enhancements bloom, isn't it strange?

With every commit, we rearrange,

In the garden of software, nothing out of range! 🌼🎉


Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • Mention @coderabbitai in any review comment for bot assistance. The bot stays silent unless called upon.
  • Note: Review comments are made on code diffs or files, not on the PR overview.

Pause Incremental Reviews

  • Insert @coderabbitai: ignore in the PR description to halt the bot's ongoing reviews. Remove the line to resume.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

Commits Files that changed from the base of the PR and between c65915b and 4315cc1 commits.
Files selected for processing (6)
  • README.md (1 hunks)
  • core/src/main/java/feign/InvocationContext.java (2 hunks)
  • core/src/main/java/feign/RedirectionInterceptor.java (1 hunks)
  • core/src/main/java/feign/ResponseHandler.java (4 hunks)
  • core/src/main/java/feign/ResponseInterceptor.java (1 hunks)
  • core/src/test/java/feign/FeignTest.java (7 hunks)
Files skipped from review due to trivial changes (1)
  • README.md
Review comments generated (11)
  • Actionable : 11
  • LGTM (Skipped): 1
  • Noise Suppression (Skipped): 6

Tips

Chat with Image description CodeRabbit Bot (@coderabbitai)

  • Tag the bot with @coderabbitai in any review comment to ask it questions. The bot will not respond unless explicitly tagged.
  • A review comment is a comment on a diff or a file and not a comment on the PR itself.
  • You can use the mouse to select multiple lines of code to provide exact context to the bot.

Code suggestions

  • The bot may make code suggestions, but please review them carefully before committing since the line number ranges may be misaligned.
  • You can edit the comment made by the bot and manually tweak the suggestion if it is slightly off.

Pausing incremental reviews

  • Add @coderabbitai: ignore anywhere in the PR description to pause further reviews from the bot.

core/src/main/java/feign/ResponseInterceptor.java Outdated Show resolved Hide resolved
core/src/main/java/feign/ResponseHandler.java Outdated Show resolved Hide resolved
core/src/main/java/feign/RedirectionInterceptor.java Outdated Show resolved Hide resolved
core/src/main/java/feign/RedirectionInterceptor.java Outdated Show resolved Hide resolved
core/src/main/java/feign/RedirectionInterceptor.java Outdated Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Outdated Show resolved Hide resolved
@velo velo closed this Aug 14, 2023
@iain-henderson
Copy link
Contributor Author

Um... why was this closed?

@velo
Copy link
Member

velo commented Aug 15, 2023

Um... why was this closed?

My bad, misclicked

@velo velo reopened this Aug 15, 2023
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 4

Commits Files that changed from the base of the PR and between 4315cc1 and 2da31ac commits.
Files selected for processing (2)
  • core/src/main/java/feign/RedirectionInterceptor.java (1 hunks)
  • core/src/test/java/feign/FeignTest.java (7 hunks)
Additional comments (Suppressed): 5
core/src/main/java/feign/RedirectionInterceptor.java (2)
  • 29-52: The aroundDecode method is handling redirection responses by checking the status code and "Location" header. However, it's not considering the possibility of multiple redirections. If there are multiple "Location" headers, only the first one is used. This might lead to incorrect behavior if the first location redirects to another location. Consider handling this scenario.

  • 46-51: As per the previous conversation chain, you've mentioned that the response must remain open in case it will be further processed. However, it's important to ensure that the response is closed at some point to avoid resource leaks. If the response isn't being closed here, make sure it's being closed elsewhere after it's no longer needed.

core/src/test/java/feign/FeignTest.java (3)
  • 1011-1019: The test decodeVoid() is verifying that the decode() method of the mockDecoder is called once when api.body(emptyList()) is invoked. However, there is no assertion to check the return value of api.body(emptyList()). As per the conversation chain, it's mentioned that there is no value to return. If this is the case and the function is void, then this comment can be disregarded.

  • 1022-1051: These tests redirectionInterceptorString(), redirectionInterceptorCollection(), responseInterceptor400Error(), and responseInterceptor500Error() are well written and cover different scenarios for the new RedirectionInterceptor and ErrorInterceptor classes. They ensure that the interceptors correctly handle redirection responses and error responses respectively.

  • 1326-1339: The ErrorInterceptor class implements the ResponseInterceptor interface and overrides the aroundDecode() method. This method checks if the response status is 300 or above, and if the return type is String, it reads the body of the response and returns it as a string. Otherwise, it proceeds with the invocation context. This implementation seems correct and handles different scenarios properly.

core/src/main/java/feign/RedirectionInterceptor.java Outdated Show resolved Hide resolved
core/src/main/java/feign/RedirectionInterceptor.java Outdated Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 2

Commits Files that changed from the base of the PR and between 2da31ac and c1fc84c commits.
Files selected for processing (2)
  • core/src/main/java/feign/RedirectionInterceptor.java (1 hunks)
  • core/src/test/java/feign/FeignTest.java (11 hunks)
Additional comments (Suppressed): 4
core/src/main/java/feign/RedirectionInterceptor.java (1)
  • 46-51: As per the previous comment chain, the response should remain open if it will be further processed. However, it's important to ensure that the response is closed at some point to avoid resource leaks. Please verify that the response is being closed elsewhere in the code after it has been fully processed.
core/src/test/java/feign/FeignTest.java (3)
  • 952-953: There seems to be a typo in the method name in the old hunk (queryMapEndcoder). It has been corrected in the new hunk (queryMapEncoder). Please ensure that all calls to this method throughout the codebase have been updated to match the new method name.

  • 1317-1320: These methods are returning the instance of the current object using this. This is a common practice when designing classes with a fluent interface or builders. The methods modify the state of the object and then return the same object, allowing the operations to be chained together.

  • 1327-1340: This class ErrorInterceptor implements the ResponseInterceptor interface and overrides the aroundDecode method. If the response status is greater than or equal to 300, it checks if the return type is String. If so, it reads the body of the response into a string and returns it. Otherwise, it proceeds with the invocation context. This interceptor can be useful for handling error responses where the body contains a message or additional details about the error.

core/src/main/java/feign/RedirectionInterceptor.java Outdated Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Outdated Show resolved Hide resolved
velo and others added 2 commits August 29, 2023 07:53
…decoder-interceptor-to-response-interceptor

# Conflicts:
#	core/src/main/java/feign/InvocationContext.java
#	core/src/main/java/feign/ResponseHandler.java
#	core/src/main/java/feign/ResponseInterceptor.java
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Commits Files that changed from the base of the PR and between c1fc84c and ec675b9 commits.
Files selected for processing (8)
  • core/pom.xml (1 hunks)
  • core/src/main/java/feign/RedirectionInterceptor.java (1 hunks)
  • core/src/main/java/feign/Request.java (2 hunks)
  • core/src/main/java/feign/ResponseHandler.java (3 hunks)
  • core/src/main/java/feign/ResponseInterceptor.java (3 hunks)
  • core/src/main/java/feign/ResponseMapper.java (1 hunks)
  • core/src/test/java/feign/DefaultContractTest.java (1 hunks)
  • core/src/test/java/feign/FeignTest.java (11 hunks)
Files skipped from review due to trivial changes (4)
  • core/pom.xml
  • core/src/main/java/feign/Request.java
  • core/src/main/java/feign/ResponseMapper.java
  • core/src/test/java/feign/DefaultContractTest.java
Additional comments (Suppressed): 16
core/src/main/java/feign/RedirectionInterceptor.java (1)
  • 50-51: Closing the response stream manually might not be necessary if you're using try-with-resources or similar resource management. If you're not, consider adding error handling around this operation as it can throw an IOException.
core/src/main/java/feign/ResponseInterceptor.java (3)
  • 37-37: The intercept method now throws a generic Exception instead of an IOException. This change could potentially break existing implementations of the ResponseInterceptor interface that are only handling IOException. Ensure all implementations of this interface have been updated to handle the more general Exception.

  • 54-64: The default implementation of the Chain interface has been simplified. It no longer handles decoding or exceptions explicitly, which might affect error handling and reporting in your application. Make sure that these responsibilities are properly handled elsewhere in your code.

  • 72-74: This part of the code remains unchanged and looks good as it is.

core/src/main/java/feign/ResponseHandler.java (3)
  • 60-75: The new implementation of the handleResponse method has removed the checks for whether the response should be decoded based on the status code and return type. This could potentially lead to issues if the response is not suitable for decoding. Please ensure that this change does not introduce any unexpected behavior.
-      if (returnType == Response.class) {
-        return disconnectResponseBodyIfNeeded(response);
-      }
-
-      final boolean shouldDecodeResponseBody = (response.status() >= 200 && response.status() < 300)
-          || (response.status() == 404 && dismiss404 && !isVoidType(returnType));
-
-      if (!shouldDecodeResponseBody) {
-        throw decodeError(configKey, response);
-      }
-
-      return decode(response, returnType);
  • 30-32: The constant MAX_RESPONSE_BUFFER_SIZE has been removed from the class. If this constant was used elsewhere in the codebase, it might cause compilation errors or unintended behavior. Please verify that this removal doesn't affect other parts of the code.

  • 84-87: The methods disconnectResponseBodyIfNeeded, decode, decodeError, and isVoidType have been removed from the class. These methods provided functionality for handling the response body and decoding the response. Ensure that their removal doesn't impact the functionality of the class and that their logic has been incorporated elsewhere as necessary.

core/src/test/java/feign/FeignTest.java (9)
  • 62-62: The mockDecoder is declared and initialized correctly. The previous comment chain indicates a misunderstanding, as the mockDecoder is indeed initialized with a mock object.

  • 902-902: There was a typo in the method name queryMapEndcoder which has been corrected to queryMapEncoder. This change should be verified across the codebase to ensure that all calls to this method have been updated.

  • 918-918: There was a typo in the method name queryMapEndcoder which has been corrected to queryMapEncoder. This change should be verified across the codebase to ensure that all calls to this method have been updated.

  • 937-937: There was a typo in the method name queryMapEndcoder which has been corrected to queryMapEncoder. This change should be verified across the codebase to ensure that all calls to this method have been updated.

  • 952-952: There was a typo in the method name queryMapEndcoder which has been corrected to queryMapEncoder. This change should be verified across the codebase to ensure that all calls to this method have been updated.

  • 1011-1020: This test case verifies that the decode() method of the mockDecoder is called once when api.body(emptyList()) is invoked. However, there is no assertion to check the return value of api.body(emptyList()). As per the conversation chain, it's clarified that there is no value to return, so the test performs as expected.

  • 1287-1289: A new method responseInterceptor(ResponseInterceptor responseInterceptor) has been added to the TestInterfaceBuilder class. Ensure that this method is used correctly throughout the codebase.

  • 1312-1314: A new method decodeVoid() has been added to the TestInterfaceBuilder class. Ensure that this method is used correctly throughout the codebase.

  • 1327-1340: A new class ErrorInterceptor implementing ResponseInterceptor interface has been added. It overrides the intercept method to handle responses with status codes 300 and above. If the return type is String, it reads the body of the response and returns it. Otherwise, it proceeds to the next interceptor in the chain. This implementation seems correct and efficient.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Commits Files that changed from the base of the PR and between ec675b9 and dc1e3b7 commits.
Files selected for processing (1)
  • core/src/test/java/feign/FeignTest.java (11 hunks)
Additional comments (Suppressed): 8
core/src/test/java/feign/FeignTest.java (8)
  • 901-905: Good job on fixing the typo from queryMapEndcoder to queryMapEncoder. This will prevent potential runtime errors due to calling an undefined method.

  • 917-921: Good job on fixing the typo from queryMapEndcoder to queryMapEncoder. This will prevent potential runtime errors due to calling an undefined method.

  • 936-940: Good job on fixing the typo from queryMapEndcoder to queryMapEncoder. This will prevent potential runtime errors due to calling an undefined method.

  • 949-953: Good job on fixing the typo from queryMapEndcoder to queryMapEncoder. This will prevent potential runtime errors due to calling an undefined method.

  • 1011-1022: Ensure that all calls to this function throughout the codebase have been updated to match the new signature.

  • 1337-1345: The newly added methods responseInterceptor and responseInterceptors in the TestInterfaceBuilder class are good additions for setting response interceptors. They improve the flexibility and configurability of the test interface builder.

  • 1367-1375: The newly added method decodeVoid in the TestInterfaceBuilder class is a good addition for setting the decode void behavior. It improves the flexibility and configurability of the test interface builder.

  • 1382-1396: The new ErrorInterceptor class provides a way to handle HTTP responses with status codes 300 and above. It's a good practice to handle such responses separately as they often indicate client or server errors. However, ensure that this new interceptor is properly integrated into the Feign client setup.

core/src/test/java/feign/FeignTest.java Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 6

Commits Files that changed from the base of the PR and between dc1e3b7 and 6fa78d7 commits.
Files selected for processing (6)
  • core/pom.xml (1 hunks)
  • core/src/main/java/feign/Logger.java (1 hunks)
  • core/src/main/java/feign/Request.java (1 hunks)
  • core/src/main/java/feign/template/Template.java (1 hunks)
  • core/src/test/java/feign/FeignTest.java (11 hunks)
  • core/src/test/java/feign/MultipleLoggerTest.java (3 hunks)
Files skipped from review due to trivial changes (4)
  • core/pom.xml
  • core/src/main/java/feign/Logger.java
  • core/src/main/java/feign/Request.java
  • core/src/main/java/feign/template/Template.java
Additional comments (Suppressed): 8
core/src/test/java/feign/FeignTest.java (8)
  • 902-902: Good job on fixing the typo in the method name from queryMapEndcoder to queryMapEncoder.

  • 918-918: Good job on fixing the typo in the method name from queryMapEndcoder to queryMapEncoder.

  • 937-937: Good job on fixing the typo in the method name from queryMapEndcoder to queryMapEncoder.

  • 952-952: Good job on fixing the typo in the method name from queryMapEndcoder to queryMapEncoder.

  • 1011-1020: This test case verifies that the decode() method of the mockDecoder is called once when api.body(emptyList()) is invoked. However, there is no assertion to check the return value of api.body(emptyList()). Consider adding an assertion to verify the expected return value.

Object result = api.body(emptyList());
verify(mockDecoder, times(1)).decode(ArgumentMatchers.any(), eq(void.class));
assertEquals("Expected result", result);
  • 1337-1345: These methods are added to allow setting a single ResponseInterceptor or multiple ResponseInterceptors in the TestInterfaceBuilder. This is a good practice as it allows for flexibility and extensibility in testing different scenarios with different interceptors.

  • 1367-1370: The decodeVoid() method has been added to the TestInterfaceBuilder class. This method sets the decodeVoid flag in the Feign builder, which controls whether void methods should be decoded. This is a useful addition for testing scenarios where the response body is not important and can be ignored.

  • 1382-1395: The ErrorInterceptor class is a custom ResponseInterceptor implementation that extracts the response body as a string if the status code is 300 or above. This is a good practice for handling error responses in a custom way.

core/src/test/java/feign/MultipleLoggerTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/MultipleLoggerTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/MultipleLoggerTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/MultipleLoggerTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/MultipleLoggerTest.java Outdated Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 5

Commits Files that changed from the base of the PR and between 6fa78d7 and e5b2308 commits.
Files selected for processing (2)
  • core/src/main/java/feign/Request.java (2 hunks)
  • core/src/test/java/feign/FeignTest.java (10 hunks)
Files skipped from review due to trivial changes (1)
  • core/src/main/java/feign/Request.java
Additional comments (Suppressed): 4
core/src/test/java/feign/FeignTest.java (4)
  • 18-29: The import statements have been rearranged and some new ones have been added. Ensure that all the newly imported classes are used in the code and that there are no unused imports.

  • 35-55: The import statements have been rearranged and some new ones have been added. Ensure that all the newly imported classes are used in the code and that there are no unused imports.

  • 1336-1344: New methods responseInterceptor and responseInterceptors have been added to the TestInterfaceBuilder class. Ensure that these methods are used correctly in the test cases and that they function as expected.

  • 1381-1395: A new inner class ErrorInterceptor has been added. This class implements the ResponseInterceptor interface and overrides the intercept method. Ensure that this class is used correctly in the test cases and that it functions as expected.

core/src/test/java/feign/FeignTest.java Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Show resolved Hide resolved
core/src/test/java/feign/FeignTest.java Show resolved Hide resolved
core/pom.xml Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 2

Commits Files that changed from the base of the PR and between e5b2308 and 008fc77 commits.
Files selected for processing (2)
  • core/src/main/java/feign/RedirectionInterceptor.java (1 hunks)
  • core/src/main/java/feign/ResponseInterceptor.java (3 hunks)
Additional comments (Suppressed): 3
core/src/main/java/feign/ResponseInterceptor.java (3)
  • 33-33: The method signature has changed from Object intercept(Context context, Chain chain) throws IOException; to Object intercept(InvocationContext invocationContext, Chain chain) throws Exception;. Ensure that all calls to this function throughout the codebase have been updated to match the new signature and that they handle the more general Exception instead of just IOException.

  • 59-59: The method signature has changed from Object next(Context context) throws IOException; to Object next(InvocationContext context) throws Exception;. Ensure that all calls to this function throughout the codebase have been updated to match the new signature and that they handle the more general Exception instead of just IOException.

  • 51-51: The default implementation of the Chain interface has been simplified. This could potentially lead to different behavior if the previous implementation was relied upon. Verify that this change does not introduce any unexpected behavior.

@velo velo merged commit 3d5f5ec into OpenFeign:master Sep 5, 2023
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants