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

[Go] Add Go API client generator #1747

Merged
merged 8 commits into from
Jan 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions bin/go-petstore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

SCRIPT="$0"

while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi

executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"

if [ ! -f "$executable" ]
then
mvn clean package
fi

# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="$@ generate -t modules/swagger-codegen/src/main/resources/go -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l go -o samples/client/petstore/go"

java $JAVA_OPTS -jar $executable $ags
10 changes: 10 additions & 0 deletions bin/windows/go-petstore.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar

If Not Exist %executable% (
mvn clean package
)

set JAVA_OPTS=%JAVA_OPTS% -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties
set ags=generate -t modules\swagger-codegen\src\main\resources\go -i modules\swagger-codegen\src\test\resources\2_0\petstore.json -l go -o samples\client\petstore\go

java %JAVA_OPTS% -jar %executable% %ags%
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
package io.swagger.codegen.languages;

import io.swagger.codegen.*;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.Property;

import java.io.File;
import java.util.*;

import org.apache.commons.lang.StringUtils;

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

public class GoClientCodegen extends DefaultCodegen implements CodegenConfig {
static Logger LOGGER = LoggerFactory.getLogger(GoClientCodegen.class);

protected String packageName = "swagger";
protected String packageVersion = "1.0.0";

public CodegenType getTag() {
return CodegenType.CLIENT;
}

public String getName() {
return "go";
}

public String getHelp() {
return "Generates a Go client library (beta).";
}

public GoClientCodegen() {
super();
outputFolder = "generated-code/go";
modelTemplateFiles.put("model.mustache", ".go");
apiTemplateFiles.put("api.mustache", ".go");
templateDir = "go";

reservedWords = new HashSet<String> (
Arrays.asList(
"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")
);

defaultIncludes = new HashSet<String>(
Arrays.asList(
"map",
"array")
);

languageSpecificPrimitives = new HashSet<String>(
Arrays.asList(
"string",
"bool",
"uint",
"uint32",
"uint64",
"int",
"int32",
"int64",
"float32",
"float64",
"complex64",
"complex128",
"rune",
"byte")
);

instantiationTypes.clear();
/*instantiationTypes.put("array", "GoArray");
instantiationTypes.put("map", "GoMap");*/

typeMapping.clear();
typeMapping.put("integer", "int32");
typeMapping.put("long", "int64");
typeMapping.put("float", "float32");
typeMapping.put("double", "float64");
typeMapping.put("boolean", "bool");
typeMapping.put("string", "string");
typeMapping.put("Date", "time.Time");
typeMapping.put("DateTime", "time.Time");
typeMapping.put("password", "string");
typeMapping.put("File", "*os.File");
typeMapping.put("file", "*os.File");
// map binary to string as a workaround
// the correct solution is to use []byte
typeMapping.put("binary", "string");

importMapping = new HashMap<String, String>();
importMapping.put("time.Time", "time");
importMapping.put("*os.File", "os");

cliOptions.clear();
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Go package name (convention: lowercase).")
.defaultValue("swagger"));
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION, "Go package version.")
.defaultValue("1.0.0"));

}

@Override
public void processOpts() {
//super.processOpts();

if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
}
else {
setPackageName("swagger");
}

if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) {
setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION));
}
else {
setPackageVersion("1.0.0");
}

additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);

modelPackage = packageName;
apiPackage = packageName;

supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
}

@Override
public String escapeReservedWord(String name) {
return "_" + name;
}

@Override
public String apiFileFolder() {
return outputFolder + File.separator + packageName;
}

public String modelFileFolder() {
return outputFolder + File.separator + packageName;
}

@Override
public String toVarName(String name) {
// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_");

// if it's all uppper case, do nothing
if (name.matches("^[A-Z_]*$"))
return name;

// camelize (lower first character) the variable name
// pet_id => PetId
name = camelize(name);

// for reserved word or word starting with number, append _
if(reservedWords.contains(name) || name.matches("^\\d.*"))
name = escapeReservedWord(name);

return name;
}

@Override
public String toParamName(String name) {
// should be the same as variable name
return toVarName(name);
}

@Override
public String toModelName(String name) {
// model name cannot use reserved keyword, e.g. return
if(reservedWords.contains(name))
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");

// camelize the model name
// phone_number => PhoneNumber
return camelize(name);
}

@Override
public String toModelFilename(String name) {
// should be the same as the model name
return toModelName(name);
}

@Override
public String getTypeDeclaration(Property p) {
if(p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
Property inner = ap.getItems();
return "[]" + getTypeDeclaration(inner);
}
else if (p instanceof MapProperty) {
MapProperty mp = (MapProperty) p;
Property inner = mp.getAdditionalProperties();

return getSwaggerType(p) + "[string]" + getTypeDeclaration(inner);
}
return super.getTypeDeclaration(p);
}

@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if(typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if(languageSpecificPrimitives.contains(type))
return (type);
}
else
type = swaggerType;
return type;
}

@Override
public String toOperationId(String operationId) {
// method name cannot use reserved keyword, e.g. return
if(reservedWords.contains(operationId))
throw new RuntimeException(operationId + " (reserved word) cannot be used as method name");

return camelize(operationId);
}

@Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
@SuppressWarnings("unchecked")
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");
@SuppressWarnings("unchecked")
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
for (CodegenOperation operation : operations) {
// http method verb conversion (e.g. PUT => Put)
operation.httpMethod = camelize(operation.httpMethod.toLowerCase());
}

// remove model imports to avoid error
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
if (imports == null)
return objs;

Iterator<Map<String, String>> iterator = imports.iterator();
while (iterator.hasNext()) {
String _import = iterator.next().get("import");
if (_import.startsWith(apiPackage()))
iterator.remove();
}

return objs;
}

@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// remove model imports to avoid error
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
final String prefix = modelPackage();
Iterator<Map<String, String>> iterator = imports.iterator();
while (iterator.hasNext()) {
String _import = iterator.next().get("import");
if (_import.startsWith(prefix))
iterator.remove();
}
return objs;
}

@Override
protected boolean needToImport(String type) {
return !defaultIncludes.contains(type)
&& !languageSpecificPrimitives.contains(type);
}

public void setPackageName(String packageName) {
this.packageName = packageName;
}

public void setPackageVersion(String packageVersion) {
this.packageVersion = packageVersion;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ io.swagger.codegen.languages.CSharpClientCodegen
io.swagger.codegen.languages.DartClientCodegen
io.swagger.codegen.languages.FlashClientCodegen
io.swagger.codegen.languages.FlaskConnexionCodegen
io.swagger.codegen.languages.GoClientCodegen
io.swagger.codegen.languages.JavaClientCodegen
io.swagger.codegen.languages.JavascriptClientCodegen
io.swagger.codegen.languages.JaxRSServerCodegen
Expand Down
12 changes: 12 additions & 0 deletions modules/swagger-codegen/src/main/resources/go/README.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Go API client for {{packageName}}

## Overview
This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client.


## Installation
Put the package under your project folder and add the following in import:
```
"./{{packageName}}"
```

Loading