Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Java] Templates to support google-api-client library #6838

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

Merged
wing328 merged 14 commits into swagger-api:master from charlescapps:google-api-client-codegen
Nov 3, 2017

Conversation

@charlescapps
Copy link
Contributor

@charlescapps charlescapps commented Oct 27, 2017
edited
Loading

PR checklist

  • Read the contribution guidelines.
  • Ran the shell script under ./bin/ to update Petstore sample so that CIs can verify the change. (For instance, only need to run ./bin/{LANG}-petstore.sh and ./bin/security/{LANG}-petstore.sh if updating the {LANG} (e.g. php, ruby, python, etc) code generator or {LANG} client's mustache templates). Windows batch files can be found in .\bin\windows\.
  • Filed the PR against the correct branch: 3.0.0 branch for changes related to OpenAPI spec 3.0. Default: master.
  • Copied the technical committee to review the pull request if your PR is targeting a particular programming langauge.

@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09)

Description of the PR

See issue #6825
This PR adds support for generating client code for the Google APIs Client for Java. This HTTP client is not just for Google's APIs, as you can read in the description of their page:

The Google APIs Client Library for Java is a flexible, efficient, and powerful Java client library for accessing any HTTP-based API on the web, not just Google APIs.

Motivation

The google-api-client is really standard in GCP for making HTTP requests. It works great with authentication in GCP (or outside GCP), by automatically handling refresh tokens with the google Credential class. Furthermore, this provides a clear upgrade path for anyone on Google Cloud Endpoints who wants to migrate to a better REST framework, since Cloud Endpoints uses the google-api-client.

Changes in this PR

  • Add a new library to the Java client codegen called google-api-client
  • Templates under modules/swagger-codegen/src/main/resources/Java/libraries/google-api-client
  • A minor tweak to DefaultCodegen to have a list of required/body params, so the client can generate overloaded methods that use a Map<String, Object> for query params.
  • Generated the samples for google-api-client, and verified they compile, etc.

