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

Providing API version header from server to caller when available. #1409

Merged
merged 4 commits into from
Jul 19, 2024

Conversation

OrangeAndGreen
Copy link
Contributor

@OrangeAndGreen OrangeAndGreen commented May 28, 2024

Attempts to safely retrieve the x-api-current-version header from API response payloads so calling code can do version checking.
https://dimagi.atlassian.net/browse/CCCT-239

cross-request: dimagi/commcare-android#2757

@@ -12,7 +12,7 @@ public interface HttpResponseProcessor {
/**
* Http response was in the 200s
*/
void processSuccess(int responseCode, InputStream responseData);
void processSuccess(int responseCode, InputStream responseData, String apiVersion);
Copy link
Contributor

Choose a reason for hiding this comment

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

is apiVersion still required here ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is how I planned to expose the value to the calling code. Specifically, after gets/posts in ConnectNetworkHelper I plan to pass the expected version into the getResponseProcessor call, and check it against the received value included in the processSuccess call here. Does that sound like the right approach?

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, I don't think we need to expose it specifically in processSuccess, instead implementations of processSucess can directly use the responseData to get apiVersion ?

Also I am confused if processSuccess is where callers will be handling apiVersion why are we adding public String getApiVersion() { in here and ModernHTTPTask ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the difference is between the ResponseStreamAccessor and InputStream. The responseData passed up in processSuccess is an InputStream which does not include knowledge of the API version. The ResponseStreamAccessor on the other hand contains both the InputStream and access to the API version. So perhaps the best solution is to have processSuccess include the ResponseStreamAccessor instead of just the InputStream?

The other option I can see is to have code in processSuccess call back to the task to access the API version, but this feels a little odd since existing interaction with the task is mostly about setup rather than handling results. In other words, calling code has to know not to attempt to retrieve the API version until after the call has completed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe a better way to phrase my concern with the second approach: If ModernHttpTask is a ResponseStreamAccessor that allows us access to the InputStream and API string, shouldn't we be accessing both the same way?

So if we're going to pass the InputStream via processSuccess instead of calling myModernHttpTask.getResponseStream, I think the API string should be provided the same way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Something to consider: perhaps instead of implementing ResponseStreamAccessor, both ModernHttpRequester and ModernHttpTask should create and return generic implementations of that interface when calling processResponse.

That way access to the response stream and API version would only be available in the callback (I'm going with the proposal to have processSuccess pass the ResponseStreamAccessor). In other words, it wouldn't be possible for calling code to attempt to access the response stream or API string from the task/requester before actually executing the request.

Copy link
Contributor

Choose a reason for hiding this comment

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

That way access to the response stream and API version would only be available in the callback (I'm going with the proposal to have processSuccess pass the ResponseStreamAccessor). In other words, it wouldn't be possible for calling code to attempt to access the response stream or API string from the task/requester before actually executing the request.

This sounds like a good design choice to me although

perhaps instead of implementing ResponseStreamAccessor, both ModernHttpRequester and ModernHttpTask should create and return generic implementations of that interface when calling processResponse.

I am not super clear what you mean by this and having some pseudo code to look at might be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No problem. The generic ResponseStreamAccessor would be created when calling processResponse in ModernHttpTask and ModernHttpRequester, rather than returning this as the last function input.

For ModernHttpTask, the new code would look like:
image

The class would no longer implement ResponseStreamAccessor, and the getResponseStream and getApiVersion methods at the end of the file would be deleted.

And in places like this, it would no longer be possible to call postTask.getResponseStream before calling connect and executeParallel. Note that I currently don't see this happening anywhere in the code, but the potential is there.

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, that seems promising to me 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented these changes

…amAccessor when call completed instead of implementing it as a class and passing 'this'.
try {
apiVerison = response.headers().get("x-api-current-version");
} catch(Exception e) {
//Ignore exception if API version header isn't present
Copy link
Contributor

Choose a reason for hiding this comment

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

the call response.headers().get("x-api-current-version") doesn't really throw an exception even if "x-api-current-version is not present, as such do we need the catch here ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense, I removed it. I was being a little overly safe!

shubham1g5
shubham1g5 previously approved these changes Jul 19, 2024
Copy link
Contributor

@shubham1g5 shubham1g5 left a comment

Choose a reason for hiding this comment

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

Approving as don't want to block this further but left one comment to address in previous review.

@OrangeAndGreen OrangeAndGreen merged commit 1f7e218 into master Jul 19, 2024
2 checks passed
@OrangeAndGreen OrangeAndGreen deleted the dv/api_versioning branch July 19, 2024 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants