Skip to content

Commit ab5b0fa

Browse files
authored
[Go]: Interface definitions for api functions (#5914)
Introduces a new "generateInterfaces" option, allowing for better testability of generated clients
1 parent 9fd66fb commit ab5b0fa

50 files changed

Lines changed: 3968 additions & 1691 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bin/configs/go-experimental-go-petstore-oas2.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-e
44
templateDir: modules/openapi-generator/src/main/resources/go-experimental
55
additionalProperties:
66
packageName: petstore
7+
generateInterfaces: true

bin/configs/go-experimental-go-petstore.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ additionalProperties:
66
enumClassPrefix: "true"
77
packageName: petstore
88
disallowAdditionalPropertiesIfNotPresent: false
9+
generateInterfaces: true

bin/configs/go-petstore-withXml.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ additionalProperties:
66
packageName: petstore
77
withXml: "true"
88
withGoCodegenComment: "true"
9+
generateInterfaces: true

docs/generators/go-experimental.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ sidebar_label: go-experimental
77
| ------ | ----------- | ------ | ------- |
88
|disallowAdditionalPropertiesIfNotPresent|Specify the behavior when the 'additionalProperties' keyword is not present in the OAS document. If false: the 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. If true: when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.This setting is currently ignored for OAS 2.0 documents: 1) When the 'additionalProperties' keyword is not present in a 2.0 schema, additional properties are NOT allowed. 2) Boolean values of the 'additionalProperties' keyword are ignored. It's as if additional properties are NOT allowed.Note: the root cause are issues #1369 and #1371, which must be resolved in the swagger-parser project.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is automatically set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.</dd></dl>|true|
99
|enumClassPrefix|Prefix enum with class name| |false|
10+
|generateInterfaces|Generate interfaces for api classes| |false|
1011
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
1112
|isGoSubmodule|whether the generated Go module is a submodule| |false|
1213
|packageName|Go package name (convention: lowercase).| |openapi|

docs/generators/go.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ sidebar_label: go
66
| Option | Description | Values | Default |
77
| ------ | ----------- | ------ | ------- |
88
|enumClassPrefix|Prefix enum with class name| |false|
9+
|generateInterfaces|Generate interfaces for api classes| |false|
910
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
1011
|isGoSubmodule|whether the generated Go module is a submodule| |false|
1112
|packageName|Go package name (convention: lowercase).| |openapi|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
4242
protected boolean withXml = false;
4343
protected boolean enumClassPrefix = false;
4444
protected boolean structPrefix = false;
45+
protected boolean generateInterfaces = false;
4546

4647
protected String packageName = "openapi";
4748
protected Set<String> numberTypes;
@@ -780,6 +781,10 @@ public void setStructPrefix(boolean structPrefix) {
780781
this.structPrefix = structPrefix;
781782
}
782783