Features of the generated Google ApiClient

  • Nice builder-style pattern e.g. apiClient.myFooApi().doSomeRequest(params...)
  • Generates overloaded API methods to specify query params as a Map<String, Object>, and methods ending in forHttpResponse that return the raw HttpResponse rather than deserializing as a POJO.
  • Configurable basePath, HttpTransport, HttpRequestInitializer (used for auth), and ObjectMapper.
  • Uses a standard Jackson ObjectMapper Instead of using the problematic Google-custom-Jackson (e.g.com.google.api.client.json.jackson2.JacksonFactory)
  • Does not generate auth-related classes under the auth package, because I'm not sure what that would gain us; it's really straightforward to use an HttpRequestInitializer to provide and access token, e.g. you can use com.google.api.client.auth.oauth2.Credential and it can also do token refreshes automatically (or just use an access token if that's all you have).

cc: @drd

Copy link
Contributor

@JFCote JFCote left a comment

Choose a reason for hiding this comment

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

I did a quick check. Look goods to me. I just have some points that needs clarification. Thanks for the PR.

supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java"));
supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java"));
// google-api-client doesn't use the Swagger auth, because it uses Google Credential directly (HttpRequestInitializer)
if (!"google-api-client".equals(getLibrary())) {
Copy link
Contributor

@JFCote JFCote Oct 30, 2017
edited
Loading

Choose a reason for hiding this comment

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

I think this should go in the GoogleApiClientCodegen.java since it's only useful for your generator.

Copy link
Contributor Author

@charlescapps charlescapps Oct 30, 2017

Choose a reason for hiding this comment

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

Okay, I'll do that right now, sounds like a plan.

Copy link
Contributor Author

@charlescapps charlescapps Oct 30, 2017
edited
Loading

Choose a reason for hiding this comment

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

FYI this is following the existing pattern. There actually aren't any subclasses of JavaClientCodegen; it uses if-statements on the library throughout to determine the configuration of each library. I'd have to figure out how to support a new subclass, it looks like it uses reflection to instantiate the JavaClientCodegen with the classes listed in modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig

}

if (!("feign".equals(getLibrary()) || "resttemplate".equals(getLibrary()) || usesAnyRetrofitLibrary())) {
if (!("feign".equals(getLibrary()) || "resttemplate".equals(getLibrary()) || usesAnyRetrofitLibrary() || "google-api-client".equals(getLibrary()))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

oh I see other library has done it too... @wing328, is this normal? Since we are using objects, we should'nt have any "if" in the JavaClientCodegen... It should all be in specific file of each generator...
Or there is a good reason for this ??

Copy link
Contributor Author

@charlescapps charlescapps Oct 30, 2017

Choose a reason for hiding this comment

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

Yeah, it appears there are no subclasses of JavaClientCodegen, see above comment, @wing328 probably has a more complete explanation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok. It's weird because for example, for the server generator "java play framework" which I maintain, there is:
JavaPlayFrameworkCodegen -> AbstractJavaCodegen -> DefaultCodegen.
This prevent having "if" everywhere.

Same thing for Typescript jQuery which I maintain too:
TypeScriptJqueryClientCodegen -> AbstractTypeScriptClientCodegen -> DefaultCodegen

I wonder why the JavaClientCodegen are all mixed in one file.
For the moment, don't change anything. We will see with @wing328 answers :)

Copy link
Contributor Author

@charlescapps charlescapps Oct 30, 2017

Choose a reason for hiding this comment

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

That makes sense. Yeah, a refactor into subclasses probably belongs in a separate pull request, but I'm game to do whatever you suggest.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is ok for now and belong in another pull request like you said. :)

Copy link
Contributor

@wing328 wing328 Nov 2, 2017

Choose a reason for hiding this comment

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

When we added support for other HTTP libraries, we didn't foresee we can support so many libraries (9 HTTP libraries support so far thanks to the awesome community). I agree a separate PR to refactor into subclasses would be ideal.

Copy link
Contributor Author

@charlescapps charlescapps Nov 3, 2017

Choose a reason for hiding this comment

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

That makes sense. Is this waiting on any additional reviews? Let me know if any more changes are needed here. Thanks! This will really help out our company in our migration to use Swagger clients for all of our service-to-service communication. (And possibly we could use this for our Android app, too).

Copy link
Contributor

@wing328 wing328 Nov 3, 2017

Choose a reason for hiding this comment

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

@charlescapps I'll take another look later today and merge accordingly.

public List<CodegenParameter> queryParams = new ArrayList<CodegenParameter>();
public List<CodegenParameter> headerParams = new ArrayList<CodegenParameter>();
public List<CodegenParameter> formParams = new ArrayList<CodegenParameter>();
public List<CodegenParameter> requiredParams = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you need to put CodegenParameter in the ArrayList to be able to compile swagger-codegen in Java < 1.7

Copy link
Contributor Author

@charlescapps charlescapps Oct 30, 2017

Choose a reason for hiding this comment

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

Will do right now! Yes, makes sense to support 1.6.

public class CodegenOperation {
public final List<CodegenProperty> responseHeaders = new ArrayList<CodegenProperty>();
public boolean hasAuthMethods, hasConsumes, hasProduces, hasParams, hasOptionalParams,
public boolean hasAuthMethods, hasConsumes, hasProduces, hasParams, hasOptionalParams,hasRequiredParams,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm surprised this is needed. Most generator use the params array and loop with "isRequired" to build almost everything. Is there any specific reason to add this to the "generic code"?

Copy link
Contributor Author

@charlescapps charlescapps Oct 30, 2017
edited
Loading

Choose a reason for hiding this comment

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

Yeah, you can check {{isRequired}} but that's not sufficient, because we use {{hasNext}} to see if there's a subsequent element, and that isn't aware of isRequired, so it was generating code with 2 commas in a row.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok makes sense!

Copy link
Contributor

wing328 commented Nov 3, 2017

@charlescapps thanks for the PR, which looks good to me and my test results are good.

cc @lwander

@wing328 wing328 merged commit c2eb53a into swagger-api:master Nov 3, 2017
Copy link
Contributor

wing328 commented Nov 3, 2017

UPDATE: Added the new Java API client to CircleCI via cf5eba8

Copy link
Contributor Author

Thanks for being so responsive. I'm excited to use this new client, now we won't need to build from a fork.

wing328 reacted with thumbs up emoji

Copy link
Contributor

wing328 commented Nov 4, 2017

@charlescapps FYI. I've filed #6885 to skip the check for body parameter, which can be optional

Ref: #6878

Copy link
Contributor

wing328 commented Nov 9, 2017

@charlescapps looks like #6885 introduces an issue. In the latest master, I ran ./bin/java-petstore-google-api-client.sh to update the Java (google-api-client) Petstore sample and notice some changes. Here is the diff for one of them:

 return apiClient.getHttpRequestFactory().buildRequest(HttpMethods.POST, genericUrl, content).execute();
 }
 
- public HttpResponse fakeOuterBooleanSerializeForHttpResponse(Boolean body, Map<String, Object> params) throws IOException {
+ public HttpResponse fakeOuterBooleanSerializeForHttpResponse(Map<String, Object> params) throws IOException {
 Object postBody = body;
 
 UriBuilder uriBuilder = UriBuilder.fromUri(apiClient.getBasePath() + "/fake/outer/boolean");```

May I know if you've time to take a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

2 more reviewers

@wing328 wing328 wing328 left review comments

@JFCote JFCote JFCote left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Projects

None yet

Milestone

v2.3.0

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /