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

feat: Add ODP GraphQL Api Interface #481

Merged
merged 6 commits into from
Aug 2, 2022

Conversation

zashraf1985
Copy link
Contributor

Summary

  1. Added an ODPApiManager interface and its Default implementation that implements the graphQL call to fetch qualified segments.
  2. The mechanism to get default parser is tightly coupled with Project Config module. I created a separate Factory class to get the default parser. This can be used by any future implementations that need a default parser.
  3. Added parsing for all four supported parsers to parse valid and error responses.

Test plan

  1. Added new unit tests to test all the new code.
  2. Existing unit tests pass
  3. Existing Full stack compatibility suite tests pass

Issues

OASIS-8384

@zashraf1985 zashraf1985 requested a review from a team as a code owner July 29, 2022 21:16
@zashraf1985 zashraf1985 removed their assignment Jul 29, 2022
}
*/
@Override
public String fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, List<String> segmentsToCheck) {
Copy link

Choose a reason for hiding this comment

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

Name "fetchQualifiedSegments" is already used in upcoming "ODPSegmentManager" (per Jae's naming). Risk of name conflict. Unless you use different names, but that might be a deviation from naming consistency across SDKs?

import java.util.List;

public interface ODPApiManager {
String fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, List<String> segmentsToCheck);
Copy link

Choose a reason for hiding this comment

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

Name already "reserved" for the method in ODPSegmentManager? This one should be fetchSegments, no? (consistency across SDKs)

Copy link

Choose a reason for hiding this comment

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

Not 100% sure, maybe I'm wrong... you have ODPAPIManager interface that defines fetchQualifiedSegments method, but there is also method fetchSegments in Swift PR that is located in the GraphQL API Manager. Not sure how you are overriding, but it seems smth not quite right...unless it's my weak java knowledge

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Design of java is a little different than other sdks. For all the external calls, we need to create an interface and pass it in to the core SDK from the outside. That is why i created ODPAPIManager which is an interface that will contain all the external calls such as graphQL and ODPEvents. Then i am providing a DefaultODPApiManager as a default implementation. user will use this by default but can pass in their own implementation. To me fethQualifiedSegments makes more sense because thats exactly what this call does. It fetches the qualified segments not all or just any segments.

logbackVerifier.expectMessage(Level.ERROR, "Unexpected response from ODP server, Response code: 500, null");
assertEquals(null, responseString);
}
}
Copy link

Choose a reason for hiding this comment

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

What about the test for network issues, such as internet is down, where status code is not returned. Request is not reaching the server and bounces off?

Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

A refactoring for sharing multiple JSON parsers suggested if it's not too much.
I need to see the next stage to see how you want to implement all. It looks good as is!

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public enum JsonParserProvider {
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good! Just wondering if there is a smart way to reuse the same code for DefaultConfigParser. It is quite complicated currently supporting multiple parsers and this repeated code will make it worse :)

Copy link
Contributor Author

@zashraf1985 zashraf1985 Aug 2, 2022

Choose a reason for hiding this comment

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

I wanted to reuse code from there but it was tightly coupled. I wanted to refactor DefaultConfigParser to use this one but i thought i will add a comment and do that later as a separate ticket. Right now it will become too much work. what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea is to make DefaultConfigParser and whatever else needs a parser use this code eventually. i am just too afraid to touch DafaultConfigParser in this PR

Copy link
Contributor

Choose a reason for hiding this comment

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

I leave it to you.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool! I will add a comment in the DefaultConfigParser mentioning the same. I will also add a ticket to refactor this and put it in the tech debt backlog.

logMessage.append(errors.get(i).getAsJsonObject().get("message").getAsString());
}
logger.error(logMessage.toString());
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Collecting error messages looks good. For other SDKs (swift and go), extracting "InvalidIdentifierException" from error "classification" and passing back to clients is important. Not sure how we can pass back this info to callers in Java. We can log in at minimum, but this may be redundant to your error log message already collecting all error messages.

return null;
}

if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What about more generous error checking like ">= 400"?

*/
@Override
public String fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, List<String> segmentsToCheck) {
HttpPost request = new HttpPost(apiEndpoint);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure about the plan to feed endpoint, but needs "/v3/graphql" appended for graphql to the shred apiEndpoint.

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 see this as the lowest level method that will make the actual call that is why it's getting the full endPoint. Users might provide their own implementation so it made more sense for it to expect the full endPoint. My plan is to build this endpoint using the host and path in the ODPSegmentManager and pass it to this one. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

That's what I thought. If we plan to support custom endpoints, this makes sense. Let's move on and review again at the top level.
One thing we also should consider is that if clients want to implement their own segment services (replacing all our default ODPManager), they can determine segments using their own solution and directly feed the "qualifedSegments" into OptimizelyUserContext, instead of injecting own ODPManager into our SDKs.

import java.util.List;

public interface ODPApiManager {
String fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, List<String> segmentsToCheck);
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like you plan to open all ODP APIs here to public for customization support. It looks good for now and we can continue discussion the final apis.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this will contain all the methods that make an external call. ODPEvents calls will also go here

@zashraf1985 zashraf1985 removed their assignment Aug 2, 2022
Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link

@Mat001 Mat001 left a comment

Choose a reason for hiding this comment

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

lgtm

@zashraf1985 zashraf1985 merged commit 618377d into master Aug 2, 2022
@zashraf1985 zashraf1985 deleted the zeeshan/ats-graphql-and-parsers branch August 2, 2022 21:45
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.

3 participants