784+
public void setGenerateInterfaces(boolean generateInterfaces) {
785+
this.generateInterfaces = generateInterfaces;
786+
}
787+
783788
@Override
784789
public String toDefaultValue(Schema schema) {
785790
if (schema.getDefault() != null) {

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoClientCodegen.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public class GoClientCodegen extends AbstractGoCodegen {
4040
public static final String WITH_XML = "withXml";
4141
public static final String STRUCT_PREFIX = "structPrefix";
4242
public static final String WITH_AWSV4_SIGNATURE = "withAWSV4Signature";
43+
public static final String GENERATE_INTERFACES = "generateInterfaces";
4344

4445
public GoClientCodegen() {
4546
super();
@@ -91,6 +92,7 @@ public GoClientCodegen() {
9192
cliOptions.add(CliOption.newBoolean(CodegenConstants.ENUM_CLASS_PREFIX, CodegenConstants.ENUM_CLASS_PREFIX_DESC));
9293
cliOptions.add(CliOption.newBoolean(STRUCT_PREFIX, "whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts"));
9394
cliOptions.add(CliOption.newBoolean(WITH_AWSV4_SIGNATURE, "whether to include AWS v4 signature support"));
95+
cliOptions.add(CliOption.newBoolean(GENERATE_INTERFACES, "Generate interfaces for api classes"));
9496

9597
// option to change the order of form/body parameter
9698
cliOptions.add(CliOption.newBoolean(
@@ -164,6 +166,11 @@ public void processOpts() {
164166
setStructPrefix(Boolean.parseBoolean(additionalProperties.get(STRUCT_PREFIX).toString()));
165167
additionalProperties.put(STRUCT_PREFIX, structPrefix);
166168
}
169+
170+
if (additionalProperties.containsKey(GENERATE_INTERFACES)) {
171+
setGenerateInterfaces(Boolean.parseBoolean(additionalProperties.get(GENERATE_INTERFACES).toString()));
172+
additionalProperties.put(GENERATE_INTERFACES, generateInterfaces);
173+
}
167174
}
168175

169176
/**

modules/openapi-generator/src/main/resources/go-experimental/api.mustache

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,49 +15,77 @@ import (
1515
var (
1616
_ _context.Context
1717
)
18+
{{#generateInterfaces}}
19+
20+
type {{classname}} interface {
21+
{{#operation}}
22+
23+
/*
24+
* {{operationId}}{{#summary}} {{{.}}}{{/summary}}{{^summary}} Method for {{operationId}}{{/summary}}
25+
{{#notes}}
26+
* {{{unescapedNotes}}}
27+
{{/notes}}
28+
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().{{#pathParams}}
29+
* @param {{paramName}}{{#description}} {{{.}}}{{/description}}{{/pathParams}}
30+
* @return Api{{operationId}}Request
31+
*/
32+
{{{nickname}}}(ctx _context.Context{{#pathParams}}, {{paramName}} {{{dataType}}}{{/pathParams}}) Api{{operationId}}Request
33+
34+
/*
35+
* {{nickname}}Execute executes the request{{#returnType}}
36+
* @return {{{.}}}{{/returnType}}
37+
*/
38+
{{nickname}}Execute(r Api{{operationId}}Request) ({{#returnType}}{{{.}}}, {{/returnType}}*_nethttp.Response, error)
39+
{{/operation}}
40+
}
41+
{{/generateInterfaces}}
1842

1943
// {{classname}}Service {{classname}} service
2044
type {{classname}}Service service
21-
2245
{{#operation}}
23-
type api{{operationId}}Request struct {
24-
ctx _context.Context
25-
apiService *{{classname}}Service{{#allParams}}
26-
{{paramName}} {{^isPathParam}}*{{/isPathParam}}{{{dataType}}}{{/allParams}}
27-
}
2846

47+
type Api{{operationId}}Request struct {
48+
ctx _context.Context{{#generateInterfaces}}
49+
ApiService {{classname}}
50+
{{/generateInterfaces}}{{^generateInterfaces}}
51+
ApiService *{{classname}}Service
52+
{{/generateInterfaces}}
2953
{{#allParams}}
30-
{{^isPathParam}}
31-
func (r api{{operationId}}Request) {{vendorExtensions.x-export-param-name}}({{paramName}} {{{dataType}}}) api{{operationId}}Request {
54+
{{paramName}} {{^isPathParam}}*{{/isPathParam}}{{{dataType}}}
55+
{{/allParams}}
56+
}
57+
{{#allParams}}{{^isPathParam}}
58+
func (r Api{{operationId}}Request) {{vendorExtensions.x-export-param-name}}({{paramName}} {{{dataType}}}) Api{{operationId}}Request {
3259
r.{{paramName}} = &{{paramName}}
3360
return r
61+
}{{/isPathParam}}{{/allParams}}
62+
63+
func (r Api{{operationId}}Request) Execute() ({{#returnType}}{{{.}}}, {{/returnType}}*_nethttp.Response, error) {
64+
return r.ApiService.{{nickname}}Execute(r)
3465
}
35-
{{/isPathParam}}
36-
{{/allParams}}
66+
3767
/*
38-
{{operationId}}{{#summary}} {{{.}}}{{/summary}}{{^summary}} Method for {{operationId}}{{/summary}}
68+
* {{operationId}}{{#summary}} {{{.}}}{{/summary}}{{^summary}} Method for {{operationId}}{{/summary}}
3969
{{#notes}}
40-
{{{unescapedNotes}}}
70+
* {{{unescapedNotes}}}
4171
{{/notes}}
4272
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().{{#pathParams}}
4373
* @param {{paramName}}{{#description}} {{{.}}}{{/description}}{{/pathParams}}
44-
@return api{{operationId}}Request
45-
*/
46-
func (a *{{{classname}}}Service) {{{nickname}}}(ctx _context.Context{{#pathParams}}, {{paramName}} {{{dataType}}}{{/pathParams}}) api{{operationId}}Request {
47-
return api{{operationId}}Request{
48-
apiService: a,
74+
* @return Api{{operationId}}Request
75+
*/
76+
func (a *{{{classname}}}Service) {{{nickname}}}(ctx _context.Context{{#pathParams}}, {{paramName}} {{{dataType}}}{{/pathParams}}) Api{{operationId}}Request {
77+
return Api{{operationId}}Request{
78+
ApiService: a,
4979
ctx: ctx,{{#pathParams}}
5080
{{paramName}}: {{paramName}},{{/pathParams}}
5181
}
5282
}
5383

5484
/*
55-
Execute executes the request
56-
{{#returnType}}
57-
@return {{{.}}}
58-
{{/returnType}}
59-
*/
60-
func (r api{{operationId}}Request) Execute() ({{#returnType}}{{{.}}}, {{/returnType}}*_nethttp.Response, error) {
85+
* Execute executes the request{{#returnType}}
86+
* @return {{{.}}}{{/returnType}}
87+
*/
88+
func (a *{{{classname}}}Service) {{nickname}}Execute(r Api{{operationId}}Request) ({{#returnType}}{{{.}}}, {{/returnType}}*_nethttp.Response, error) {
6189
var (
6290
localVarHTTPMethod = _nethttp.Method{{httpMethod}}
6391
localVarPostBody interface{}
@@ -69,7 +97,7 @@ func (r api{{operationId}}Request) Execute() ({{#returnType}}{{{.}}}, {{/returnT
6997
{{/returnType}}
7098
)
7199

72-
localBasePath, err := r.apiService.client.cfg.ServerURLWithContext(r.ctx, "{{{classname}}}Service.{{{nickname}}}")
100+
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "{{{classname}}}Service.{{{nickname}}}")
73101
if err != nil {
74102
return {{#returnType}}localVarReturnValue, {{/returnType}}nil, GenericOpenAPIError{error: err.Error()}
75103
}
@@ -282,12 +310,12 @@ func (r api{{operationId}}Request) Execute() ({{#returnType}}{{{.}}}, {{/returnT
282310
{{/isKeyInCookie}}
283311
{{/isApiKey}}
284312
{{/authMethods}}
285-
req, err := r.apiService.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes)
313+
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes)
286314
if err != nil {
287315
return {{#returnType}}localVarReturnValue, {{/returnType}}nil, err
288316
}
289317

290-
localVarHTTPResponse, err := r.apiService.client.callAPI(req)
318+
localVarHTTPResponse, err := a.client.callAPI(req)
291319
if err != nil || localVarHTTPResponse == nil {
292320
return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, err
293321
}
@@ -311,7 +339,7 @@ func (r api{{operationId}}Request) Execute() ({{#returnType}}{{{.}}}, {{/returnT
311339
if localVarHTTPResponse.StatusCode == {{{code}}} {
312340
{{/wildcard}}
313341
var v {{{dataType}}}
314-
err = r.apiService.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
342+
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
315343
if err != nil {
316344
newErr.error = err.Error()
317345
return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, newErr
@@ -331,7 +359,7 @@ func (r api{{operationId}}Request) Execute() ({{#returnType}}{{{.}}}, {{/returnT
331359
}
332360

333361
{{#returnType}}
334-
err = r.apiService.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
362+
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
335363
if err != nil {
336364
newErr := GenericOpenAPIError{
337365
body: localVarBody,

modules/openapi-generator/src/main/resources/go-experimental/client.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ type APIClient struct {
4242
{{#apis}}
4343
{{#operations}}
4444

45+
{{#generateInterfaces}}
46+
{{classname}} {{classname}}
47+
{{/generateInterfaces}}
48+
{{^generateInterfaces}}
4549
{{classname}} *{{classname}}Service
50+
{{/generateInterfaces}}
4651
{{/operations}}
4752
{{/apis}}
4853
{{/apiInfo}}

modules/openapi-generator/src/main/resources/go/api.mustache

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,40 @@ var (
1717
_ _context.Context
1818
)
1919

20+
{{#generateInterfaces}}
21+
type {{classname}} interface {
22+
{{#operation}}
23+
24+
/*
25+
* {{operationId}}{{#summary}} {{{.}}}{{/summary}}{{^summary}} Method for {{operationId}}{{/summary}}
26+
*
27+
{{#notes}}
28+
* {{notes}}
29+
*
30+
{{/notes}}
31+
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
32+
{{#allParams}}
33+
{{#required}}
34+
* @param {{paramName}}{{#description}} {{{.}}}{{/description}}
35+
{{/required}}
36+
{{/allParams}}
37+
{{#hasOptionalParams}}
38+
* @param optional nil or *{{#structPrefix}}{{&classname}}{{/structPrefix}}{{{nickname}}}Opts - Optional Parameters:
39+
{{#allParams}}
40+
{{^required}}
41+
* @param "{{vendorExtensions.x-export-param-name}}" ({{#isPrimitiveType}}{{^isBinary}}optional.{{vendorExtensions.x-optional-data-type}}{{/isBinary}}{{#isBinary}}optional.Interface of {{dataType}}{{/isBinary}}{{/isPrimitiveType}}{{^isPrimitiveType}}optional.Interface of {{dataType}}{{/isPrimitiveType}}) - {{#description}} {{{.}}}{{/description}}
42+
{{/required}}
43+
{{/allParams}}
44+
{{/hasOptionalParams}}
45+
{{#returnType}}
46+
* @return {{{returnType}}}
47+
{{/returnType}}
48+
*/
49+
{{{nickname}}}(ctx _context.Context{{#hasParams}}, {{/hasParams}}{{#allParams}}{{#required}}{{paramName}} {{{dataType}}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/allParams}}{{#hasOptionalParams}}localVarOptionals *{{#structPrefix}}{{&classname}}{{/structPrefix}}{{{nickname}}}Opts{{/hasOptionalParams}}) ({{#returnType}}{{{returnType}}}, {{/returnType}}*_nethttp.Response, error)
50+
{{/operation}}
51+
}
52+
53+
{{/generateInterfaces}}
2054
// {{classname}}Service {{classname}} service
2155
type {{classname}}Service service
2256
{{#operation}}
@@ -43,9 +77,11 @@ type {{#structPrefix}}{{&classname}}{{/structPrefix}}{{{nickname}}}Opts struct {
4377

4478
{{/hasOptionalParams}}
4579
/*
46-
{{operationId}}{{#summary}} {{{.}}}{{/summary}}{{^summary}} Method for {{operationId}}{{/summary}}
80+
* {{operationId}}{{#summary}} {{{.}}}{{/summary}}{{^summary}} Method for {{operationId}}{{/summary}}
81+
*
4782
{{#notes}}
48-
{{notes}}
83+
* {{notes}}
84+
*
4985
{{/notes}}
5086
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
5187
{{#allParams}}
@@ -62,9 +98,9 @@ type {{#structPrefix}}{{&classname}}{{/structPrefix}}{{{nickname}}}Opts struct {
6298
{{/allParams}}
6399
{{/hasOptionalParams}}
64100
{{#returnType}}
65-
@return {{{returnType}}}
101+
* @return {{{returnType}}}
66102
{{/returnType}}
67-
*/
103+
*/
68104
func (a *{{{classname}}}Service) {{{nickname}}}(ctx _context.Context{{#hasParams}}, {{/hasParams}}{{#allParams}}{{#required}}{{paramName}} {{{dataType}}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/allParams}}{{#hasOptionalParams}}localVarOptionals *{{#structPrefix}}{{&classname}}{{/structPrefix}}{{{nickname}}}Opts{{/hasOptionalParams}}) ({{#returnType}}{{{returnType}}}, {{/returnType}}*_nethttp.Response, error) {
69105
var (
70106
localVarHTTPMethod = _nethttp.Method{{httpMethod}}

0 commit comments

Comments
 (0)