Skip to content

Commit 04f8d61

Browse files
authored
Merge pull request #641 from swagger-api/go-client-codegen
Go client codegen
2 parents 03ad1d6 + 6c7aa40 commit 04f8d61

33 files changed

+2515
-29
lines changed

src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,9 +2173,7 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
21732173
} else if (param instanceof CookieParameter || "cookie".equalsIgnoreCase(param.getIn())) {
21742174
cookieParams.add(codegenParameter.copy());
21752175
}
2176-
if (!codegenParameter.required) {
2177-
codegenOperation.getVendorExtensions().put(CodegenConstants.HAS_OPTIONAL_PARAMS_EXT_NAME, Boolean.TRUE);
2178-
} else {
2176+
if (codegenParameter.required) {
21792177
requiredParams.add(codegenParameter.copy());
21802178
}
21812179
}
@@ -2222,6 +2220,10 @@ public int compare(CodegenParameter one, CodegenParameter another) {
22222220
boolean hasRequiredParams = codegenOperation.requiredParams.size() > 0;
22232221
codegenOperation.getVendorExtensions().put(CodegenConstants.HAS_REQUIRED_PARAMS_EXT_NAME, hasRequiredParams);
22242222

2223+
boolean hasOptionalParams = codegenOperation.allParams.stream()
2224+
.anyMatch(codegenParameter -> !codegenParameter.required);
2225+
codegenOperation.getVendorExtensions().put(CodegenConstants.HAS_OPTIONAL_PARAMS_EXT_NAME, hasOptionalParams);
2226+
22252227
// set Restful Flag
22262228
codegenOperation.getVendorExtensions().put(CodegenConstants.IS_RESTFUL_SHOW_EXT_NAME, codegenOperation.getIsRestfulShow());
22272229
codegenOperation.getVendorExtensions().put(CodegenConstants.IS_RESTFUL_INDEX_EXT_NAME, codegenOperation.getIsRestfulIndex());

src/main/java/io/swagger/codegen/v3/generators/go/AbstractGoCodegen.java

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package io.swagger.codegen.v3.generators.go;
22

33
import io.swagger.codegen.v3.CliOption;
4-
import io.swagger.codegen.v3.CodegenConfig;
54
import io.swagger.codegen.v3.CodegenConstants;
5+
import io.swagger.codegen.v3.CodegenContent;
66
import io.swagger.codegen.v3.CodegenModel;
77
import io.swagger.codegen.v3.CodegenOperation;
88
import io.swagger.codegen.v3.CodegenParameter;
99
import io.swagger.codegen.v3.CodegenProperty;
10+
import io.swagger.codegen.v3.ISchemaHandler;
1011
import io.swagger.codegen.v3.generators.DefaultCodegenConfig;
12+
import io.swagger.codegen.v3.generators.util.OpenAPIUtil;
1113
import io.swagger.v3.core.util.Yaml;
1214
import io.swagger.v3.oas.models.OpenAPI;
1315
import io.swagger.v3.oas.models.media.ArraySchema;
@@ -77,6 +79,7 @@ public AbstractGoCodegen() {
7779
typeMapping.put("number", "float32");
7880
typeMapping.put("float", "float32");
7981
typeMapping.put("double", "float64");
82+
typeMapping.put("BigDecimal", "float64");
8083
typeMapping.put("boolean", "bool");
8184
typeMapping.put("string", "string");
8285
typeMapping.put("UUID", "string");
@@ -265,6 +268,14 @@ public String getTypeDeclaration(Schema schema) {
265268
@Override
266269
public String getSchemaType(Schema schema) {
267270
String schemaType = super.getSchemaType(schema);
271+
272+
if (schema.get$ref() != null) {
273+
final Schema refSchema = OpenAPIUtil.getSchemaFromName(schemaType, this.openAPI);
274+
if (refSchema != null && !isObjectSchema(refSchema)) {
275+
schemaType = super.getSchemaType(refSchema);
276+
}
277+
}
278+
268279
String type;
269280
if(typeMapping.containsKey(schemaType)) {
270281
type = typeMapping.get(schemaType);
@@ -325,34 +336,36 @@ public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
325336
boolean addedTimeImport = false;
326337
boolean addedOSImport = false;
327338
for (CodegenOperation operation : operations) {
328-
for (CodegenParameter param : operation.allParams) {
329-
// import "os" if the operation uses files
330-
if (!addedOSImport && param.dataType == "*os.File") {
331-
imports.add(createMapping("import", "os"));
332-
addedOSImport = true;
333-
}
334-
335-
// import "time" if the operation has a required time parameter.
336-
if (param.required) {
337-
if (!addedTimeImport && param.dataType == "time.Time") {
338-
imports.add(createMapping("import", "time"));
339-
addedTimeImport = true;
339+
for (CodegenContent codegenContent : operation.getContents()) {
340+
for (CodegenParameter param : codegenContent.getParameters()) {
341+
// import "os" if the operation uses files
342+
if (!addedOSImport && param.dataType == "*os.File") {
343+
imports.add(createMapping("import", "os"));
344+
addedOSImport = true;
340345
}
341-
}
342346

343-
// import "optionals" package if the parameter is primitive and optional
344-
if (!param.required && getBooleanValue(param, CodegenConstants.IS_PRIMITIVE_TYPE_EXT_NAME)) {
345-
if (!addedOptionalImport) {
346-
imports.add(createMapping("import", "github.com/antihax/optional"));
347-
addedOptionalImport = true;
347+
// import "time" if the operation has a required time parameter.
348+
if (param.required) {
349+
if (!addedTimeImport && param.dataType == "time.Time") {
350+
imports.add(createMapping("import", "time"));
351+
addedTimeImport = true;
352+
}
348353
}
349-
// We need to specially map Time type to the optionals package
350-
if (param.dataType == "time.Time") {
351-
param.vendorExtensions.put("x-optionalDataType", "Time");
352-
continue;
354+
355+
// import "optionals" package if the parameter is primitive and optional
356+
if (!param.required && param.getIsPrimitiveType()) {
357+
if (!addedOptionalImport) {
358+
imports.add(createMapping("import", "github.com/antihax/optional"));
359+
addedOptionalImport = true;
360+
}
361+
// We need to specially map Time type to the optionals package
362+
if (param.dataType == "time.Time") {
363+
param.vendorExtensions.put("x-optionalDataType", "Time");
364+
continue;
365+
}
366+
// Map optional type to dataType
367+
param.vendorExtensions.put("x-optionalDataType", param.dataType.substring(0, 1).toUpperCase() + param.dataType.substring(1));
353368
}
354-
// Map optional type to dataType
355-
param.vendorExtensions.put("x-optionalDataType", param.dataType.substring(0, 1).toUpperCase() + param.dataType.substring(1));
356369
}
357370
}
358371
}
@@ -426,7 +439,7 @@ public Map<String, Object> postProcessModels(Map<String, Object> objs) {
426439

427440
@Override
428441
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
429-
OpenAPI openAPI = (OpenAPI)objs.get("openapi");
442+
OpenAPI openAPI = (OpenAPI)objs.get("openAPI");
430443
if(openAPI != null) {
431444
try {
432445
objs.put("swagger-yaml", Yaml.mapper().writeValueAsString(openAPI));
@@ -527,4 +540,25 @@ public String toEnumName(CodegenProperty property) {
527540
public void setWithXml(boolean withXml) {
528541
this.withXml = withXml;
529542
}
543+
544+
@Override
545+
public CodegenModel fromModel(String name, Schema schema, Map<String, Schema> allDefinitions) {
546+
final CodegenModel codegenModel = super.fromModel(name, schema, allDefinitions);
547+
if (!getBooleanValue(codegenModel, CodegenConstants.IS_ALIAS_EXT_NAME)) {
548+
boolean isAlias = schema instanceof ArraySchema
549+
|| schema instanceof MapSchema
550+
|| (!isObjectSchema(schema));
551+
552+
codegenModel.getVendorExtensions().put(CodegenConstants.IS_ALIAS_EXT_NAME, isAlias);
553+
}
554+
555+
556+
557+
return codegenModel;
558+
}
559+
560+
@Override
561+
public ISchemaHandler getSchemaHandler() {
562+
return new GoSchemaHandler(this);
563+
}
530564
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package io.swagger.codegen.v3.generators.go;
2+
3+
import io.swagger.codegen.v3.CliOption;
4+
import io.swagger.codegen.v3.CodegenOperation;
5+
import io.swagger.codegen.v3.CodegenType;
6+
import io.swagger.codegen.v3.SupportingFile;
7+
import io.swagger.v3.oas.models.OpenAPI;
8+
import io.swagger.v3.oas.models.Operation;
9+
import io.swagger.v3.oas.models.media.Schema;
10+
import org.apache.commons.lang3.StringUtils;
11+
12+
import java.io.File;
13+
import java.util.Arrays;
14+
import java.util.Map;
15+
16+
public class GoClientCodegen extends AbstractGoCodegen {
17+
protected String packageVersion = "1.0.0";
18+
protected String apiDocPath = "docs/";
19+
protected String modelDocPath = "docs/";
20+
public static final String WITH_XML = "withXml";
21+
22+
public GoClientCodegen() {
23+
this.outputFolder = "generated-code/go";
24+
this.modelTemplateFiles.put("model.mustache", ".go");
25+
this.apiTemplateFiles.put("api.mustache", ".go");
26+
this.modelDocTemplateFiles.put("model_doc.mustache", ".md");
27+
this.apiDocTemplateFiles.put("api_doc.mustache", ".md");
28+
this.hideGenerationTimestamp = Boolean.TRUE;
29+
this.setReservedWordsLowerCase(Arrays.asList("string", "bool", "uint", "uint8", "uint16", "uint32", "uint64", "int", "int8", "int16", "int32", "int64", "float32", "float64", "complex64", "complex128", "rune", "byte", "uintptr", "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", "error", "ApiResponse", "nil"));
30+
this.cliOptions.add((new CliOption("packageVersion", "Go package version.")).defaultValue("1.0.0"));
31+
this.cliOptions.add(CliOption.newBoolean("withXml", "whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)"));
32+
}
33+
34+
@Override
35+
public String getDefaultTemplateDir() {
36+
return "go";
37+
}
38+
39+
public void processOpts() {
40+
super.processOpts();
41+
42+
if (StringUtils.isBlank(templateDir)) {
43+
embeddedTemplateDir = templateDir = getTemplateDir();
44+
}
45+
46+
if (this.additionalProperties.containsKey("packageName")) {
47+
this.setPackageName((String)this.additionalProperties.get("packageName"));
48+
} else {
49+
this.setPackageName("swagger");
50+
}
51+
52+
if (this.additionalProperties.containsKey("packageVersion")) {
53+
this.setPackageVersion((String)this.additionalProperties.get("packageVersion"));
54+
} else {
55+
this.setPackageVersion("1.0.0");
56+
}
57+
58+
this.additionalProperties.put("packageName", this.packageName);
59+
this.additionalProperties.put("packageVersion", this.packageVersion);
60+
this.additionalProperties.put("apiDocPath", this.apiDocPath);
61+
this.additionalProperties.put("modelDocPath", this.modelDocPath);
62+
this.modelPackage = this.packageName;
63+
this.apiPackage = this.packageName;
64+
this.supportingFiles.add(new SupportingFile("swagger.mustache", "api", "swagger.yaml"));
65+
this.supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
66+
this.supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
67+
this.supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
68+
this.supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.go"));
69+
this.supportingFiles.add(new SupportingFile("client.mustache", "", "client.go"));
70+
this.supportingFiles.add(new SupportingFile("response.mustache", "", "response.go"));
71+
this.supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml"));
72+
if (this.additionalProperties.containsKey("withXml")) {
73+
this.setWithXml(Boolean.parseBoolean(this.additionalProperties.get("withXml").toString()));
74+
if (this.withXml) {
75+
this.additionalProperties.put("withXml", "true");
76+
}
77+
}
78+
79+
}
80+
81+
public CodegenType getTag() {
82+
return CodegenType.CLIENT;
83+
}
84+
85+
public String getName() {
86+
return "go";
87+
}
88+
89+
public String getHelp() {
90+
return "Generates a Go client library (beta).";
91+
}
92+
93+
public String apiFileFolder() {
94+
return this.outputFolder + File.separator;
95+
}
96+
97+
public String modelFileFolder() {
98+
return this.outputFolder + File.separator;
99+
}
100+
101+
public String apiDocFileFolder() {
102+
return (this.outputFolder + "/" + this.apiDocPath).replace('/', File.separatorChar);
103+
}
104+
105+
public String modelDocFileFolder() {
106+
return (this.outputFolder + "/" + this.modelDocPath).replace('/', File.separatorChar);
107+
}
108+
109+
public String toModelDocFilename(String name) {
110+
return this.toModelName(name);
111+
}
112+
113+
public String toApiDocFilename(String name) {
114+
return this.toApiName(name);
115+
}
116+
117+
public void setPackageVersion(String packageVersion) {
118+
this.packageVersion = packageVersion;
119+
}
120+
121+
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map<String, Schema> schemas, OpenAPI openAPI) {
122+
final CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, schemas, openAPI);
123+
if (codegenOperation.getHasBodyParam() || codegenOperation.bodyParam != null) {
124+
codegenOperation.getFormParams().clear();
125+
}
126+
return codegenOperation;
127+
}
128+
}
129+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.swagger.codegen.v3.generators.go;
2+
3+
import io.swagger.codegen.v3.CodegenModel;
4+
import io.swagger.codegen.v3.generators.DefaultCodegenConfig;
5+
import io.swagger.codegen.v3.generators.SchemaHandler;
6+
import io.swagger.v3.oas.models.media.Schema;
7+
import org.apache.commons.lang3.StringUtils;
8+
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
public class GoSchemaHandler extends SchemaHandler {
13+
14+
public GoSchemaHandler(DefaultCodegenConfig codegenConfig) {
15+
super(codegenConfig);
16+
}
17+
18+
protected void addInterfaces(List<Schema> schemas, CodegenModel composedModel, Map<String, CodegenModel> allModels) {
19+
for (Schema interfaceSchema : schemas) {
20+
final String ref = interfaceSchema.get$ref();
21+
if (StringUtils.isBlank(ref)) {
22+
continue;
23+
}
24+
final String schemaName = ref.substring(ref.lastIndexOf("/") + 1);
25+
this.addInterfaceModel(composedModel, allModels.get(codegenConfig.toModelName(schemaName)));
26+
}
27+
}
28+
}

src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
io.swagger.codegen.v3.generators.dotnet.AspNetCoreServerCodegen
22
io.swagger.codegen.v3.generators.dotnet.CSharpClientCodegen
33
io.swagger.codegen.v3.generators.dotnet.CsharpDotNet2ClientCodegen
4+
io.swagger.codegen.v3.generators.go.GoClientCodegen
45
io.swagger.codegen.v3.generators.go.GoServerCodegen
56
io.swagger.codegen.v3.generators.html.StaticDocCodegen
67
io.swagger.codegen.v3.generators.html.StaticHtmlCodegen

src/main/resources/handlebars/go-server/model.mustache

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,15 @@ const (
1717
){{/isEnum}}{{^isEnum}}{{#description}}
1818
// {{{description}}}{{/description}}
1919
type {{classname}} struct {
20+
{{#isComposedModel}}
21+
{{#interfaceModels}}
22+
{{classname}}
23+
{{/interfaceModels}}
24+
{{/isComposedModel}}
25+
{{^isComposedModel}}
2026
{{#vars}}{{#description}}
2127
// {{{description}}}{{/description}}
2228
{{name}} {{^isEnum}}{{^isPrimitiveType}}{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{/isPrimitiveType}}{{/isEnum}}{{{datatype}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"`
2329
{{/vars}}
30+
{{/isComposedModel}}
2431
}{{/isEnum}}{{/model}}{{/models}}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
language: go
2+
3+
install:
4+
- go get -d -v .
5+
6+
script:
7+
- go build -v ./
8+

0 commit comments

Comments
 (0)