forked from loafle/openapi-generator-original
Merge branch 'develop_2.0' into develop_2.0_objc_contenttype
Conflicts: samples/client/petstore/objc/client/SWGPetApi.m
This commit is contained in:
commit
87a730b5a2
12
.gitignore
vendored
12
.gitignore
vendored
@ -22,7 +22,17 @@ samples/server-generator/scalatra/output
|
||||
samples/server-generator/node/output/node_modules
|
||||
samples/server-generator/scalatra/target
|
||||
samples/server-generator/scalatra/output/.history
|
||||
|
||||
samples/client/petstore/qt5cpp/PetStore/moc_*
|
||||
samples/client/petstore/qt5cpp/PetStore/*.o
|
||||
samples/client/petstore/objc/PetstoreClient.xcworkspace/xcuserdata
|
||||
samples/client/petstore/qt5cpp/build-*
|
||||
samples/client/petstore/qt5cpp/PetStore/PetStore
|
||||
samples/client/petstore/qt5cpp/PetStore/Makefile
|
||||
samples/client/petstore/java/hello.txt
|
||||
samples/client/petstore/android-java/hello.txt
|
||||
samples/client/petstore/objc/Build
|
||||
samples/client/petstore/objc/Pods
|
||||
samples/server/petstore/nodejs/node_modules
|
||||
target
|
||||
.idea
|
||||
.lib
|
||||
|
@ -150,8 +150,11 @@ JavaClientCodegen.java
|
||||
JaxRSServerCodegen.java
|
||||
NodeJSServerCodegen.java
|
||||
ObjcClientCodegen.java
|
||||
PerlClientCodegen.java
|
||||
PhpClientCodegen.java
|
||||
Python3ClientCodegen.java
|
||||
PythonClientCodegen.java
|
||||
Qt5CPPGenerator.java
|
||||
RubyClientCodegen.java
|
||||
ScalaClientCodegen.java
|
||||
ScalatraServerCodegen.java
|
||||
|
@ -26,6 +26,6 @@ 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/JavaJaxRS -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l jaxrs -o samples/server/petstore/jaxrs"
|
||||
ags="$@ generate -t modules/swagger-codegen/src/main/resources/JavaJaxRS -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l jaxrs -o samples/server/petstore/jaxrs -Dswagger.codegen.jaxrs.impl.source=src/main/java"
|
||||
|
||||
java $JAVA_OPTS -jar $executable $ags
|
||||
|
@ -54,10 +54,16 @@ public class Generate implements Runnable {
|
||||
"Pass in a URL-encoded string of name:header with a comma separating multiple values")
|
||||
private String auth;
|
||||
|
||||
@Option( name= {"-D"}, title = "system properties", description = "sets specified system properties in " +
|
||||
"the format of name=value,name=value")
|
||||
private String systemProperties;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
verbosed(verbose);
|
||||
|
||||
setSystemProperties();
|
||||
|
||||
ClientOptInput input = new ClientOptInput();
|
||||
|
||||
if (isNotEmpty(auth)) {
|
||||
@ -77,6 +83,17 @@ public class Generate implements Runnable {
|
||||
new DefaultGenerator().opts(input.opts(new ClientOpts()).swagger(swagger)).generate();
|
||||
}
|
||||
|
||||
private void setSystemProperties() {
|
||||
if( systemProperties != null && systemProperties.length() > 0 ){
|
||||
for( String property : systemProperties.split(",")) {
|
||||
int ix = property.indexOf('=');
|
||||
if( ix > 0 && ix < property.length()-1 ){
|
||||
System.setProperty( property.substring(0, ix), property.substring(ix+1) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If true parameter, adds system properties which enables debug mode in generator
|
||||
* @param verbose - if true, enables debug mode
|
||||
|
@ -6,11 +6,9 @@
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.wordnik</groupId>
|
||||
<artifactId>swagger-codegen</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>swagger-codegen (core library)</name>
|
||||
<version>2.1.1-M2-SNAPSHOT</version>
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
|
@ -56,4 +56,8 @@ public interface CodegenConfig {
|
||||
Map<String, Object> postProcessModels(Map<String, Object> objs);
|
||||
Map<String, Object> postProcessOperations(Map<String, Object> objs);
|
||||
Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs);
|
||||
|
||||
String apiFilename(String templateName, String tag);
|
||||
|
||||
boolean shouldOverwrite(String filename);
|
||||
}
|
||||
|
@ -11,6 +11,6 @@ public class CodegenModel {
|
||||
public String defaultValue;
|
||||
public List<CodegenProperty> vars = new ArrayList<CodegenProperty>();
|
||||
public Set<String> imports = new HashSet<String>();
|
||||
public Boolean hasVars, emptyVars, hasMoreModels;
|
||||
public Boolean hasVars, emptyVars, hasMoreModels, hasEnums;
|
||||
public ExternalDocs externalDocs;
|
||||
}
|
@ -3,7 +3,7 @@ package com.wordnik.swagger.codegen;
|
||||
public class CodegenParameter {
|
||||
public Boolean isFormParam, isQueryParam, isPathParam, isHeaderParam,
|
||||
isCookieParam, isBodyParam, isFile, notFile, hasMore, isContainer, secondaryParam;
|
||||
public String baseName, paramName, dataType, collectionFormat, description, baseType;
|
||||
public String baseName, paramName, dataType, collectionFormat, description, baseType, defaultValue;
|
||||
public String jsonSchema;
|
||||
|
||||
/**
|
||||
@ -34,7 +34,8 @@ public class CodegenParameter {
|
||||
output.isBodyParam = this.isBodyParam;
|
||||
output.required = this.required;
|
||||
output.jsonSchema = this.jsonSchema;
|
||||
output.defaultValue = this.defaultValue;
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,10 @@ public class CodegenProperty {
|
||||
public String example;
|
||||
|
||||
public String jsonSchema;
|
||||
public Double minimum, maximum, exclusiveMinimum, exclusiveMaximum;
|
||||
public Double minimum;
|
||||
public Double maximum;
|
||||
public Boolean exclusiveMinimum;
|
||||
public Boolean exclusiveMaximum;
|
||||
public Boolean hasMore = null, required = null, secondaryParam = null;
|
||||
public Boolean isPrimitiveType, isContainer, isNotContainer;
|
||||
public boolean isEnum;
|
||||
|
@ -1,17 +1,21 @@
|
||||
package com.wordnik.swagger.codegen;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CodegenResponse {
|
||||
public String code, message;
|
||||
public Boolean hasMore;
|
||||
public List<Map<String, String>> examples;
|
||||
public List<Map<String, Object>> examples;
|
||||
public final List<CodegenProperty> headers = new ArrayList<CodegenProperty>();
|
||||
public String dataType, baseType, containerType;
|
||||
public Boolean isDefault;
|
||||
public Boolean simpleType;
|
||||
public Boolean primitiveType;
|
||||
public Boolean isMapContainer;
|
||||
public Boolean isListContainer;
|
||||
public Object schema;
|
||||
public String jsonSchema;
|
||||
}
|
||||
public boolean isWildcard() { return "0".equals(code) || "default".equals(code); }
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package com.wordnik.swagger.codegen;
|
||||
|
||||
public class CodegenSecurity {
|
||||
String name;
|
||||
String type;
|
||||
Boolean hasMore, isBasic, isOAuth, isApiKey;
|
||||
public String name;
|
||||
public String type;
|
||||
public Boolean hasMore, isBasic, isOAuth, isApiKey;
|
||||
// ApiKey specific
|
||||
String keyParamName;
|
||||
Boolean isKeyInQuery, isKeyInHeader;
|
||||
|
||||
public String keyParamName;
|
||||
public Boolean isKeyInQuery, isKeyInHeader;
|
||||
}
|
||||
|
@ -1,26 +1,58 @@
|
||||
package com.wordnik.swagger.codegen;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.wordnik.swagger.codegen.examples.ExampleGenerator;
|
||||
import com.wordnik.swagger.models.*;
|
||||
import com.wordnik.swagger.models.ArrayModel;
|
||||
import com.wordnik.swagger.models.Model;
|
||||
import com.wordnik.swagger.models.ModelImpl;
|
||||
import com.wordnik.swagger.models.Operation;
|
||||
import com.wordnik.swagger.models.RefModel;
|
||||
import com.wordnik.swagger.models.Response;
|
||||
import com.wordnik.swagger.models.Swagger;
|
||||
import com.wordnik.swagger.models.auth.ApiKeyAuthDefinition;
|
||||
import com.wordnik.swagger.models.auth.BasicAuthDefinition;
|
||||
import com.wordnik.swagger.models.auth.In;
|
||||
import com.wordnik.swagger.models.auth.SecuritySchemeDefinition;
|
||||
import com.wordnik.swagger.models.parameters.*;
|
||||
import com.wordnik.swagger.models.properties.*;
|
||||
import com.wordnik.swagger.models.parameters.BodyParameter;
|
||||
import com.wordnik.swagger.models.parameters.CookieParameter;
|
||||
import com.wordnik.swagger.models.parameters.FormParameter;
|
||||
import com.wordnik.swagger.models.parameters.HeaderParameter;
|
||||
import com.wordnik.swagger.models.parameters.Parameter;
|
||||
import com.wordnik.swagger.models.parameters.PathParameter;
|
||||
import com.wordnik.swagger.models.parameters.QueryParameter;
|
||||
import com.wordnik.swagger.models.parameters.SerializableParameter;
|
||||
import com.wordnik.swagger.models.properties.AbstractNumericProperty;
|
||||
import com.wordnik.swagger.models.properties.ArrayProperty;
|
||||
import com.wordnik.swagger.models.properties.BooleanProperty;
|
||||
import com.wordnik.swagger.models.properties.DateProperty;
|
||||
import com.wordnik.swagger.models.properties.DateTimeProperty;
|
||||
import com.wordnik.swagger.models.properties.DecimalProperty;
|
||||
import com.wordnik.swagger.models.properties.DoubleProperty;
|
||||
import com.wordnik.swagger.models.properties.FloatProperty;
|
||||
import com.wordnik.swagger.models.properties.IntegerProperty;
|
||||
import com.wordnik.swagger.models.properties.LongProperty;
|
||||
import com.wordnik.swagger.models.properties.MapProperty;
|
||||
import com.wordnik.swagger.models.properties.Property;
|
||||
import com.wordnik.swagger.models.properties.PropertyBuilder;
|
||||
import com.wordnik.swagger.models.properties.RefProperty;
|
||||
import com.wordnik.swagger.models.properties.StringProperty;
|
||||
import com.wordnik.swagger.util.Json;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DefaultCodegen {
|
||||
Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class);
|
||||
|
||||
@ -166,6 +198,9 @@ public class DefaultCodegen {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String toEnumName(CodegenProperty property) {
|
||||
return StringUtils.capitalize(property.name) + "Enum";
|
||||
}
|
||||
|
||||
public String escapeReservedWord(String name) {
|
||||
throw new RuntimeException("reserved word " + name + " not allowed");
|
||||
@ -470,6 +505,7 @@ public class DefaultCodegen {
|
||||
}
|
||||
if(impl.getProperties() != null && impl.getProperties().size() > 0) {
|
||||
m.hasVars = true;
|
||||
m.hasEnums = false;
|
||||
for(String key: impl.getProperties().keySet()) {
|
||||
Property prop = impl.getProperties().get(key);
|
||||
|
||||
@ -497,6 +533,8 @@ public class DefaultCodegen {
|
||||
}
|
||||
m.vars.add(cp);
|
||||
count += 1;
|
||||
if (cp.isEnum)
|
||||
m.hasEnums = true;
|
||||
if(count != impl.getProperties().keySet().size())
|
||||
cp.hasMore = new Boolean(true);
|
||||
if(cp.isContainer != null) {
|
||||
@ -589,7 +627,7 @@ public class DefaultCodegen {
|
||||
|
||||
// this can cause issues for clients which don't support enums
|
||||
if(property.isEnum)
|
||||
property.datatypeWithEnum = StringUtils.capitalize(property.name) + "Enum";
|
||||
property.datatypeWithEnum = toEnumName(property);
|
||||
else
|
||||
property.datatypeWithEnum = property.datatype;
|
||||
|
||||
@ -692,11 +730,11 @@ public class DefaultCodegen {
|
||||
for(String key: operation.getConsumes()) {
|
||||
Map<String, String> mediaType = new HashMap<String, String>();
|
||||
mediaType.put("mediaType", key);
|
||||
count += 1;
|
||||
if (count < operation.getConsumes().size())
|
||||
mediaType.put("hasMore", "true");
|
||||
else
|
||||
mediaType.put("hasMore", null);
|
||||
count += 1;
|
||||
c.add(mediaType);
|
||||
}
|
||||
op.consumes = c;
|
||||
@ -722,7 +760,6 @@ public class DefaultCodegen {
|
||||
|
||||
if (operation.getResponses() != null && !operation.getResponses().isEmpty()) {
|
||||
Response methodResponse = findMethodResponse(operation.getResponses());
|
||||
CodegenResponse methodCodegenResponse = null;
|
||||
|
||||
for (Map.Entry<String, Response> entry : operation.getResponses().entrySet()) {
|
||||
Response response = entry.getValue();
|
||||
@ -732,9 +769,7 @@ public class DefaultCodegen {
|
||||
!defaultIncludes.contains(r.baseType) &&
|
||||
!languageSpecificPrimitives.contains(r.baseType))
|
||||
imports.add(r.baseType);
|
||||
|
||||
if (response == methodResponse)
|
||||
methodCodegenResponse = r;
|
||||
r.isDefault = response == methodResponse;
|
||||
op.responses.add(r);
|
||||
}
|
||||
op.responses.get(op.responses.size() - 1).hasMore = false;
|
||||
@ -904,6 +939,15 @@ public class DefaultCodegen {
|
||||
p.required = param.getRequired();
|
||||
p.jsonSchema = Json.pretty(param);
|
||||
|
||||
// move the defaultValue for headers, forms and params
|
||||
if(param instanceof QueryParameter) {
|
||||
p.defaultValue = ((QueryParameter)param).getDefaultValue();
|
||||
} else if(param instanceof HeaderParameter) {
|
||||
p.defaultValue = ((HeaderParameter)param).getDefaultValue();
|
||||
} else if(param instanceof FormParameter) {
|
||||
p.defaultValue = ((FormParameter)param).getDefaultValue();
|
||||
}
|
||||
|
||||
if(param instanceof SerializableParameter) {
|
||||
SerializableParameter qp = (SerializableParameter) param;
|
||||
Property property = null;
|
||||
@ -918,6 +962,19 @@ public class DefaultCodegen {
|
||||
collectionFormat = qp.getCollectionFormat();
|
||||
CodegenProperty pr = fromProperty("inner", inner);
|
||||
p.baseType = pr.datatype;
|
||||
p.isContainer = true;
|
||||
imports.add(pr.baseType);
|
||||
}
|
||||
else if("object".equals(qp.getType())) {
|
||||
Property inner = qp.getItems();
|
||||
if(inner == null) {
|
||||
LOGGER.warn("warning! No inner type supplied for map parameter \"" + qp.getName() + "\", using String");
|
||||
inner = new StringProperty().description("//TODO automatically added by swagger-codegen");
|
||||
}
|
||||
property = new MapProperty(inner);
|
||||
collectionFormat = qp.getCollectionFormat();
|
||||
CodegenProperty pr = fromProperty("inner", inner);
|
||||
p.baseType = pr.datatype;
|
||||
imports.add(pr.baseType);
|
||||
}
|
||||
else
|
||||
@ -926,6 +983,7 @@ public class DefaultCodegen {
|
||||
LOGGER.warn("warning! Property type \"" + qp.getType() + "\" not found for parameter \"" + param.getName() + "\", using String");
|
||||
property = new StringProperty().description("//TODO automatically added by swagger-codegen. Type was " + qp.getType() + " but not supported");
|
||||
}
|
||||
property.setRequired(param.getRequired());
|
||||
CodegenProperty model = fromProperty(qp.getName(), property);
|
||||
p.collectionFormat = collectionFormat;
|
||||
p.dataType = model.datatype;
|
||||
@ -949,6 +1007,7 @@ public class DefaultCodegen {
|
||||
else {
|
||||
// TODO: missing format, so this will not always work
|
||||
Property prop = PropertyBuilder.build(impl.getType(), null, null);
|
||||
prop.setRequired(bp.getRequired());
|
||||
CodegenProperty cp = fromProperty("property", prop);
|
||||
if(cp != null) {
|
||||
p.dataType = cp.datatype;
|
||||
@ -962,6 +1021,7 @@ public class DefaultCodegen {
|
||||
CodegenModel cm = fromModel(bp.getName(), impl);
|
||||
// get the single property
|
||||
ArrayProperty ap = new ArrayProperty().items(impl.getItems());
|
||||
ap.setRequired(param.getRequired());
|
||||
CodegenProperty cp = fromProperty("inner", ap);
|
||||
if(cp.complexType != null) {
|
||||
imports.add(cp.complexType);
|
||||
@ -996,9 +1056,9 @@ public class DefaultCodegen {
|
||||
if(schemes == null)
|
||||
return null;
|
||||
|
||||
List<CodegenSecurity> secs = new ArrayList<CodegenSecurity>();
|
||||
for(Iterator entries = schemes.entrySet().iterator(); entries.hasNext(); ) {
|
||||
Map.Entry<String, SecuritySchemeDefinition> entry = (Map.Entry<String, SecuritySchemeDefinition>) entries.next();
|
||||
List<CodegenSecurity> secs = new ArrayList<CodegenSecurity>(schemes.size());
|
||||
for (Iterator<Map.Entry<String, SecuritySchemeDefinition>> it = schemes.entrySet().iterator(); it.hasNext();) {
|
||||
final Map.Entry<String, SecuritySchemeDefinition> entry = it.next();
|
||||
final SecuritySchemeDefinition schemeDefinition = entry.getValue();
|
||||
|
||||
CodegenSecurity sec = CodegenModelFactory.newInstance(CodegenModelType.SECURITY);
|
||||
@ -1018,23 +1078,21 @@ public class DefaultCodegen {
|
||||
sec.isOAuth = !sec.isBasic;
|
||||
}
|
||||
|
||||
sec.hasMore = entries.hasNext();
|
||||
sec.hasMore = it.hasNext();
|
||||
secs.add(sec);
|
||||
}
|
||||
return secs;
|
||||
}
|
||||
|
||||
protected List<Map<String, String>> toExamples(Map<String, String> examples) {
|
||||
protected List<Map<String, Object>> toExamples(Map<String, Object> examples) {
|
||||
if(examples == null)
|
||||
return null;
|
||||
|
||||
List<Map<String, String>> output = new ArrayList<Map<String, String>>();
|
||||
for(String key: examples.keySet()) {
|
||||
String value = examples.get(key);
|
||||
|
||||
Map<String, String> kv = new HashMap<String, String>();
|
||||
kv.put("contentType", key);
|
||||
kv.put("example", value);
|
||||
final List<Map<String, Object>> output = new ArrayList<Map<String, Object>>(examples.size());
|
||||
for(Map.Entry<String, Object> entry : examples.entrySet()) {
|
||||
final Map<String, Object> kv = new HashMap<String, Object>();
|
||||
kv.put("contentType", entry.getKey());
|
||||
kv.put("example", entry.getValue());
|
||||
output.add(kv);
|
||||
}
|
||||
return output;
|
||||
@ -1169,4 +1227,13 @@ public class DefaultCodegen {
|
||||
}
|
||||
|
||||
|
||||
public String apiFilename(String templateName, String tag)
|
||||
{
|
||||
String suffix = apiTemplateFiles().get(templateName);
|
||||
return apiFileFolder() + File.separator + toApiFilename(tag) + suffix;
|
||||
}
|
||||
|
||||
public boolean shouldOverwrite( String filename ){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,10 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
|
||||
operation.putAll(config.additionalProperties());
|
||||
operation.put("classname", config.toApiName(tag));
|
||||
operation.put("classVarName", config.toApiVarName(tag));
|
||||
operation.put("importPath", config.toApiImport(tag));
|
||||
|
||||
processMimeTypes(swagger.getConsumes(), operation, "consumes");
|
||||
processMimeTypes(swagger.getProduces(), operation, "produces");
|
||||
|
||||
allOperations.add(new HashMap<String, Object>(operation));
|
||||
for (int i = 0; i < allOperations.size(); i++) {
|
||||
@ -175,11 +179,11 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
|
||||
}
|
||||
|
||||
for (String templateName : config.apiTemplateFiles().keySet()) {
|
||||
String suffix = config.apiTemplateFiles().get(templateName);
|
||||
String filename = config.apiFileFolder() +
|
||||
File.separator +
|
||||
config.toApiFilename(tag) +
|
||||
suffix;
|
||||
|
||||
String filename = config.apiFilename( templateName, tag );
|
||||
if( new File( filename ).exists() && !config.shouldOverwrite( filename )){
|
||||
continue;
|
||||
}
|
||||
|
||||
String template = readTemplate(config.templateDir() + File.separator + templateName);
|
||||
Template tmpl = Mustache.compiler()
|
||||
@ -217,6 +221,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
|
||||
bundle.put("models", allModels);
|
||||
bundle.put("apiFolder", config.apiPackage().replace('.', File.separatorChar));
|
||||
bundle.put("modelPackage", config.modelPackage());
|
||||
bundle.put("authMethods", config.fromSecurity(swagger.getSecurityDefinitions()));
|
||||
if (swagger.getExternalDocs() != null) {
|
||||
bundle.put("externalDocs", swagger.getExternalDocs());
|
||||
}
|
||||
@ -291,6 +296,28 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
|
||||
return files;
|
||||
}
|
||||
|
||||
private void processMimeTypes(List<String> mimeTypeList, Map<String, Object> operation, String source) {
|
||||
if(mimeTypeList != null && mimeTypeList.size() > 0) {
|
||||
List<Map<String, String>> c = new ArrayList<Map<String, String>>();
|
||||
int count = 0;
|
||||
for(String key: mimeTypeList) {
|
||||
Map<String, String> mediaType = new HashMap<String, String>();
|
||||
mediaType.put("mediaType", key);
|
||||
count += 1;
|
||||
if (count < mimeTypeList.size()) {
|
||||
mediaType.put("hasMore", "true");
|
||||
}
|
||||
else {
|
||||
mediaType.put("hasMore", null);
|
||||
}
|
||||
c.add(mediaType);
|
||||
}
|
||||
operation.put(source, c);
|
||||
String flagFieldName = "has" + source.substring(0, 1).toUpperCase() + source.substring(1);
|
||||
operation.put(flagFieldName, true);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, List<CodegenOperation>> processPaths(Map<String, Path> paths) {
|
||||
Map<String, List<CodegenOperation>> ops = new HashMap<String, List<CodegenOperation>>();
|
||||
|
||||
@ -427,6 +454,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
|
||||
CodegenModel cm = config.fromModel(key, mm);
|
||||
Map<String, Object> mo = new HashMap<String, Object>();
|
||||
mo.put("model", cm);
|
||||
mo.put("importPath", config.toModelImport(key));
|
||||
models.add(mo);
|
||||
allImports.addAll(cm.imports);
|
||||
}
|
||||
|
@ -1,19 +1,33 @@
|
||||
package com.wordnik.swagger.codegen.examples;
|
||||
|
||||
import com.wordnik.swagger.models.*;
|
||||
import com.wordnik.swagger.models.properties.*;
|
||||
import com.wordnik.swagger.util.Json;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.wordnik.swagger.models.Model;
|
||||
import com.wordnik.swagger.models.ModelImpl;
|
||||
import com.wordnik.swagger.models.properties.ArrayProperty;
|
||||
import com.wordnik.swagger.models.properties.BooleanProperty;
|
||||
import com.wordnik.swagger.models.properties.DateProperty;
|
||||
import com.wordnik.swagger.models.properties.DateTimeProperty;
|
||||
import com.wordnik.swagger.models.properties.DecimalProperty;
|
||||
import com.wordnik.swagger.models.properties.DoubleProperty;
|
||||
import com.wordnik.swagger.models.properties.FileProperty;
|
||||
import com.wordnik.swagger.models.properties.FloatProperty;
|
||||
import com.wordnik.swagger.models.properties.IntegerProperty;
|
||||
import com.wordnik.swagger.models.properties.LongProperty;
|
||||
import com.wordnik.swagger.models.properties.MapProperty;
|
||||
import com.wordnik.swagger.models.properties.ObjectProperty;
|
||||
import com.wordnik.swagger.models.properties.Property;
|
||||
import com.wordnik.swagger.models.properties.RefProperty;
|
||||
import com.wordnik.swagger.models.properties.StringProperty;
|
||||
import com.wordnik.swagger.models.properties.UUIDProperty;
|
||||
import com.wordnik.swagger.util.Json;
|
||||
|
||||
public class ExampleGenerator {
|
||||
protected Map<String, Model> examples;
|
||||
@ -22,7 +36,7 @@ public class ExampleGenerator {
|
||||
this.examples = examples;
|
||||
}
|
||||
|
||||
public List<Map<String, String>> generate(Map<String, String> examples, List<String> mediaTypes, Property property) {
|
||||
public List<Map<String, String>> generate(Map<String, Object> examples, List<String> mediaTypes, Property property) {
|
||||
List<Map<String, String>> output = new ArrayList<Map<String, String>>();
|
||||
Set<String> processedModels = new HashSet<String>();
|
||||
if(examples == null ) {
|
||||
@ -37,7 +51,6 @@ public class ExampleGenerator {
|
||||
String example = Json.pretty(resolvePropertyToExample(mediaType, property, processedModels));
|
||||
|
||||
if(example != null) {
|
||||
example = example.replaceAll("\n", "\\\\n");
|
||||
kv.put("example", example);
|
||||
output.add(kv);
|
||||
}
|
||||
@ -45,7 +58,6 @@ public class ExampleGenerator {
|
||||
else if(property != null && mediaType.startsWith("application/xml")) {
|
||||
String example = new XmlExampleGenerator(this.examples).toXml(property);
|
||||
if(example != null) {
|
||||
example = example.replaceAll("\n", "\\\\n");
|
||||
kv.put("example", example);
|
||||
output.add(kv);
|
||||
}
|
||||
@ -53,12 +65,10 @@ public class ExampleGenerator {
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(String key: examples.keySet()) {
|
||||
String value = examples.get(key);
|
||||
|
||||
Map<String, String> kv = new HashMap<String, String>();
|
||||
kv.put("contentType", key);
|
||||
kv.put("example", value);
|
||||
for(Map.Entry<String, Object> entry: examples.entrySet()) {
|
||||
final Map<String, String> kv = new HashMap<String, String>();
|
||||
kv.put("contentType", entry.getKey());
|
||||
kv.put("example", Json.pretty(entry.getValue()));
|
||||
output.add(kv);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import com.wordnik.swagger.models.properties.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
|
||||
public class XmlExampleGenerator {
|
||||
public static String NEWLINE = "\n";
|
||||
public static String TAG_START = "<";
|
||||
@ -16,6 +18,7 @@ public class XmlExampleGenerator {
|
||||
protected Map<String, Model> examples;
|
||||
protected SimpleDateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
protected SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
private static String EMPTY = "";
|
||||
|
||||
public XmlExampleGenerator(Map<String, Model> examples) {
|
||||
this.examples = examples;
|
||||
@ -24,29 +27,36 @@ public class XmlExampleGenerator {
|
||||
}
|
||||
|
||||
public String toXml(Property property) {
|
||||
return toXml(null, property, 0);
|
||||
return toXml(null, property, 0, Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
protected String toXml(Model model, int indent) {
|
||||
protected String toXml(Model model, int indent, Collection<String> path) {
|
||||
if(model instanceof RefModel) {
|
||||
RefModel ref = (RefModel) model;
|
||||
Model actualModel = examples.get(ref.getSimpleRef());
|
||||
if(actualModel instanceof ModelImpl)
|
||||
return modelImplToXml((ModelImpl)actualModel, indent);
|
||||
return modelImplToXml((ModelImpl) actualModel, indent, path);
|
||||
}
|
||||
else if(model instanceof ModelImpl) {
|
||||
return modelImplToXml((ModelImpl)model, indent);
|
||||
return modelImplToXml((ModelImpl) model, indent, path);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String modelImplToXml(ModelImpl model, int indent) {
|
||||
protected String modelImplToXml(ModelImpl model, int indent, Collection<String> path) {
|
||||
final String modelName = model.getName();
|
||||
if (path.contains(modelName)) {
|
||||
return EMPTY;
|
||||
}
|
||||
final Set<String> selfPath = new HashSet<String>(path);
|
||||
selfPath.add(modelName);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// attributes
|
||||
Map<String, Property> attributes = new LinkedHashMap<String, Property>();
|
||||
Map<String, Property> elements = new LinkedHashMap<String, Property>();
|
||||
|
||||
String name = model.getName();
|
||||
String name = modelName;
|
||||
String namespace;
|
||||
String prefix;
|
||||
Boolean wrapped;
|
||||
@ -67,13 +77,17 @@ public class XmlExampleGenerator {
|
||||
sb.append(name);
|
||||
for(String pName : attributes.keySet()) {
|
||||
Property p = attributes.get(pName);
|
||||
sb.append(" ").append(pName).append("=").append(quote(toXml(null, p, 0)));
|
||||
sb.append(" ").append(pName).append("=").append(quote(toXml(null, p, 0, selfPath)));
|
||||
}
|
||||
sb.append(CLOSE_TAG);
|
||||
sb.append(NEWLINE);
|
||||
for(String pName : elements.keySet()) {
|
||||
Property p = elements.get(pName);
|
||||
sb.append(toXml(pName, p, indent + 1));
|
||||
final String asXml = toXml(pName, p, indent + 1, selfPath);
|
||||
if (StringUtils.isEmpty(asXml)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(asXml);
|
||||
sb.append(NEWLINE);
|
||||
}
|
||||
sb.append(indent(indent)).append(TAG_END).append(name).append(CLOSE_TAG);
|
||||
@ -85,7 +99,7 @@ public class XmlExampleGenerator {
|
||||
return "\"" + string + "\"";
|
||||
}
|
||||
|
||||
protected String toXml(String name, Property property, int indent) {
|
||||
protected String toXml(String name, Property property, int indent, Collection<String> path) {
|
||||
if(property == null) {
|
||||
return "";
|
||||
}
|
||||
@ -98,12 +112,16 @@ public class XmlExampleGenerator {
|
||||
if(property.getXml() != null && property.getXml().getWrapped())
|
||||
wrapped = true;
|
||||
if(wrapped) {
|
||||
String prefix = EMPTY;
|
||||
if(name != null) {
|
||||
sb.append(indent(indent));
|
||||
sb.append(openTag(name));
|
||||
sb.append(NEWLINE);
|
||||
prefix = NEWLINE;
|
||||
}
|
||||
final String asXml = toXml(name, inner, indent + 1, path);
|
||||
if (StringUtils.isNotEmpty(asXml)) {
|
||||
sb.append(prefix).append(asXml);
|
||||
}
|
||||
sb.append(toXml(name, inner, indent + 1));
|
||||
if(name != null) {
|
||||
sb.append(NEWLINE);
|
||||
sb.append(indent(indent));
|
||||
@ -111,12 +129,12 @@ public class XmlExampleGenerator {
|
||||
}
|
||||
}
|
||||
else
|
||||
sb.append(toXml(name, inner, indent));
|
||||
sb.append(toXml(name, inner, indent, path));
|
||||
}
|
||||
else if(property instanceof RefProperty) {
|
||||
RefProperty ref = (RefProperty) property;
|
||||
Model actualModel = examples.get(ref.getSimpleRef());
|
||||
sb.append(toXml(actualModel, indent));
|
||||
sb.append(toXml(actualModel, indent, path));
|
||||
}
|
||||
else {
|
||||
if(name != null) {
|
||||
|
@ -0,0 +1,365 @@
|
||||
package com.wordnik.swagger.codegen.languages;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.samskivert.mustache.Mustache;
|
||||
import com.samskivert.mustache.Template;
|
||||
import com.wordnik.swagger.codegen.*;
|
||||
import com.wordnik.swagger.models.auth.SecuritySchemeDefinition;
|
||||
import com.wordnik.swagger.models.properties.*;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
|
||||
public class AkkaScalaClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
Logger LOGGER = LoggerFactory.getLogger(AkkaScalaClientCodegen.class);
|
||||
|
||||
protected String mainPackage = "io.swagger.client";
|
||||
|
||||
protected String invokerPackage = mainPackage + ".core";
|
||||
protected String groupId = "com.wordnik";
|
||||
protected String artifactId = "swagger-client";
|
||||
protected String artifactVersion = "1.0.0";
|
||||
protected String sourceFolder = "src/main/scala";
|
||||
protected String resourcesFolder = "src/main/resources";
|
||||
protected String configKey = "apiRequest";
|
||||
protected int defaultTimeoutInMs = 5000;
|
||||
protected String configKeyPath = mainPackage;
|
||||
|
||||
protected boolean registerNonStandardStatusCodes = true;
|
||||
protected boolean renderJavadoc = true;
|
||||
protected boolean removeOAuthSecurities = true;
|
||||
/**
|
||||
* If set to true, only the default response (the one with le lowest 2XX code) will be considered as a success, and all
|
||||
* others as ApiErrors.
|
||||
* If set to false, all responses defined in the model will be considered as a success upon reception. Only http errors,
|
||||
* unmarshalling problems and any other RuntimeException will be considered as ApiErrors.
|
||||
*/
|
||||
protected boolean onlyOneSuccess = true;
|
||||
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.CLIENT;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "akka-scala";
|
||||
}
|
||||
|
||||
public String getHelp() {
|
||||
return "Generates a Scala client library base on Akka/Spray.";
|
||||
}
|
||||
|
||||
public AkkaScalaClientCodegen() {
|
||||
super();
|
||||
outputFolder = "generated-code/scala";
|
||||
modelTemplateFiles.put("model.mustache", ".scala");
|
||||
apiTemplateFiles.put("api.mustache", ".scala");
|
||||
templateDir = "akka-scala";
|
||||
apiPackage = mainPackage + ".api";
|
||||
modelPackage = mainPackage + ".model";
|
||||
|
||||
reservedWords = new HashSet<String>(
|
||||
Arrays.asList(
|
||||
"abstract", "case", "catch", "class", "def", "do", "else", "extends",
|
||||
"false", "final", "finally", "for", "forSome", "if", "implicit",
|
||||
"import", "lazy", "match", "new", "null", "object", "override", "package",
|
||||
"private", "protected", "return", "sealed", "super", "this", "throw",
|
||||
"trait", "try", "true", "type", "val", "var", "while", "with", "yield")
|
||||
);
|
||||
|
||||
additionalProperties.put("invokerPackage", invokerPackage);
|
||||
additionalProperties.put("groupId", groupId);
|
||||
additionalProperties.put("artifactId", artifactId);
|
||||
additionalProperties.put("artifactVersion", artifactVersion);
|
||||
additionalProperties.put("configKey", configKey);
|
||||
additionalProperties.put("configKeyPath", configKeyPath);
|
||||
additionalProperties.put("defaultTimeout", defaultTimeoutInMs);
|
||||
if (renderJavadoc)
|
||||
additionalProperties.put("javadocRenderer", new JavadocLambda());
|
||||
additionalProperties.put("fnCapitalize", new CapitalizeLambda());
|
||||
additionalProperties.put("fnCamelize", new CamelizeLambda(false));
|
||||
additionalProperties.put("fnEnumEntry", new EnumEntryLambda());
|
||||
additionalProperties.put("onlyOneSuccess", onlyOneSuccess);
|
||||
|
||||
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
|
||||
supportingFiles.add(new SupportingFile("reference.mustache", resourcesFolder, "reference.conf"));
|
||||
final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator);
|
||||
supportingFiles.add(new SupportingFile("apiRequest.mustache", invokerFolder, "ApiRequest.scala"));
|
||||
supportingFiles.add(new SupportingFile("apiInvoker.mustache", invokerFolder, "ApiInvoker.scala"));
|
||||
supportingFiles.add(new SupportingFile("requests.mustache", invokerFolder, "requests.scala"));
|
||||
supportingFiles.add(new SupportingFile("apiSettings.mustache", invokerFolder, "ApiSettings.scala"));
|
||||
final String apiFolder = (sourceFolder + File.separator + apiPackage).replace(".", File.separator);
|
||||
supportingFiles.add(new SupportingFile("enumsSerializers.mustache", apiFolder, "EnumsSerializers.scala"));
|
||||
|
||||
importMapping.remove("Seq");
|
||||
importMapping.remove("List");
|
||||
importMapping.remove("Set");
|
||||
importMapping.remove("Map");
|
||||
|
||||
importMapping.put("DateTime", "org.joda.time.DateTime");
|
||||
|
||||
typeMapping = new HashMap<String, String>();
|
||||
typeMapping.put("array", "Seq");
|
||||
typeMapping.put("set", "Set");
|
||||
typeMapping.put("boolean", "Boolean");
|
||||
typeMapping.put("string", "String");
|
||||
typeMapping.put("int", "Int");
|
||||
typeMapping.put("integer", "Int");
|
||||
typeMapping.put("long", "Long");
|
||||
typeMapping.put("float", "Float");
|
||||
typeMapping.put("byte", "Byte");
|
||||
typeMapping.put("short", "Short");
|
||||
typeMapping.put("char", "Char");
|
||||
typeMapping.put("long", "Long");
|
||||
typeMapping.put("double", "Double");
|
||||
typeMapping.put("object", "Any");
|
||||
typeMapping.put("file", "File");
|
||||
typeMapping.put("number", "Double");
|
||||
|
||||
languageSpecificPrimitives = new HashSet<String>(
|
||||
Arrays.asList(
|
||||
"String",
|
||||
"boolean",
|
||||
"Boolean",
|
||||
"Double",
|
||||
"Int",
|
||||
"Long",
|
||||
"Float",
|
||||
"Object",
|
||||
"List",
|
||||
"Seq",
|
||||
"Map")
|
||||
);
|
||||
instantiationTypes.put("array", "ListBuffer");
|
||||
instantiationTypes.put("map", "Map");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeReservedWord(String name) {
|
||||
return "`" + name + "`";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
public String modelFileFolder() {
|
||||
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
|
||||
if (registerNonStandardStatusCodes) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, ArrayList<CodegenOperation>> opsMap = (Map<String, ArrayList<CodegenOperation>>) objs.get("operations");
|
||||
HashSet<Integer> unknownCodes = new HashSet<Integer>();
|
||||
for (CodegenOperation operation : opsMap.get("operation")) {
|
||||
for (CodegenResponse response : operation.responses) {
|
||||
if ("default".equals(response.code))
|
||||
continue;
|
||||
try {
|
||||
int code = Integer.parseInt(response.code);
|
||||
if (code >= 600) {
|
||||
unknownCodes.add(code);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.error("Status code is not an integer : response.code", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!unknownCodes.isEmpty()) {
|
||||
additionalProperties.put("unknownStatusCodes", unknownCodes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Unable to find operations List", e);
|
||||
}
|
||||
}
|
||||
return super.postProcessOperations(objs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeDeclaration(Property p) {
|
||||
if (p instanceof ArrayProperty) {
|
||||
ArrayProperty ap = (ArrayProperty) p;
|
||||
Property inner = ap.getItems();
|
||||
return getSwaggerType(p) + "[" + 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 List<CodegenSecurity> fromSecurity(Map<String, SecuritySchemeDefinition> schemes) {
|
||||
final List<CodegenSecurity> codegenSecurities = super.fromSecurity(schemes);
|
||||
if (!removeOAuthSecurities)
|
||||
return codegenSecurities;
|
||||
|
||||
// Remove OAuth securities
|
||||
Iterator<CodegenSecurity> it = codegenSecurities.iterator();
|
||||
while (it.hasNext()) {
|
||||
final CodegenSecurity security = it.next();
|
||||
if (security.isOAuth)
|
||||
it.remove();
|
||||
}
|
||||
// Adapt 'hasMore'
|
||||
it = codegenSecurities.iterator();
|
||||
while (it.hasNext()) {
|
||||
final CodegenSecurity security = it.next();
|
||||
security.hasMore = it.hasNext();
|
||||
}
|
||||
|
||||
if (codegenSecurities.isEmpty())
|
||||
return null;
|
||||
return codegenSecurities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toOperationId(String operationId) {
|
||||
return super.toOperationId(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, operationId));
|
||||
}
|
||||
|
||||
private String formatIdentifier(String name, boolean capitalized) {
|
||||
String identifier = camelize(name, true);
|
||||
if (capitalized)
|
||||
identifier = StringUtils.capitalize(identifier);
|
||||
if (identifier.matches("[a-zA-Z_$][\\w_$]+") && !reservedWords.contains(identifier))
|
||||
return identifier;
|
||||
return escapeReservedWord(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toParamName(String name) { return formatIdentifier(name, false); }
|
||||
|
||||
@Override
|
||||
public String toVarName(String name) {
|
||||
return formatIdentifier(name, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toEnumName(CodegenProperty property)
|
||||
{
|
||||
return formatIdentifier(property.baseName, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSwaggerType(Property p) {
|
||||
String swaggerType = super.getSwaggerType(p);
|
||||
String type;
|
||||
if (typeMapping.containsKey(swaggerType)) {
|
||||
type = typeMapping.get(swaggerType);
|
||||
if (languageSpecificPrimitives.contains(type))
|
||||
return toModelName(type);
|
||||
} else
|
||||
type = swaggerType;
|
||||
return toModelName(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toInstantiationType(Property p) {
|
||||
if (p instanceof MapProperty) {
|
||||
MapProperty ap = (MapProperty) p;
|
||||
String inner = getSwaggerType(ap.getAdditionalProperties());
|
||||
return instantiationTypes.get("map") + "[String, " + inner + "]";
|
||||
} else if (p instanceof ArrayProperty) {
|
||||
ArrayProperty ap = (ArrayProperty) p;
|
||||
String inner = getSwaggerType(ap.getItems());
|
||||
return instantiationTypes.get("array") + "[" + inner + "]";
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toDefaultValue(Property p) {
|
||||
if (!p.getRequired())
|
||||
return "None";
|
||||
if (p instanceof StringProperty)
|
||||
return "null";
|
||||
else if (p instanceof BooleanProperty)
|
||||
return "null";
|
||||
else if (p instanceof DateProperty)
|
||||
return "null";
|
||||
else if (p instanceof DateTimeProperty)
|
||||
return "null";
|
||||
else if (p instanceof DoubleProperty)
|
||||
return "null";
|
||||
else if (p instanceof FloatProperty)
|
||||
return "null";
|
||||
else if (p instanceof IntegerProperty)
|
||||
return "null";
|
||||
else if (p instanceof LongProperty)
|
||||
return "null";
|
||||
else if (p instanceof MapProperty) {
|
||||
MapProperty ap = (MapProperty) p;
|
||||
String inner = getSwaggerType(ap.getAdditionalProperties());
|
||||
return "Map[String, " + inner + "].empty ";
|
||||
} else if (p instanceof ArrayProperty) {
|
||||
ArrayProperty ap = (ArrayProperty) p;
|
||||
String inner = getSwaggerType(ap.getItems());
|
||||
return "Seq[" + inner + "].empty ";
|
||||
} else
|
||||
return "null";
|
||||
}
|
||||
|
||||
private static abstract class CustomLambda implements Mustache.Lambda {
|
||||
@Override
|
||||
public void execute(Template.Fragment frag, Writer out) throws IOException {
|
||||
final StringWriter tempWriter = new StringWriter();
|
||||
frag.execute(tempWriter);
|
||||
out.write(formatFragment(tempWriter.toString()));
|
||||
}
|
||||
public abstract String formatFragment(String fragment);
|
||||
}
|
||||
|
||||
|
||||
private static class JavadocLambda extends CustomLambda {
|
||||
@Override
|
||||
public String formatFragment(String fragment) {
|
||||
final String[] lines = fragment.split("\\r?\\n");
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(" /**\n");
|
||||
for (String line : lines) {
|
||||
sb.append(" * ").append(line).append("\n");
|
||||
}
|
||||
sb.append(" */\n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class CapitalizeLambda extends CustomLambda {
|
||||
@Override
|
||||
public String formatFragment(String fragment) {
|
||||
return StringUtils.capitalize(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CamelizeLambda extends CustomLambda {
|
||||
private final boolean capitalizeFirst;
|
||||
|
||||
public CamelizeLambda(boolean capitalizeFirst) {
|
||||
this.capitalizeFirst = capitalizeFirst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatFragment(String fragment) {
|
||||
return camelize(fragment, !capitalizeFirst);
|
||||
}
|
||||
}
|
||||
|
||||
private class EnumEntryLambda extends CustomLambda {
|
||||
@Override
|
||||
public String formatFragment(String fragment) {
|
||||
return formatIdentifier(fragment, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,6 +13,7 @@ public class AndroidClientCodegen extends DefaultCodegen implements CodegenConfi
|
||||
protected String artifactVersion = "1.0.0";
|
||||
protected String projectFolder = "src/main";
|
||||
protected String sourceFolder = projectFolder + "/java";
|
||||
protected Boolean useAndroidMavenGradlePlugin = true;
|
||||
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.CLIENT;
|
||||
@ -52,6 +53,9 @@ public class AndroidClientCodegen extends DefaultCodegen implements CodegenConfi
|
||||
additionalProperties.put("artifactVersion", artifactVersion);
|
||||
|
||||
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
|
||||
additionalProperties.put("useAndroidMavenGradlePlugin", useAndroidMavenGradlePlugin);
|
||||
|
||||
supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
|
||||
supportingFiles.add(new SupportingFile("build.mustache", "", "build.gradle"));
|
||||
supportingFiles.add(new SupportingFile("manifest.mustache", projectFolder, "AndroidManifest.xml"));
|
||||
supportingFiles.add(new SupportingFile("apiInvoker.mustache",
|
||||
|
@ -7,7 +7,7 @@ import java.util.*;
|
||||
import java.io.File;
|
||||
|
||||
public class CSharpClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
protected String invokerPackage = "io.swagger.client";
|
||||
protected String invokerPackage = "IO.Swagger.Client";
|
||||
protected String groupId = "io.swagger";
|
||||
protected String artifactId = "swagger-csharp-client";
|
||||
protected String artifactVersion = "1.0.0";
|
||||
@ -31,8 +31,8 @@ public class CSharpClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
modelTemplateFiles.put("model.mustache", ".cs");
|
||||
apiTemplateFiles.put("api.mustache", ".cs");
|
||||
templateDir = "csharp";
|
||||
apiPackage = "io.swagger.Api";
|
||||
modelPackage = "io.swagger.Model";
|
||||
apiPackage = "IO.Swagger.Api";
|
||||
modelPackage = "IO.Swagger.Model";
|
||||
|
||||
reservedWords = new HashSet<String> (
|
||||
Arrays.asList(
|
||||
@ -80,7 +80,7 @@ public class CSharpClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
typeMapping.put("double", "double?");
|
||||
typeMapping.put("number", "double?");
|
||||
typeMapping.put("Date", "DateTime");
|
||||
typeMapping.put("file", "byte[]");
|
||||
typeMapping.put("file", "string"); // path to file
|
||||
typeMapping.put("array", "List");
|
||||
typeMapping.put("map", "Dictionary");
|
||||
|
||||
|
@ -130,7 +130,6 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
return toModelName(name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getTypeDeclaration(Property p) {
|
||||
if(p instanceof ArrayProperty) {
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.wordnik.swagger.codegen.languages;
|
||||
|
||||
import com.wordnik.swagger.models.Operation;
|
||||
import com.wordnik.swagger.models.Path;
|
||||
import com.wordnik.swagger.util.Json;
|
||||
import com.wordnik.swagger.codegen.*;
|
||||
import com.wordnik.swagger.models.properties.*;
|
||||
|
||||
@ -14,7 +12,6 @@ public class JaxRSServerCodegen extends JavaClientCodegen implements CodegenConf
|
||||
protected String groupId = "io.swagger";
|
||||
protected String artifactId = "swagger-jaxrs-server";
|
||||
protected String artifactVersion = "1.0.0";
|
||||
protected String sourceFolder = "src/main/java";
|
||||
protected String title = "Swagger Server";
|
||||
|
||||
public CodegenType getTag() {
|
||||
@ -31,12 +28,19 @@ public class JaxRSServerCodegen extends JavaClientCodegen implements CodegenConf
|
||||
|
||||
public JaxRSServerCodegen() {
|
||||
super();
|
||||
outputFolder = "generated-code/javaJaxRS";
|
||||
|
||||
sourceFolder = "src/gen/java";
|
||||
|
||||
outputFolder = System.getProperty( "swagger.codegen.jaxrs.genfolder", "generated-code/javaJaxRS" );
|
||||
modelTemplateFiles.put("model.mustache", ".java");
|
||||
apiTemplateFiles.put("api.mustache", ".java");
|
||||
apiTemplateFiles.put("apiService.mustache", ".java");
|
||||
apiTemplateFiles.put("apiServiceImpl.mustache", ".java");
|
||||
apiTemplateFiles.put("apiServiceFactory.mustache", ".java");
|
||||
|
||||
templateDir = "JavaJaxRS";
|
||||
apiPackage = "io.swagger.api";
|
||||
modelPackage = "io.swagger.model";
|
||||
apiPackage = System.getProperty( "swagger.codegen.jaxrs.apipackage", "io.swagger.api") ;
|
||||
modelPackage = System.getProperty( "swagger.codegen.jaxrs.modelpackage", "io.swagger.model" );
|
||||
|
||||
additionalProperties.put("invokerPackage", invokerPackage);
|
||||
additionalProperties.put("groupId", groupId);
|
||||
@ -146,4 +150,44 @@ public class JaxRSServerCodegen extends JavaClientCodegen implements CodegenConf
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apiFilename(String templateName, String tag) {
|
||||
|
||||
String result = super.apiFilename(templateName, tag);
|
||||
|
||||
if( templateName.endsWith( "Impl.mustache")){
|
||||
int ix = result.lastIndexOf( '/' );
|
||||
result = result.substring( 0, ix ) + "/impl" + result.substring( ix, result.length()-5 ) + "ServiceImpl.java";
|
||||
|
||||
String output = System.getProperty( "swagger.codegen.jaxrs.impl.source" );
|
||||
if( output != null ){
|
||||
result = result.replace( apiFileFolder(), implFileFolder(output));
|
||||
}
|
||||
}
|
||||
else if( templateName.endsWith( "Factory.mustache")){
|
||||
int ix = result.lastIndexOf( '/' );
|
||||
result = result.substring( 0, ix ) + "/factories" + result.substring( ix, result.length()-5 ) + "ServiceFactory.java";
|
||||
|
||||
String output = System.getProperty( "swagger.codegen.jaxrs.impl.source" );
|
||||
if( output != null ){
|
||||
result = result.replace( apiFileFolder(), implFileFolder(output));
|
||||
}
|
||||
}
|
||||
else if( templateName.endsWith( "Service.mustache")) {
|
||||
int ix = result.lastIndexOf('.');
|
||||
result = result.substring(0, ix) + "Service.java";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String implFileFolder(String output) {
|
||||
return outputFolder + "/" + output + "/" + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
public boolean shouldOverwrite( String filename ){
|
||||
|
||||
return !filename.endsWith( "ServiceImpl.java") && !filename.endsWith( "ServiceFactory.java");
|
||||
}
|
||||
}
|
@ -1,11 +1,19 @@
|
||||
package com.wordnik.swagger.codegen.languages;
|
||||
|
||||
import com.wordnik.swagger.codegen.*;
|
||||
import com.wordnik.swagger.util.Json;
|
||||
import com.wordnik.swagger.models.properties.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.wordnik.swagger.codegen.CodegenConfig;
|
||||
import com.wordnik.swagger.codegen.CodegenOperation;
|
||||
import com.wordnik.swagger.codegen.CodegenParameter;
|
||||
import com.wordnik.swagger.codegen.CodegenResponse;
|
||||
import com.wordnik.swagger.codegen.CodegenType;
|
||||
import com.wordnik.swagger.codegen.DefaultCodegen;
|
||||
import com.wordnik.swagger.codegen.SupportingFile;
|
||||
|
||||
public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
protected String apiVersion = "1.0.0";
|
||||
@ -156,8 +164,10 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
|
||||
Map<String, Object> objectMap = (Map<String, Object>)objs.get("operations");
|
||||
List<CodegenOperation> operations = (List<CodegenOperation>)objectMap.get("operation");
|
||||
@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) {
|
||||
operation.httpMethod = operation.httpMethod.toLowerCase();
|
||||
List<CodegenParameter> params = operation.allParams;
|
||||
@ -170,20 +180,14 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig
|
||||
resp.code = "default";
|
||||
}
|
||||
}
|
||||
if(operation.examples != null && operation.examples.size() > 0) {
|
||||
List<Map<String, String>> examples = operation.examples;
|
||||
for(int i = examples.size() - 1; i >= 0; i--) {
|
||||
Map<String, String> example = examples.get(i);
|
||||
String contentType = example.get("contentType");
|
||||
if(contentType != null && contentType.indexOf("application/json") == 0) {
|
||||
String jsonExample = example.get("example");
|
||||
if(jsonExample != null) {
|
||||
jsonExample = jsonExample.replaceAll("\\\\n", "\n");
|
||||
example.put("example", jsonExample);
|
||||
}
|
||||
if(operation.examples != null && !operation.examples.isEmpty()) {
|
||||
// Leave application/json* items only
|
||||
for (Iterator<Map<String, String>> it = operation.examples.iterator(); it.hasNext();) {
|
||||
final Map<String, String> example = it.next();
|
||||
final String contentType = example.get("contentType");
|
||||
if (contentType == null || !contentType.startsWith("application/json")) {
|
||||
it.remove();
|
||||
}
|
||||
else
|
||||
examples.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
supportingFiles.add(new SupportingFile("SWGApiClient.m", sourceFolder, "SWGApiClient.m"));
|
||||
supportingFiles.add(new SupportingFile("SWGFile.h", sourceFolder, "SWGFile.h"));
|
||||
supportingFiles.add(new SupportingFile("SWGFile.m", sourceFolder, "SWGFile.m"));
|
||||
supportingFiles.add(new SupportingFile("SWGDate.h", sourceFolder, "SWGDate.h"));
|
||||
supportingFiles.add(new SupportingFile("SWGDate.m", sourceFolder, "SWGDate.m"));
|
||||
supportingFiles.add(new SupportingFile("JSONValueTransformer+ISO8601.m", sourceFolder, "JSONValueTransformer+ISO8601.m"));
|
||||
supportingFiles.add(new SupportingFile("JSONValueTransformer+ISO8601.h", sourceFolder, "JSONValueTransformer+ISO8601.h"));
|
||||
supportingFiles.add(new SupportingFile("Podfile.mustache", "", "Podfile"));
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
typeMapping.put("list", "array");
|
||||
|
||||
supportingFiles.add(new SupportingFile("composer.mustache", packagePath, "composer.json"));
|
||||
supportingFiles.add(new SupportingFile("configuration.mustache", packagePath + "/lib", "Configuration.php"));
|
||||
supportingFiles.add(new SupportingFile("APIClient.mustache", packagePath + "/lib", "APIClient.php"));
|
||||
supportingFiles.add(new SupportingFile("APIClientException.mustache", packagePath + "/lib", "APIClientException.php"));
|
||||
supportingFiles.add(new SupportingFile("require.mustache", packagePath, invokerPackage + ".php"));
|
||||
|
@ -34,13 +34,12 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
apiTemplateFiles.put("api.mustache", ".py");
|
||||
templateDir = "python";
|
||||
|
||||
apiPackage = invokerPackage;
|
||||
apiPackage = invokerPackage + ".apis";
|
||||
modelPackage = invokerPackage + ".models";
|
||||
|
||||
languageSpecificPrimitives.clear();
|
||||
languageSpecificPrimitives.add("int");
|
||||
languageSpecificPrimitives.add("float");
|
||||
languageSpecificPrimitives.add("long");
|
||||
languageSpecificPrimitives.add("list");
|
||||
languageSpecificPrimitives.add("bool");
|
||||
languageSpecificPrimitives.add("str");
|
||||
@ -49,7 +48,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
typeMapping.clear();
|
||||
typeMapping.put("integer", "int");
|
||||
typeMapping.put("float", "float");
|
||||
typeMapping.put("long", "long");
|
||||
typeMapping.put("long", "int");
|
||||
typeMapping.put("double", "float");
|
||||
typeMapping.put("array", "list");
|
||||
typeMapping.put("map", "map");
|
||||
@ -70,8 +69,11 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
supportingFiles.add(new SupportingFile("README.mustache", eggPackage, "README.md"));
|
||||
supportingFiles.add(new SupportingFile("setup.mustache", eggPackage, "setup.py"));
|
||||
supportingFiles.add(new SupportingFile("swagger.mustache", invokerPackage, "swagger.py"));
|
||||
supportingFiles.add(new SupportingFile("rest.mustache", invokerPackage, "rest.py"));
|
||||
supportingFiles.add(new SupportingFile("util.mustache", invokerPackage, "util.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__package.mustache", invokerPackage, "__init__.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__model.mustache", modelPackage.replace('.', File.separatorChar), "__init__.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__api.mustache", apiPackage.replace('.', File.separatorChar), "__init__.py"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,9 +115,9 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
if(languageSpecificPrimitives.contains(type)) {
|
||||
return type;
|
||||
}
|
||||
} else {
|
||||
type = toModelName(swaggerType);
|
||||
}
|
||||
else
|
||||
type = swaggerType;
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -133,9 +135,9 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
if (name.matches("^[A-Z_]*$"))
|
||||
name = name.toLowerCase();
|
||||
|
||||
// camelize (lower first character) the variable name
|
||||
// underscore the variable name
|
||||
// petId => pet_id
|
||||
name = underscore(name);
|
||||
name = underscore(dropDots(name));
|
||||
|
||||
// for reserved word or word starting with number, append _
|
||||
if(reservedWords.contains(name) || name.matches("^\\d.*"))
|
||||
@ -144,6 +146,10 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
return name;
|
||||
}
|
||||
|
||||
private static String dropDots(String str) {
|
||||
return str.replaceAll("\\.", "_");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toParamName(String name) {
|
||||
// should be the same as variable name
|
||||
@ -168,8 +174,8 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");
|
||||
|
||||
// underscore the model file name
|
||||
// PhoneNumber.rb => phone_number.rb
|
||||
return underscore(name);
|
||||
// PhoneNumber => phone_number
|
||||
return underscore(dropDots(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -8,10 +8,9 @@ import java.util.*;
|
||||
import java.io.File;
|
||||
|
||||
public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
protected String invokerPackage = "com.wordnik.client";
|
||||
protected String groupId = "com.wordnik";
|
||||
protected String artifactId = "swagger-client";
|
||||
protected String artifactVersion = "1.0.0";
|
||||
protected String gemName = "swagger_client";
|
||||
protected String moduleName = null;
|
||||
protected String libFolder = "lib";
|
||||
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.CLIENT;
|
||||
@ -25,10 +24,18 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
return "Generates a Ruby client library.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Ruby module name from the gem name, e.g. use "SwaggerClient" for "swagger_client".
|
||||
*/
|
||||
public String generateModuleName() {
|
||||
return camelize(gemName.replaceAll("[^\\w]+", "_"));
|
||||
}
|
||||
|
||||
public RubyClientCodegen() {
|
||||
super();
|
||||
modelPackage = "models";
|
||||
apiPackage = "lib";
|
||||
moduleName = generateModuleName();
|
||||
modelPackage = gemName + "/models";
|
||||
apiPackage = gemName + "/api";
|
||||
outputFolder = "generated-code/ruby";
|
||||
modelTemplateFiles.put("model.mustache", ".rb");
|
||||
apiTemplateFiles.put("api.mustache", ".rb");
|
||||
@ -39,17 +46,15 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
|
||||
reservedWords = new HashSet<String> (
|
||||
Arrays.asList(
|
||||
"__FILE__", "and", "def", "end", "in", "or", "self", "unless", "__LINE__",
|
||||
"__FILE__", "and", "def", "end", "in", "or", "self", "unless", "__LINE__",
|
||||
"begin", "defined?", "ensure", "module", "redo", "super", "until", "BEGIN",
|
||||
"break", "do", "false", "next", "rescue", "then", "when", "END", "case",
|
||||
"break", "do", "false", "next", "rescue", "then", "when", "END", "case",
|
||||
"else", "for", "nil", "retry", "true", "while", "alias", "class", "elsif",
|
||||
"if", "not", "return", "undef", "yield")
|
||||
);
|
||||
|
||||
additionalProperties.put("invokerPackage", invokerPackage);
|
||||
additionalProperties.put("groupId", groupId);
|
||||
additionalProperties.put("artifactId", artifactId);
|
||||
additionalProperties.put("artifactVersion", artifactVersion);
|
||||
additionalProperties.put("gemName", gemName);
|
||||
additionalProperties.put("moduleName", moduleName);
|
||||
|
||||
languageSpecificPrimitives.add("int");
|
||||
languageSpecificPrimitives.add("array");
|
||||
@ -64,15 +69,18 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
typeMapping.put("List", "array");
|
||||
typeMapping.put("map", "map");
|
||||
|
||||
supportingFiles.add(new SupportingFile("swagger-client.gemspec.mustache", "", "swagger-client.gemspec"));
|
||||
supportingFiles.add(new SupportingFile("swagger-client.mustache", "", "lib/swagger-client.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger.mustache", "", "lib/swagger.rb"));
|
||||
supportingFiles.add(new SupportingFile("monkey.mustache", "", "lib/monkey.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/request.mustache", "", "lib/swagger/request.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/response.mustache", "", "lib/swagger/response.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/version.mustache", "", "lib/swagger/version.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/configuration.mustache", "", "lib/swagger/configuration.rb"));
|
||||
supportingFiles.add(new SupportingFile("base_object.mustache", "", "models/base_object.rb"));
|
||||
String baseFolder = "lib/" + gemName;
|
||||
String swaggerFolder = baseFolder + "/swagger";
|
||||
String modelFolder = baseFolder + "/models";
|
||||
supportingFiles.add(new SupportingFile("swagger_client.gemspec.mustache", "", gemName + ".gemspec"));
|
||||
supportingFiles.add(new SupportingFile("swagger_client.mustache", "lib", gemName + ".rb"));
|
||||
supportingFiles.add(new SupportingFile("monkey.mustache", baseFolder, "monkey.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger.mustache", baseFolder, "swagger.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/request.mustache", swaggerFolder, "request.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/response.mustache", swaggerFolder, "response.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/version.mustache", swaggerFolder, "version.rb"));
|
||||
supportingFiles.add(new SupportingFile("swagger/configuration.mustache", swaggerFolder, "configuration.rb"));
|
||||
supportingFiles.add(new SupportingFile("base_object.mustache", modelFolder, "base_object.rb"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,11 +90,11 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return outputFolder + "/" + apiPackage().replace('.', File.separatorChar);
|
||||
return outputFolder + File.separatorChar + "lib" + File.separatorChar + gemName + File.separatorChar + "api";
|
||||
}
|
||||
|
||||
public String modelFileFolder() {
|
||||
return outputFolder + "/" + modelPackage().replace('.', File.separatorChar);
|
||||
return outputFolder + File.separatorChar + "lib" + File.separatorChar + gemName + File.separatorChar + "models";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,13 +158,13 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
// 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);
|
||||
@ -167,11 +175,11 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
// 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");
|
||||
|
||||
|
||||
// underscore the model file name
|
||||
// PhoneNumber.rb => phone_number.rb
|
||||
return underscore(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toApiFilename(String name) {
|
||||
@ -186,7 +194,7 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
public String toApiName(String name) {
|
||||
if(name.length() == 0)
|
||||
return "DefaultApi";
|
||||
// e.g. phone_number_api => PhoneNumberApi
|
||||
// e.g. phone_number_api => PhoneNumberApi
|
||||
return camelize(name) + "Api";
|
||||
}
|
||||
|
||||
@ -196,8 +204,17 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
if(reservedWords.contains(operationId))
|
||||
throw new RuntimeException(operationId + " (reserved word) cannot be used as method name");
|
||||
|
||||
return underscore(operationId);
|
||||
return underscore(operationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelImport(String name) {
|
||||
return modelPackage() + "/" + toModelFilename(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toApiImport(String name) {
|
||||
return apiPackage() + "/" + toApiFilename(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package {{package}};
|
||||
|
||||
import {{modelPackage}}.*;
|
||||
import {{package}}.{{classname}}Service;
|
||||
import {{package}}.factories.{{classname}}ServiceFactory;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiParam;
|
||||
|
||||
@ -21,26 +23,31 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.*;
|
||||
|
||||
@Path("/{{baseName}}")
|
||||
{{#hasConsumes}}@Consumes({ {{#consumes}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }){{/hasConsumes}}
|
||||
{{#hasProduces}}@Produces({ {{#produces}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }){{/hasProduces}}
|
||||
@com.wordnik.swagger.annotations.Api(value = "/{{baseName}}", description = "the {{baseName}} API")
|
||||
{{#operations}}
|
||||
public class {{classname}} {
|
||||
{{#operation}}
|
||||
@{{httpMethod}}
|
||||
{{#subresourceOperation}}@Path("{{path}}"){{/subresourceOperation}}
|
||||
{{#hasConsumes}}@Consumes({ {{#consumes}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }){{/hasConsumes}}
|
||||
{{#hasProduces}}@Produces({ {{#produces}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }){{/hasProduces}}
|
||||
@com.wordnik.swagger.annotations.ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}})
|
||||
@com.wordnik.swagger.annotations.ApiResponses(value = { {{#responses}}
|
||||
@com.wordnik.swagger.annotations.ApiResponse(code = {{{code}}}, message = "{{{message}}}"){{#hasMore}},
|
||||
{{/hasMore}}{{/responses}} })
|
||||
public class {{classname}} {
|
||||
|
||||
public Response {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},
|
||||
private final {{classname}}Service delegate = {{classname}}ServiceFactory.get{{classname}}();
|
||||
|
||||
{{#operation}}
|
||||
@{{httpMethod}}
|
||||
{{#subresourceOperation}}@Path("{{path}}"){{/subresourceOperation}}
|
||||
{{#hasConsumes}}@Consumes({ {{#consumes}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }){{/hasConsumes}}
|
||||
{{#hasProduces}}@Produces({ {{#produces}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }){{/hasProduces}}
|
||||
@com.wordnik.swagger.annotations.ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}})
|
||||
@com.wordnik.swagger.annotations.ApiResponses(value = { {{#responses}}
|
||||
@com.wordnik.swagger.annotations.ApiResponse(code = {{{code}}}, message = "{{{message}}}"){{#hasMore}},
|
||||
{{/hasMore}}{{/responses}} })
|
||||
|
||||
public Response {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},
|
||||
{{/hasMore}}{{/allParams}})
|
||||
throws NotFoundException {
|
||||
// do some magic!
|
||||
return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
|
||||
}
|
||||
|
||||
{{/operation}}
|
||||
throws NotFoundException {
|
||||
// do some magic!
|
||||
return delegate.{{nickname}}({{#allParams}}{{#isFile}}fileDetail{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}}{{#hasMore}},{{/hasMore}}{{/allParams}});
|
||||
}
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
package {{package}};
|
||||
|
||||
import {{package}}.*;
|
||||
import {{modelPackage}}.*;
|
||||
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
|
||||
{{#imports}}import {{import}};
|
||||
{{/imports}}
|
||||
|
||||
import java.util.List;
|
||||
import {{package}}.NotFoundException;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.sun.jersey.core.header.FormDataContentDisposition;
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
{{#operations}}
|
||||
public abstract class {{classname}}Service {
|
||||
{{#operation}}
|
||||
public abstract Response {{nickname}}({{#allParams}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{#hasMore}},{{/hasMore}}{{/allParams}})
|
||||
throws NotFoundException;
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
@ -0,0 +1,14 @@
|
||||
package {{package}}.factories;
|
||||
|
||||
import {{package}}.{{classname}}Service;
|
||||
import {{package}}.impl.{{classname}}ServiceImpl;
|
||||
|
||||
public class {{classname}}ServiceFactory {
|
||||
|
||||
private final static {{classname}}Service service = new {{classname}}ServiceImpl();
|
||||
|
||||
public static {{classname}}Service get{{classname}}()
|
||||
{
|
||||
return service;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package {{package}}.impl;
|
||||
|
||||
import {{package}}.*;
|
||||
import {{modelPackage}}.*;
|
||||
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
|
||||
{{#imports}}import {{import}};
|
||||
{{/imports}}
|
||||
|
||||
import java.util.List;
|
||||
import {{package}}.NotFoundException;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.sun.jersey.core.header.FormDataContentDisposition;
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
{{#operations}}
|
||||
public class {{classname}}ServiceImpl extends {{classname}}Service {
|
||||
{{#operation}}
|
||||
@Override
|
||||
public Response {{nickname}}({{#allParams}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{#hasMore}},{{/hasMore}}{{/allParams}})
|
||||
throws NotFoundException {
|
||||
// do some magic!
|
||||
return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
|
||||
}
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
@ -62,6 +62,25 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>1.9.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/gen/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
@ -129,7 +148,7 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
<properties>
|
||||
<swagger-core-version>1.5.2-M2-SNAPSHOT</swagger-core-version>
|
||||
<swagger-core-version>1.5.2-M2</swagger-core-version>
|
||||
<jetty-version>9.2.9.v20150224</jetty-version>
|
||||
<jersey-version>1.13</jersey-version>
|
||||
<slf4j-version>1.6.3</slf4j-version>
|
||||
|
@ -0,0 +1 @@
|
||||
{{#isBodyParam}}{{{dataType}}} {{paramName}}{{/isBodyParam}}
|
@ -0,0 +1 @@
|
||||
{{#isFormParam}}{{#notFile}}{{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}FormDataContentDisposition fileDetail{{/isFile}}{{/isFormParam}}
|
@ -0,0 +1 @@
|
||||
{{#isHeaderParam}}{{{dataType}}} {{paramName}}{{/isHeaderParam}}
|
@ -0,0 +1 @@
|
||||
{{#isPathParam}}{{{dataType}}} {{paramName}}{{/isPathParam}}
|
@ -0,0 +1 @@
|
||||
{{#isQueryParam}}{{{dataType}}} {{paramName}}{{/isQueryParam}}
|
@ -1,2 +1,2 @@
|
||||
{{#isFormParam}}{{#notFile}}
|
||||
@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@RequestPart("{{paramName}}") {{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}@ApiParam(value = "file detail") @RequestPart("file") MultipartFile fileDetail{{/isFile}}{{/isFormParam}}
|
||||
@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestPart(value="{{paramName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}@ApiParam(value = "file detail") @RequestPart("file") MultipartFile fileDetail{{/isFile}}{{/isFormParam}}
|
@ -1 +1 @@
|
||||
{{#isHeaderParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@RequestHeader("{{paramName}}") {{{dataType}}} {{paramName}}{{/isHeaderParam}}
|
||||
{{#isHeaderParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestHeader(value="{{paramName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{{dataType}}} {{paramName}}{{/isHeaderParam}}
|
||||
|
@ -1 +1 @@
|
||||
{{#isQueryParam}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}) @RequestParam(value = "{{paramName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{{dataType}}} {{paramName}}{{/isQueryParam}}
|
||||
{{#isQueryParam}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}) @RequestParam(value = "{{paramName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/isQueryParam}}
|
||||
|
@ -19,3 +19,4 @@ com.wordnik.swagger.codegen.languages.StaticHtmlGenerator
|
||||
com.wordnik.swagger.codegen.languages.SwaggerGenerator
|
||||
com.wordnik.swagger.codegen.languages.SwaggerYamlGenerator
|
||||
com.wordnik.swagger.codegen.languages.TizenClientCodegen
|
||||
com.wordnik.swagger.codegen.languages.AkkaScalaClientCodegen
|
||||
|
@ -0,0 +1,43 @@
|
||||
package {{package}}
|
||||
|
||||
{{#imports}}
|
||||
import {{import}}
|
||||
{{/imports}}
|
||||
import {{invokerPackage}}._
|
||||
import {{invokerPackage}}.CollectionFormats._
|
||||
import {{invokerPackage}}.ApiKeyLocations._
|
||||
|
||||
{{#operations}}
|
||||
object {{classname}} {
|
||||
|
||||
{{#operation}}
|
||||
{{#javadocRenderer}}
|
||||
{{>javadoc}}
|
||||
{{/javadocRenderer}}
|
||||
def {{operationId}}({{>methodParameters}}): ApiRequest[{{>operationReturnType}}] =
|
||||
ApiRequest[{{>operationReturnType}}](ApiMethods.{{httpMethod.toUpperCase}}, "{{basePath}}", "{{path}}", {{#consumes.0}}"{{mediaType}}"{{/consumes.0}}{{^consumes}}"application/json"{{/consumes}})
|
||||
{{#authMethods}}{{#isApiKey}}.withApiKey(apiKey, "{{keyParamName}}", {{#isKeyInQuery}}QUERY{{/isKeyInQuery}}{{#isKeyInHeader}}HEADER{{/isKeyInHeader}})
|
||||
{{/isApiKey}}{{#isBasic}}.withCredentials(basicAuth)
|
||||
{{/isBasic}}{{/authMethods}}{{#bodyParam}}.withBody({{paramName}})
|
||||
{{/bodyParam}}{{#formParams}}.withFormParam({{>paramCreation}})
|
||||
{{/formParams}}{{#queryParams}}.withQueryParam({{>paramCreation}})
|
||||
{{/queryParams}}{{#pathParams}}.withPathParam({{>paramCreation}})
|
||||
{{/pathParams}}{{#headerParams}}.withHeaderParam({{>paramCreation}})
|
||||
{{/headerParams}}{{#responses}}{{^isWildcard}}{{#dataType}}.with{{>responseState}}Response[{{dataType}}]({{code}})
|
||||
{{/dataType}}{{^dataType}}.with{{>responseState}}Response[Unit]({{code}})
|
||||
{{/dataType}}{{/isWildcard}}{{/responses}}{{#responses}}{{#isWildcard}}{{#dataType}}.withDefault{{>responseState}}Response[{{dataType}}]
|
||||
{{/dataType}}{{^dataType}}.withDefault{{>responseState}}Response[Unit]
|
||||
{{/dataType}}{{/isWildcard}}{{/responses}}{{^responseHeaders.isEmpty}}
|
||||
object {{#fnCapitalize}}{{operationId}}{{/fnCapitalize}}Headers { {{#responseHeaders}}
|
||||
def {{name}}(r: ApiReturnWithHeaders) = r.get{{^isContainer}}{{baseType}}{{/isContainer}}{{#isContainer}}String{{/isContainer}}Header("{{baseName}}"){{/responseHeaders}}
|
||||
}
|
||||
{{/responseHeaders.isEmpty}}
|
||||
{{/operation}}
|
||||
|
||||
{{#unknownStatusCodes}}
|
||||
ApiInvoker.addCustomStatusCode({{value}}, isSuccess = false)
|
||||
{{/unknownStatusCodes}}
|
||||
|
||||
}
|
||||
|
||||
{{/operations}}
|
@ -0,0 +1,323 @@
|
||||
package {{invokerPackage}}
|
||||
|
||||
import java.io.File
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.net.ssl._
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.io.IO
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.format.ISODateTimeFormat
|
||||
import org.json4s.JsonAST.JString
|
||||
import org.json4s._
|
||||
import org.json4s.jackson.JsonMethods._
|
||||
import org.json4s.jackson.Serialization
|
||||
import spray.can.Http
|
||||
import spray.can.Http.HostConnectorSetup
|
||||
import spray.client.pipelining
|
||||
import spray.client.pipelining._
|
||||
import spray.http.HttpEncodings._
|
||||
import spray.http.HttpHeaders.{RawHeader, `Accept-Encoding`}
|
||||
import spray.http.Uri.Query
|
||||
import spray.http._
|
||||
import spray.http.parser.HttpParser
|
||||
import spray.httpx.encoding.{Deflate, Encoder, Gzip}
|
||||
import spray.httpx.unmarshalling._
|
||||
import spray.io.ClientSSLEngineProvider
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.reflect.ClassTag
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
object ApiInvoker {
|
||||
|
||||
def apply()(implicit system: ActorSystem): ApiInvoker =
|
||||
apply(DefaultFormats + DateTimeSerializer)
|
||||
def apply(serializers: Traversable[Serializer[_]])(implicit system: ActorSystem): ApiInvoker =
|
||||
apply(DefaultFormats + DateTimeSerializer ++ serializers)
|
||||
def apply(formats: Formats)(implicit system: ActorSystem): ApiInvoker = new ApiInvoker(formats)
|
||||
|
||||
case class CustomStatusCode(value: Int, reason: String = "Application-defined status code", isSuccess: Boolean = true)
|
||||
|
||||
def addCustomStatusCode(code: CustomStatusCode): Unit = addCustomStatusCode(code.value, code.reason, code.isSuccess)
|
||||
|
||||
def addCustomStatusCode(code: Int, reason: String = "Application defined code", isSuccess: Boolean = true) = {
|
||||
StatusCodes.getForKey(code) foreach { c =>
|
||||
StatusCodes.registerCustom(code, reason, reason, isSuccess, allowsEntity = true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows request execution without calling apiInvoker.execute(request)
|
||||
* request.response can be used to get a future of the ApiResponse generated.
|
||||
* request.result can be used to get a future of the expected ApiResponse content. If content doesn't match, a
|
||||
* Future will failed with a ClassCastException
|
||||
* @param request the apiRequest to be executed
|
||||
*/
|
||||
implicit class ApiRequestImprovements[T](request: ApiRequest[T]) {
|
||||
|
||||
def response(invoker: ApiInvoker)(implicit ec: ExecutionContext, system: ActorSystem): Future[ApiResponse[T]] =
|
||||
response(ec, system, invoker)
|
||||
|
||||
def response(implicit ec: ExecutionContext, system: ActorSystem, invoker: ApiInvoker): Future[ApiResponse[T]] =
|
||||
invoker.execute(request)
|
||||
|
||||
def result[U <: T](implicit c: ClassTag[U], ec: ExecutionContext, system: ActorSystem, invoker: ApiInvoker): Future[U] =
|
||||
invoker.execute(request).map(_.content).mapTo[U]
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows transformation from ApiMethod to spray HttpMethods
|
||||
* @param method the ApiMethod to be converted
|
||||
*/
|
||||
implicit class ApiMethodExtensions(val method: ApiMethod) {
|
||||
def toSprayMethod: HttpMethod = HttpMethods.getForKey(method.value).getOrElse(HttpMethods.GET)
|
||||
}
|
||||
|
||||
case object DateTimeSerializer extends CustomSerializer[DateTime](format => ( {
|
||||
case JString(s) =>
|
||||
ISODateTimeFormat.dateTimeParser().parseDateTime(s)
|
||||
}, {
|
||||
case d: DateTime =>
|
||||
JString(ISODateTimeFormat.dateTimeParser().print(d))
|
||||
}))
|
||||
}
|
||||
|
||||
class ApiInvoker(formats: Formats)(implicit system: ActorSystem) extends UntrustedSslContext with CustomContentTypes {
|
||||
|
||||
import io.swagger.client.core.ApiInvoker._
|
||||
import io.swagger.client.core.ParametersMap._
|
||||
|
||||
implicit val ec = system.dispatcher
|
||||
implicit val jsonFormats = formats
|
||||
|
||||
def settings = ApiSettings(system)
|
||||
|
||||
import spray.http.MessagePredicate._
|
||||
|
||||
val CompressionFilter = MessagePredicate({ _ => settings.compressionEnabled}) &&
|
||||
Encoder.DefaultFilter &&
|
||||
minEntitySize(settings.compressionSizeThreshold)
|
||||
|
||||
settings.customCodes.foreach(addCustomStatusCode)
|
||||
|
||||
private def addAuthentication(credentialsSeq: Seq[Credentials]): pipelining.RequestTransformer =
|
||||
request =>
|
||||
credentialsSeq.foldLeft(request) {
|
||||
case (req, BasicCredentials(login, password)) =>
|
||||
req ~> addCredentials(BasicHttpCredentials(login, password))
|
||||
case (req, ApiKeyCredentials(keyValue, keyName, ApiKeyLocations.HEADER)) =>
|
||||
req ~> addHeader(RawHeader(keyName, keyValue.value))
|
||||
case (req, _) => req
|
||||
}
|
||||
|
||||
private def addHeaders(headers: Map[String, Any]): pipelining.RequestTransformer = { request =>
|
||||
|
||||
val rawHeaders = for {
|
||||
(name, value) <- headers.asFormattedParams
|
||||
header = RawHeader(name, String.valueOf(value))
|
||||
} yield header
|
||||
|
||||
request.withHeaders(rawHeaders.toList)
|
||||
}
|
||||
|
||||
private def bodyPart(name: String, value: Any): BodyPart = {
|
||||
value match {
|
||||
case f: File =>
|
||||
BodyPart(f, name)
|
||||
case v: String =>
|
||||
BodyPart(HttpEntity(String.valueOf(v)))
|
||||
case NumericValue(v) =>
|
||||
BodyPart(HttpEntity(String.valueOf(v)))
|
||||
case m: ApiModel =>
|
||||
BodyPart(HttpEntity(Serialization.write(m)))
|
||||
}
|
||||
}
|
||||
|
||||
private def formDataContent(request: ApiRequest[_]) = {
|
||||
val params = request.formParams.asFormattedParams
|
||||
if (params.isEmpty)
|
||||
None
|
||||
else
|
||||
Some(
|
||||
normalizedContentType(request.contentType).mediaType match {
|
||||
case MediaTypes.`multipart/form-data` =>
|
||||
MultipartFormData(params.map { case (name, value) => (name, bodyPart(name, value))})
|
||||
case MediaTypes.`application/x-www-form-urlencoded` =>
|
||||
FormData(params.mapValues(String.valueOf))
|
||||
case m: MediaType => // Default : application/x-www-form-urlencoded.
|
||||
FormData(params.mapValues(String.valueOf))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private def bodyContent(request: ApiRequest[_]): Option[Any] = {
|
||||
request.bodyParam.map(Extraction.decompose).map(compact)
|
||||
}
|
||||
|
||||
private def createRequest(uri: Uri, request: ApiRequest[_]): HttpRequest = {
|
||||
|
||||
val builder = new RequestBuilder(request.method.toSprayMethod)
|
||||
val httpRequest = request.method.toSprayMethod match {
|
||||
case HttpMethods.GET | HttpMethods.DELETE => builder.apply(uri)
|
||||
case HttpMethods.POST | HttpMethods.PUT =>
|
||||
formDataContent(request) orElse bodyContent(request) match {
|
||||
case Some(c: FormData) =>
|
||||
builder.apply(uri, c)
|
||||
case Some(c: MultipartFormData) =>
|
||||
builder.apply(uri, c)
|
||||
case Some(c: String) =>
|
||||
builder.apply(uri, HttpEntity(normalizedContentType(request.contentType), c))
|
||||
case _ =>
|
||||
builder.apply(uri, HttpEntity(normalizedContentType(request.contentType), " "))
|
||||
}
|
||||
case _ => builder.apply(uri)
|
||||
}
|
||||
|
||||
httpRequest ~>
|
||||
addHeaders(request.headerParams) ~>
|
||||
addAuthentication(request.credentials) ~>
|
||||
encode(Gzip(CompressionFilter))
|
||||
}
|
||||
|
||||
def makeQuery(r: ApiRequest[_]): Query = {
|
||||
r.credentials.foldLeft(r.queryParams) {
|
||||
case (params, ApiKeyCredentials(key, keyName, ApiKeyLocations.QUERY)) =>
|
||||
params + (keyName -> key.value)
|
||||
case (params, _) => params
|
||||
}.asFormattedParams
|
||||
.mapValues(String.valueOf)
|
||||
.foldRight[Query](Uri.Query.Empty) {
|
||||
case ((name, value), acc) => acc.+:(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
def makeUri(r: ApiRequest[_]): Uri = {
|
||||
val opPath = r.operationPath.replaceAll("\\{format\\}", "json")
|
||||
val opPathWithParams = r.pathParams.asFormattedParams
|
||||
.mapValues(String.valueOf)
|
||||
.foldLeft(opPath) {
|
||||
case (path, (name, value)) => path.replaceAll(s"\\{$name\\}", value)
|
||||
}
|
||||
val query = makeQuery(r)
|
||||
|
||||
Uri(r.basePath + opPathWithParams).withQuery(query)
|
||||
}
|
||||
|
||||
def execute[T](r: ApiRequest[T]): Future[ApiResponse[T]] = {
|
||||
try {
|
||||
implicit val timeout: Timeout = settings.connectionTimeout
|
||||
|
||||
val uri = makeUri(r)
|
||||
|
||||
val connector = HostConnectorSetup(
|
||||
uri.authority.host.toString,
|
||||
uri.effectivePort,
|
||||
sslEncryption = "https".equals(uri.scheme),
|
||||
defaultHeaders = settings.defaultHeaders ++ List(`Accept-Encoding`(gzip, deflate)))
|
||||
|
||||
val request = createRequest(uri, r)
|
||||
|
||||
for {
|
||||
Http.HostConnectorInfo(hostConnector, _) <- IO(Http) ? connector
|
||||
response <- hostConnector.ask(request).mapTo[HttpResponse]
|
||||
} yield {
|
||||
response ~> decode(Deflate) ~> decode(Gzip) ~> unmarshallApiResponse(r)
|
||||
}
|
||||
}
|
||||
catch {
|
||||
case NonFatal(x) => Future.failed(x)
|
||||
}
|
||||
}
|
||||
|
||||
def unmarshallApiResponse[T](request: ApiRequest[T])(response: HttpResponse): ApiResponse[T] = {
|
||||
request.responseForCode(response.status.intValue) match {
|
||||
case Some( (manifest: Manifest[T], state: ResponseState) ) =>
|
||||
entityUnmarshaller(manifest)(response.entity) match {
|
||||
case Right(value) ⇒
|
||||
state match {
|
||||
case ResponseState.Success =>
|
||||
ApiResponse(response.status.intValue, value, response.headers.map(header => (header.name, header.value)).toMap)
|
||||
case ResponseState.Error =>
|
||||
throw new ApiError(response.status.intValue, "Error response received",
|
||||
Some(value),
|
||||
headers = response.headers.map(header => (header.name, header.value)).toMap)
|
||||
}
|
||||
|
||||
case Left(MalformedContent(error, Some(cause))) ⇒
|
||||
throw new ApiError(response.status.intValue, s"Unable to unmarshall content to [$manifest]", Some(response.entity.toString), cause)
|
||||
|
||||
case Left(MalformedContent(error, None)) ⇒
|
||||
throw new ApiError(response.status.intValue, s"Unable to unmarshall content to [$manifest]", Some(response.entity.toString))
|
||||
|
||||
case Left(ContentExpected) ⇒
|
||||
throw new ApiError(response.status.intValue, s"Unable to unmarshall empty response to [$manifest]", Some(response.entity.toString))
|
||||
}
|
||||
|
||||
case _ => throw new ApiError(response.status.intValue, "Unexpected response code", Some(response.entity.toString))
|
||||
}
|
||||
}
|
||||
|
||||
def entityUnmarshaller[T](implicit mf: Manifest[T]): Unmarshaller[T] =
|
||||
Unmarshaller[T](MediaTypes.`application/json`) {
|
||||
case x: HttpEntity.NonEmpty ⇒
|
||||
parse(x.asString(defaultCharset = HttpCharsets.`UTF-8`))
|
||||
.noNulls
|
||||
.camelizeKeys
|
||||
.extract[T]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed trait CustomContentTypes {
|
||||
|
||||
def normalizedContentType(original: String): ContentType =
|
||||
MediaTypes.forExtension(original) map (ContentType(_)) getOrElse parseContentType(original)
|
||||
|
||||
def parseContentType(contentType: String): ContentType = {
|
||||
val contentTypeAsRawHeader = HttpHeaders.RawHeader("Content-Type", contentType)
|
||||
val parsedContentTypeHeader = HttpParser.parseHeader(contentTypeAsRawHeader)
|
||||
(parsedContentTypeHeader: @unchecked) match {
|
||||
case Right(ct: HttpHeaders.`Content-Type`) =>
|
||||
ct.contentType
|
||||
case Left(error: ErrorInfo) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Error converting '$contentType' to a ContentType header: '${error.summary}'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait UntrustedSslContext {
|
||||
this: ApiInvoker =>
|
||||
|
||||
implicit lazy val trustfulSslContext: SSLContext = {
|
||||
settings.alwaysTrustCertificates match {
|
||||
case false =>
|
||||
SSLContext.getDefault
|
||||
|
||||
case true =>
|
||||
class IgnoreX509TrustManager extends X509TrustManager {
|
||||
def checkClientTrusted(chain: Array[X509Certificate], authType: String): Unit = {}
|
||||
|
||||
def checkServerTrusted(chain: Array[X509Certificate], authType: String): Unit = {}
|
||||
|
||||
def getAcceptedIssuers = null
|
||||
}
|
||||
|
||||
val context = SSLContext.getInstance("TLS")
|
||||
context.init(null, Array(new IgnoreX509TrustManager), null)
|
||||
context
|
||||
}
|
||||
}
|
||||
|
||||
implicit val clientSSLEngineProvider =
|
||||
ClientSSLEngineProvider {
|
||||
_ =>
|
||||
val engine = trustfulSslContext.createSSLEngine()
|
||||
engine.setUseClientMode(true)
|
||||
engine
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package {{invokerPackage}}
|
||||
|
||||
sealed trait ResponseState
|
||||
object ResponseState {
|
||||
case object Success extends ResponseState
|
||||
case object Error extends ResponseState
|
||||
}
|
||||
|
||||
case class ApiRequest[U](
|
||||
// required fields
|
||||
method: ApiMethod,
|
||||
basePath: String,
|
||||
operationPath: String,
|
||||
contentType: String,
|
||||
|
||||
// optional fields
|
||||
responses: Map[Int, (Manifest[_], ResponseState)] = Map.empty,
|
||||
bodyParam: Option[Any] = None,
|
||||
formParams: Map[String, Any] = Map.empty,
|
||||
pathParams: Map[String, Any] = Map.empty,
|
||||
queryParams: Map[String, Any] = Map.empty,
|
||||
headerParams: Map[String, Any] = Map.empty,
|
||||
credentials: Seq[Credentials] = List.empty) {
|
||||
|
||||
def withCredentials(cred: Credentials) = copy[U](credentials = credentials :+ cred)
|
||||
|
||||
def withApiKey(key: ApiKeyValue, keyName: String, location: ApiKeyLocation) = withCredentials(ApiKeyCredentials(key, keyName, location))
|
||||
|
||||
def withSuccessResponse[T](code: Int)(implicit m: Manifest[T]) = copy[U](responses = responses + (code -> (m, ResponseState.Success)))
|
||||
|
||||
def withErrorResponse[T](code: Int)(implicit m: Manifest[T]) = copy[U](responses = responses + (code -> (m, ResponseState.Error)))
|
||||
|
||||
def withDefaultSuccessResponse[T](implicit m: Manifest[T]) = withSuccessResponse[T](0)
|
||||
|
||||
def withDefaultErrorResponse[T](implicit m: Manifest[T]) = withErrorResponse[T](0)
|
||||
|
||||
def responseForCode(statusCode: Int): Option[(Manifest[_], ResponseState)] = responses.get(statusCode) orElse responses.get(0)
|
||||
|
||||
def withoutBody() = copy[U](bodyParam = None)
|
||||
|
||||
def withBody(body: Any) = copy[U](bodyParam = Some(body))
|
||||
|
||||
def withFormParam(name: String, value: Any) = copy[U](formParams = formParams + (name -> value))
|
||||
|
||||
def withPathParam(name: String, value: Any) = copy[U](pathParams = pathParams + (name -> value))
|
||||
|
||||
def withQueryParam(name: String, value: Any) = copy[U](queryParams = queryParams + (name -> value))
|
||||
|
||||
def withHeaderParam(name: String, value: Any) = copy[U](headerParams = headerParams + (name -> value))
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package {{invokerPackage}}
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import akka.actor.{ExtendedActorSystem, Extension, ExtensionKey}
|
||||
import com.typesafe.config.Config
|
||||
import io.swagger.client.core.ApiInvoker.CustomStatusCode
|
||||
import spray.http.HttpHeaders.RawHeader
|
||||
|
||||
import scala.collection.JavaConversions._
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
class ApiSettings(config: Config) extends Extension {
|
||||
def this(system: ExtendedActorSystem) = this(system.settings.config)
|
||||
|
||||
private def cfg = config.getConfig("io.swagger.client.apiRequest")
|
||||
|
||||
val alwaysTrustCertificates = cfg.getBoolean("trust-certificates")
|
||||
val defaultHeaders = cfg.getConfig("default-headers").entrySet.toList.map(c => RawHeader(c.getKey, c.getValue.render))
|
||||
val connectionTimeout = FiniteDuration(cfg.getDuration("connection-timeout", TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS)
|
||||
val compressionEnabled = cfg.getBoolean("compression.enabled")
|
||||
val compressionSizeThreshold = cfg.getBytes("compression.size-threshold").toInt
|
||||
val customCodes = cfg.getConfigList("custom-codes").toList.map { c => CustomStatusCode(
|
||||
c.getInt("code"),
|
||||
c.getString("reason"),
|
||||
c.getBoolean("success"))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
object ApiSettings extends ExtensionKey[ApiSettings]
|
@ -0,0 +1,42 @@
|
||||
package {{apiPackage}}
|
||||
|
||||
import {{modelPackage}}._
|
||||
import org.json4s._
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
object EnumsSerializers {
|
||||
|
||||
def all = Seq[Serializer[_]](){{#models}}{{#model}}{{#hasEnums}}{{#vars}}{{#isEnum}} :+
|
||||
new EnumNameSerializer({{classname}}Enums.{{datatypeWithEnum}}){{/isEnum}}{{/vars}}{{/hasEnums}}{{/model}}{{/models}}
|
||||
|
||||
|
||||
|
||||
private class EnumNameSerializer[E <: Enumeration: ClassTag](enum: E)
|
||||
extends Serializer[E#Value] {
|
||||
import JsonDSL._
|
||||
|
||||
val EnumerationClass = classOf[E#Value]
|
||||
|
||||
def deserialize(implicit format: Formats):
|
||||
PartialFunction[(TypeInfo, JValue), E#Value] = {
|
||||
case (t @ TypeInfo(EnumerationClass, _), json) if isValid(json) => {
|
||||
json match {
|
||||
case JString(value) =>
|
||||
enum.withName(value)
|
||||
case value =>
|
||||
throw new MappingException(s"Can't convert $value to $EnumerationClass")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private[this] def isValid(json: JValue) = json match {
|
||||
case JString(value) if enum.values.exists(_.toString == value) => true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
|
||||
case i: E#Value => i.toString
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{{^notes.isEmpty}}
|
||||
{{notes}}
|
||||
{{/notes.isEmpty}}
|
||||
|
||||
Expected answers:
|
||||
{{#responses}}
|
||||
code {{code}} : {{dataType}} {{^message.isEmpty}}({{message}}){{/message.isEmpty}}{{^headers.isEmpty}}
|
||||
Headers :{{#headers}}
|
||||
{{baseName}} - {{description}}{{/headers}}{{/headers.isEmpty}}
|
||||
{{/responses}}
|
||||
{{#authMethods.0}}
|
||||
|
||||
Available security schemes:
|
||||
{{#authMethods}}
|
||||
{{name}} ({{type}})
|
||||
{{/authMethods}}
|
||||
{{/authMethods.0}}
|
||||
|
||||
{{#allParams}}
|
||||
@param {{paramName}} {{description}}
|
||||
{{/allParams}}
|
@ -0,0 +1 @@
|
||||
{{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}{{#isContainer}}{{dataType}}{{/isContainer}}{{^isContainer}}Option[{{dataType}}]{{/isContainer}}{{/required}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}{{^required}}{{^isContainer}} = None{{/isContainer}}{{/required}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}{{#authMethods.0}})(implicit {{#authMethods}}{{#isApiKey}}apiKey: ApiKeyValue{{/isApiKey}}{{#isBasic}}basicAuth: BasicCredentials{{/isBasic}}{{#hasMore}}, {{/hasMore}}{{/authMethods}}{{/authMethods.0}}
|
@ -0,0 +1,30 @@
|
||||
package {{package}}
|
||||
|
||||
import {{invokerPackage}}.ApiModel
|
||||
import org.joda.time.DateTime
|
||||
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
|
||||
case class {{classname}} (
|
||||
{{#vars}}{{#description}}/* {{{description}}} */
|
||||
{{/description}}{{name}}: {{^required}}Option[{{/required}}{{^isEnum}}{{datatype}}{{/isEnum}}{{#isEnum}}{{classname}}Enums.{{datatypeWithEnum}}{{/isEnum}}{{^required}}]{{/required}}{{#hasMore}},{{/hasMore}}{{^hasMore}}){{/hasMore}}
|
||||
{{/vars}} extends ApiModel
|
||||
|
||||
{{#hasEnums}}
|
||||
object {{classname}}Enums {
|
||||
|
||||
{{#vars}}{{#isEnum}}type {{datatypeWithEnum}} = {{datatypeWithEnum}}.Value
|
||||
{{/isEnum}}{{/vars}}
|
||||
{{#vars}}{{#isEnum}}object {{datatypeWithEnum}} extends Enumeration {
|
||||
{{#_enum}}
|
||||
val {{#fnEnumEntry}}{{.}}{{/fnEnumEntry}} = Value("{{.}}")
|
||||
{{/_enum}}
|
||||
}
|
||||
|
||||
{{/isEnum}}{{/vars}}
|
||||
}
|
||||
{{/hasEnums}}
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
|
@ -0,0 +1 @@
|
||||
{{#onlyOneSuccess}}{{^defaultResponse}}Unit{{/defaultResponse}}{{#defaultResponse}}{{#responses}}{{#isDefault}}{{#dataType}}{{dataType}}{{/dataType}}{{^dataType}}Unit{{/dataType}}{{/isDefault}}{{/responses}}{{/defaultResponse}}{{/onlyOneSuccess}}{{^onlyOneSuccess}}{{#responses}}{{#-first}}{{^hasMore}}{{#dataType}}{{dataType}}{{/dataType}}{{^dataType}}Unit{{/dataType}}{{/hasMore}}{{#hasMore}}Any{{/hasMore}}{{/-first}}{{/responses}}{{/onlyOneSuccess}}
|
@ -0,0 +1 @@
|
||||
"{{baseName}}", {{#isContainer}}ArrayValues({{paramName}}{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}){{/isContainer}}{{^isContainer}}{{paramName}}{{/isContainer}}
|
@ -0,0 +1,227 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>{{groupId}}</groupId>
|
||||
<artifactId>{{artifactId}}</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>{{artifactId}}</name>
|
||||
<version>{{artifactVersion}}</version>
|
||||
<prerequisites>
|
||||
<maven>2.2.0</maven>
|
||||
</prerequisites>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>maven-mongodb-plugin-repo</id>
|
||||
<name>maven mongodb plugin repository</name>
|
||||
<url>http://maven-mongodb-plugin.googlecode.com/svn/maven/repo</url>
|
||||
<layout>default</layout>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.12</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>loggerPath</name>
|
||||
<value>conf/log4j.properties</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<argLine>-Xms512m -Xmx1500m</argLine>
|
||||
<parallel>methods</parallel>
|
||||
<forkMode>pertest</forkMode>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- attach test jar -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add_sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>
|
||||
src/main/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add_test_sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>add-test-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>
|
||||
src/test/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>
|
||||
1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.alchim31.maven</groupId>
|
||||
<artifactId>scala-maven-plugin</artifactId>
|
||||
<version>${scala-maven-plugin-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>scala-compile-first</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>scala-test-compile</id>
|
||||
<phase>process-test-resources</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<args>
|
||||
<arg>-feature</arg>
|
||||
</args>
|
||||
<jvmArgs>
|
||||
<jvmArg>-Xms128m</jvmArg>
|
||||
<jvmArg>-Xmx1500m</jvmArg>
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
<configuration>
|
||||
<scalaVersion>${scala-version}</scalaVersion>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>${scala-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.wordnik</groupId>
|
||||
<artifactId>swagger-core</artifactId>
|
||||
<version>${swagger-core-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scalatest</groupId>
|
||||
<artifactId>scalatest_2.10</artifactId>
|
||||
<version>${scala-test-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${joda-time-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.joda</groupId>
|
||||
<artifactId>joda-convert</artifactId>
|
||||
<version>${joda-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe</groupId>
|
||||
<artifactId>config</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_2.10</artifactId>
|
||||
<version>${akka-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spray</groupId>
|
||||
<artifactId>spray-client</artifactId>
|
||||
<version>${spray-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json4s</groupId>
|
||||
<artifactId>json4s-jackson_2.10</artifactId>
|
||||
<version>${json4s-jackson-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<scala-version>2.10.4</scala-version>
|
||||
<json4s-jackson-version>3.2.11</json4s-jackson-version>
|
||||
<json4s-ext-version>3.2.11</json4s-ext-version>
|
||||
<spray-version>1.3.1</spray-version>
|
||||
<akka-version>2.3.9</akka-version>
|
||||
<joda-version>1.2</joda-version>
|
||||
<joda-time-version>2.2</joda-time-version>
|
||||
<swagger-core-version>1.5.0-M1</swagger-core-version>
|
||||
<maven-plugin.version>1.0.0</maven-plugin.version>
|
||||
|
||||
<junit-version>4.8.1</junit-version>
|
||||
<scala-maven-plugin-version>3.1.5</scala-maven-plugin-version>
|
||||
<scala-test-version>2.1.3</scala-test-version>
|
||||
</properties>
|
||||
</project>
|
@ -0,0 +1,24 @@
|
||||
{{configKeyPath}} {
|
||||
|
||||
{{configKey}} {
|
||||
|
||||
compression {
|
||||
enabled: false
|
||||
size-threshold: 0
|
||||
}
|
||||
|
||||
trust-certificates: true
|
||||
|
||||
connection-timeout: {{defaultTimeout}}ms
|
||||
|
||||
default-headers {
|
||||
"userAgent": "{{artifactId}}_{{artifactVersion}}"
|
||||
}
|
||||
|
||||
// let you define custom http status code, as in :
|
||||
// { code: 601, reason: "some custom http status code", success: false }
|
||||
custom-codes : []
|
||||
}
|
||||
}
|
||||
|
||||
spray.can.host-connector.max-redirects = 10
|
@ -0,0 +1,166 @@
|
||||
package {{invokerPackage}}
|
||||
|
||||
import java.io.File
|
||||
import java.net.URLEncoder
|
||||
import scala.util.Try
|
||||
|
||||
sealed trait ApiReturnWithHeaders {
|
||||
def headers: Map[String, String]
|
||||
def header(name: String): Option[String] = headers.get(name)
|
||||
def getStringHeader(name: String) = header(name)
|
||||
def getIntHeader(name: String) = castedHeader(name, java.lang.Integer.parseInt)
|
||||
def getLongHeader(name: String) = castedHeader(name, java.lang.Long.parseLong)
|
||||
def getFloatHeader(name: String) = castedHeader(name, java.lang.Float.parseFloat)
|
||||
def getDoubleHeader(name: String) = castedHeader(name, java.lang.Double.parseDouble)
|
||||
def getBooleanHeader(name: String) = castedHeader(name, java.lang.Boolean.parseBoolean)
|
||||
private def castedHeader[U](name: String, conversion: String => U): Option[U] = { Try { header(name).map( conversion ) }.get }
|
||||
}
|
||||
|
||||
sealed case class ApiResponse[T](code: Int, content: T, headers: Map[String, String] = Map.empty)
|
||||
extends ApiReturnWithHeaders
|
||||
|
||||
sealed case class ApiError[T](code: Int, message: String, responseContent: Option[T], cause: Throwable = null, headers: Map[String, String] = Map.empty)
|
||||
extends Throwable(s"($code) $message.${responseContent.map(s => s" Content : $s").getOrElse("")}", cause)
|
||||
with ApiReturnWithHeaders
|
||||
|
||||
sealed case class ApiMethod(value: String)
|
||||
|
||||
object ApiMethods {
|
||||
val CONNECT = ApiMethod("CONNECT")
|
||||
val DELETE = ApiMethod("DELETE")
|
||||
val GET = ApiMethod("GET")
|
||||
val HEAD = ApiMethod("HEAD")
|
||||
val OPTIONS = ApiMethod("OPTIONS")
|
||||
val PATCH = ApiMethod("PATCH")
|
||||
val POST = ApiMethod("POST")
|
||||
val PUT = ApiMethod("PUT")
|
||||
val TRACE = ApiMethod("TRACE")
|
||||
}
|
||||
|
||||
/**
|
||||
* This trait needs to be added to any model defined by the api.
|
||||
*/
|
||||
trait ApiModel
|
||||
|
||||
/**
|
||||
* Single trait defining a credential that can be transformed to a paramName / paramValue tupple
|
||||
*/
|
||||
sealed trait Credentials {
|
||||
def asQueryParam: Option[(String, String)] = None
|
||||
}
|
||||
|
||||
sealed case class BasicCredentials(user: String, password: String) extends Credentials
|
||||
|
||||
sealed case class ApiKeyCredentials(key: ApiKeyValue, keyName: String, location: ApiKeyLocation) extends Credentials {
|
||||
override def asQueryParam: Option[(String, String)] = location match {
|
||||
case ApiKeyLocations.QUERY => Some((keyName, key.value))
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
sealed case class ApiKeyValue(value: String)
|
||||
|
||||
sealed trait ApiKeyLocation
|
||||
|
||||
object ApiKeyLocations {
|
||||
|
||||
case object QUERY extends ApiKeyLocation
|
||||
|
||||
case object HEADER extends ApiKeyLocation
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Case class used to unapply numeric values only in pattern matching
|
||||
* @param value the string representation of the numeric value
|
||||
*/
|
||||
sealed case class NumericValue(value: String) {
|
||||
override def toString = value
|
||||
}
|
||||
|
||||
object NumericValue {
|
||||
def unapply(n: Any): Option[NumericValue] = n match {
|
||||
case (_: Int | _: Long | _: Float | _: Double | _: Boolean | _: Byte) => Some(NumericValue(String.valueOf(n)))
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for params being arrays
|
||||
*/
|
||||
sealed case class ArrayValues(values: Seq[Any], format: CollectionFormat = CollectionFormats.CSV)
|
||||
|
||||
object ArrayValues {
|
||||
def apply(values: Option[Seq[Any]], format: CollectionFormat): ArrayValues =
|
||||
ArrayValues(values.getOrElse(Seq.empty), format)
|
||||
|
||||
def apply(values: Option[Seq[Any]]): ArrayValues = ArrayValues(values, CollectionFormats.CSV)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines how arrays should be rendered in query strings.
|
||||
*/
|
||||
sealed trait CollectionFormat
|
||||
|
||||
trait MergedArrayFormat extends CollectionFormat {
|
||||
def separator: String
|
||||
}
|
||||
|
||||
object CollectionFormats {
|
||||
|
||||
case object CSV extends MergedArrayFormat {
|
||||
override val separator = ","
|
||||
}
|
||||
|
||||
case object TSV extends MergedArrayFormat {
|
||||
override val separator = "\t"
|
||||
}
|
||||
|
||||
case object SSV extends MergedArrayFormat {
|
||||
override val separator = " "
|
||||
}
|
||||
|
||||
case object PIPES extends MergedArrayFormat {
|
||||
override val separator = "|"
|
||||
}
|
||||
|
||||
case object MULTI extends CollectionFormat
|
||||
|
||||
}
|
||||
|
||||
object ParametersMap {
|
||||
|
||||
/**
|
||||
* Pimp parameters maps (Map[String, Any]) in order to transform them in a sequence of String -> Any tupples,
|
||||
* with valid url-encoding, arrays handling, files preservation, ...
|
||||
*/
|
||||
implicit class ParametersMapImprovements(val m: Map[String, Any]) {
|
||||
|
||||
def asFormattedParamsList = m.toList.flatMap(formattedParams)
|
||||
|
||||
def asFormattedParams = m.flatMap(formattedParams)
|
||||
|
||||
private def urlEncode(v: Any) = URLEncoder.encode(String.valueOf(v), "utf-8").replaceAll("\\+", "%20")
|
||||
|
||||
private def formattedParams(tuple: (String, Any)): Seq[(String, Any)] = formattedParams(tuple._1, tuple._2)
|
||||
|
||||
private def formattedParams(name: String, value: Any): Seq[(String, Any)] = value match {
|
||||
case arr: ArrayValues =>
|
||||
arr.format match {
|
||||
case CollectionFormats.MULTI => arr.values.flatMap(formattedParams(name, _))
|
||||
case format: MergedArrayFormat => Seq((name, arr.values.mkString(format.separator)))
|
||||
}
|
||||
case None => Seq.empty
|
||||
case Some(opt) =>
|
||||
formattedParams(name, opt)
|
||||
case s: Seq[Any] =>
|
||||
formattedParams(name, ArrayValues(s))
|
||||
case v: String => Seq((name, urlEncode(v)))
|
||||
case NumericValue(v) => Seq((name, urlEncode(v)))
|
||||
case f: File => Seq((name, f))
|
||||
case m: ApiModel => Seq((name, m))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{{#onlyOneSuccess}}{{#isDefault}}Success{{/isDefault}}{{^isDefault}}Error{{/isDefault}}{{/onlyOneSuccess}}{{^onlyOneSuccess}}Success{{/onlyOneSuccess}}
|
@ -1,9 +1,17 @@
|
||||
{{#useAndroidMavenGradlePlugin}}
|
||||
group = '{{groupId}}'
|
||||
project.version = '{{artifactVersion}}'
|
||||
{{/useAndroidMavenGradlePlugin}}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.2.2'
|
||||
{{#useAndroidMavenGradlePlugin}}
|
||||
classpath 'com.github.dcendents:android-maven-plugin:1.2'
|
||||
{{/useAndroidMavenGradlePlugin}}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +21,11 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
{{#useAndroidMavenGradlePlugin}}
|
||||
apply plugin: 'com.github.dcendents.android-maven'
|
||||
{{/useAndroidMavenGradlePlugin}}
|
||||
|
||||
android {
|
||||
compileSdkVersion 22
|
||||
@ -22,6 +34,17 @@ android {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 22
|
||||
}
|
||||
|
||||
// Rename the aar correctly
|
||||
libraryVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def outputFile = output.outputFile
|
||||
if (outputFile != null && outputFile.name.endsWith('.aar')) {
|
||||
def fileName = "${project.name}-${variant.baseName}-${version}.aar"
|
||||
output.outputFile = new File(outputFile.parent, fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +60,12 @@ dependencies {
|
||||
compile "com.google.code.gson:gson:$gson_version"
|
||||
compile "org.apache.httpcomponents:httpcore:$httpclient_version"
|
||||
compile "org.apache.httpcomponents:httpclient:$httpclient_version"
|
||||
compile "org.apache.httpcomponents:httpmime:$httpclient_version"
|
||||
compile ("org.apache.httpcomponents:httpcore:$httpcore_version") {
|
||||
exclude(group: 'org.apache.httpcomponents', module: 'httpclient')
|
||||
}
|
||||
compile ("org.apache.httpcomponents:httpmime:$httpmime_version") {
|
||||
exclude(group: 'org.apache.httpcomponents', module: 'httpclient')
|
||||
}
|
||||
testCompile "junit:junit:$junit_version"
|
||||
}
|
||||
|
||||
@ -48,7 +76,18 @@ afterEvaluate {
|
||||
task.dependsOn variant.javaCompile
|
||||
task.from variant.javaCompile.destinationDir
|
||||
task.destinationDir = project.file("${project.buildDir}/outputs/jar")
|
||||
task.archiveName = "${project.name}-${variant.baseName}.jar"
|
||||
task.archiveName = "${project.name}-${variant.baseName}-${version}.jar"
|
||||
artifacts.add('archives', task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{{#useAndroidMavenGradlePlugin}}
|
||||
task sourcesJar(type: Jar) {
|
||||
from android.sourceSets.main.java.srcDirs
|
||||
classifier = 'sources'
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
}
|
||||
{{/useAndroidMavenGradlePlugin}}
|
@ -0,0 +1 @@
|
||||
rootProject.name = "{{artifactId}}"
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using RestSharp;
|
||||
using {{invokerPackage}};
|
||||
using {{modelPackage}};
|
||||
{{#imports}}
|
||||
@ -9,101 +10,73 @@ namespace {{package}} {
|
||||
{{#operations}}
|
||||
public class {{classname}} {
|
||||
string basePath;
|
||||
private readonly ApiInvoker apiInvoker = ApiInvoker.GetInstance();
|
||||
protected RestClient restClient;
|
||||
|
||||
public {{classname}}(String basePath = "{{basePath}}")
|
||||
{
|
||||
this.basePath = basePath;
|
||||
this.restClient = new RestClient(basePath);
|
||||
}
|
||||
|
||||
public ApiInvoker getInvoker() {
|
||||
return apiInvoker;
|
||||
}
|
||||
|
||||
// Sets the endpoint base url for the services being accessed
|
||||
public void setBasePath(string basePath) {
|
||||
/// <summary>
|
||||
/// Sets the endpoint base url for the services being accessed
|
||||
/// </summary>
|
||||
/// <param name="basePath"> Base URL
|
||||
/// <returns></returns>
|
||||
public void SetBasePath(string basePath) {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
// Gets the endpoint base url for the services being accessed
|
||||
public String getBasePath() {
|
||||
return basePath;
|
||||
/// <summary>
|
||||
/// Gets the endpoint base url for the services being accessed
|
||||
/// <returns>Base URL</returns>
|
||||
/// </summary>
|
||||
public String GetBasePath() {
|
||||
return this.basePath;
|
||||
}
|
||||
|
||||
{{#operation}}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// {{summary}} {{notes}}
|
||||
/// </summary>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}</param>
|
||||
{{#hasMore}} {{/hasMore}}{{/allParams}}
|
||||
/// <returns></returns>
|
||||
public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}} {{nickname}} ({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) {
|
||||
// create path and map variables
|
||||
var path = "{{path}}".Replace("{format}","json"){{#pathParams}}.Replace("{" + "{{baseName}}" + "}", apiInvoker.ParameterToString({{{paramName}}})){{/pathParams}};
|
||||
{{#allParams}} /// <param name="{{paramName}}">{{description}}</param>
|
||||
{{/allParams}}
|
||||
/// <returns>{{#returnType}}{{{returnType}}}{{/returnType}}</returns>
|
||||
public {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{nickname}} ({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) {
|
||||
|
||||
// query params
|
||||
var queryParams = new Dictionary<String, String>();
|
||||
var headerParams = new Dictionary<String, String>();
|
||||
var formParams = new Dictionary<String, object>();
|
||||
var _request = new RestRequest("{{path}}", Method.{{httpMethod}});
|
||||
|
||||
{{#requiredParamCount}}
|
||||
// verify required params are set
|
||||
if ({{/requiredParamCount}}{{#requiredParams}} {{paramName}} == null {{#hasMore}}|| {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) {
|
||||
throw new ApiException(400, "missing required params");
|
||||
{{#allParams}}{{#required}}
|
||||
// verify the required parameter '{{paramName}}' is set
|
||||
if ({{paramName}} == null) throw new ApiException(400, "Missing required parameter '{{paramName}}' when calling {{nickname}}");
|
||||
{{/required}}{{/allParams}}
|
||||
|
||||
// add default header, if any
|
||||
foreach(KeyValuePair<string, string> defaultHeader in ApiInvoker.GetDefaultHeader())
|
||||
{
|
||||
_request.AddHeader(defaultHeader.Key, defaultHeader.Value);
|
||||
}
|
||||
{{/requiredParamCount}}
|
||||
|
||||
{{#queryParams}}if ({{paramName}} != null){
|
||||
queryParams.Add("{{baseName}}", apiInvoker.ParameterToString({{paramName}}));
|
||||
}
|
||||
_request.AddUrlSegment("format", "json"); // set format to json by default
|
||||
{{#pathParams}}_request.AddUrlSegment("{{baseName}}", ApiInvoker.ParameterToString({{{paramName}}})); // path (url segment) parameter
|
||||
{{/pathParams}}
|
||||
{{#queryParams}} if ({{paramName}} != null) _request.AddParameter("{{baseName}}", ApiInvoker.ParameterToString({{paramName}})); // query parameter
|
||||
{{/queryParams}}
|
||||
|
||||
{{#headerParams}}headerParams.Add("{{baseName}}", apiInvoker.ParameterToString({{paramName}}));
|
||||
{{#headerParams}} if ({{paramName}} != null) _request.AddHeader("{{baseName}}", ApiInvoker.ParameterToString({{paramName}})); // header parameter
|
||||
{{/headerParams}}
|
||||
|
||||
{{#formParams}}if ({{paramName}} != null){
|
||||
if({{paramName}} is byte[]) {
|
||||
formParams.Add("{{baseName}}", {{paramName}});
|
||||
} else {
|
||||
formParams.Add("{{baseName}}", apiInvoker.ParameterToString({{paramName}}));
|
||||
}
|
||||
}
|
||||
{{#formParams}}if ({{paramName}} != null) {{#isFile}}_request.AddFile("{{baseName}}", {{paramName}});{{/isFile}}{{^isFile}}_request.AddParameter("{{baseName}}", ApiInvoker.ParameterToString({{paramName}})); // form parameter{{/isFile}}
|
||||
{{/formParams}}
|
||||
{{#bodyParam}}_request.AddParameter("application/json", ApiInvoker.Serialize({{paramName}}), ParameterType.RequestBody); // http body (model) parameter
|
||||
{{/bodyParam}}
|
||||
|
||||
try {
|
||||
if (typeof({{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}) == typeof(byte[])) {
|
||||
{{#returnType}}
|
||||
var response = apiInvoker.invokeBinaryAPI(basePath, path, "GET", queryParams, null, headerParams, formParams);
|
||||
return ((object)response) as {{{returnType}}};
|
||||
{{/returnType}}
|
||||
{{^returnType}}
|
||||
apiInvoker.invokeBinaryAPI(basePath, path, "GET", queryParams, null, headerParams, formParams);
|
||||
return;
|
||||
{{/returnType}}
|
||||
} else {
|
||||
{{#returnType}}
|
||||
var response = apiInvoker.invokeAPI(basePath, path, "{{httpMethod}}", queryParams, {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}, headerParams, formParams);
|
||||
if (response != null){
|
||||
return ({{{returnType}}}) ApiInvoker.deserialize(response, typeof({{{returnType}}}));
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
{{/returnType}}
|
||||
{{^returnType}}
|
||||
apiInvoker.invokeAPI(basePath, path, "{{httpMethod}}", queryParams, {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}, headerParams, formParams);
|
||||
return;
|
||||
{{/returnType}}
|
||||
}
|
||||
} catch (ApiException ex) {
|
||||
if(ex.ErrorCode == 404) {
|
||||
return {{#returnType}}null{{/returnType}};
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
// make the HTTP request
|
||||
IRestResponse response = restClient.Execute(_request);
|
||||
if (((int)response.StatusCode) >= 400) {
|
||||
throw new ApiException ((int)response.StatusCode, "Error calling {{nickname}}: " + response.Content);
|
||||
}
|
||||
{{#returnType}}return ({{{returnType}}}) ApiInvoker.Deserialize(response.Content, typeof({{{returnType}}}));{{/returnType}}{{^returnType}}
|
||||
return;{{/returnType}}
|
||||
}
|
||||
{{/operation}}
|
||||
}
|
||||
|
@ -1,21 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace {{invokerPackage}} {
|
||||
|
||||
public class ApiException : Exception {
|
||||
|
||||
private int errorCode = 0;
|
||||
|
||||
public int ErrorCode { get; set; }
|
||||
|
||||
public ApiException() {}
|
||||
|
||||
public int ErrorCode {
|
||||
get
|
||||
{
|
||||
return errorCode;
|
||||
}
|
||||
public ApiException(int errorCode, string message) : base(message) {
|
||||
this.ErrorCode = errorCode;
|
||||
}
|
||||
|
||||
public ApiException(int errorCode, string message) : base(message) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,235 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace {{invokerPackage}} {
|
||||
public class ApiInvoker {
|
||||
private static readonly ApiInvoker _instance = new ApiInvoker();
|
||||
private Dictionary<String, String> defaultHeaderMap = new Dictionary<String, String>();
|
||||
namespace {{invokerPackage}} {
|
||||
public class ApiInvoker {
|
||||
private static Dictionary<String, String> defaultHeaderMap = new Dictionary<String, String>();
|
||||
|
||||
public static ApiInvoker GetInstance() {
|
||||
return _instance;
|
||||
}
|
||||
/// <summary>
|
||||
/// Add default header
|
||||
/// </summary>
|
||||
/// <param name="key"> Header field name
|
||||
/// <param name="value"> Header field value
|
||||
/// <returns></returns>
|
||||
public static void AddDefaultHeader(string key, string value) {
|
||||
defaultHeaderMap.Add(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add default header
|
||||
/// </summary>
|
||||
/// <param name="key"> Header field name
|
||||
/// <param name="value"> Header field value
|
||||
/// <returns></returns>
|
||||
public void addDefaultHeader(string key, string value) {
|
||||
defaultHeaderMap.Add(key, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Get default header
|
||||
/// </summary>
|
||||
/// <returns>Dictionary of default header</returns>
|
||||
public static Dictionary<String, String> GetDefaultHeader() {
|
||||
return defaultHeaderMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// escape string (url-encoded)
|
||||
/// </summary>
|
||||
/// <param name="str"> String to be escaped
|
||||
/// <returns>Escaped string</returns>
|
||||
public string escapeString(string str) {
|
||||
return str;
|
||||
}
|
||||
/// <summary>
|
||||
/// escape string (url-encoded)
|
||||
/// </summary>
|
||||
/// <param name="str"> String to be escaped
|
||||
/// <returns>Escaped string</returns>
|
||||
public static string EscapeString(string str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// if parameter is DateTime, output in ISO8601 format, otherwise just return the string
|
||||
/// </summary>
|
||||
/// <param name="obj"> The parameter (header, path, query, form)
|
||||
/// <returns>Formatted string</returns>
|
||||
public string ParameterToString(object obj)
|
||||
/// <summary>
|
||||
/// if parameter is DateTime, output in ISO8601 format, otherwise just return the string
|
||||
/// </summary>
|
||||
/// <param name="obj"> The parameter (header, path, query, form)
|
||||
/// <returns>Formatted string</returns>
|
||||
public static string ParameterToString(object obj)
|
||||
{
|
||||
return (obj is DateTime) ? ((DateTime)obj).ToString ("u") : Convert.ToString (obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the JSON string into a proper object
|
||||
/// </summary>
|
||||
/// <param name="json"> JSON string
|
||||
/// <param name="type"> Object type
|
||||
/// <returns>Object representation of the JSON string</returns>
|
||||
public static object Deserialize(string json, Type type) {
|
||||
try
|
||||
{
|
||||
return (obj is DateTime) ? ((DateTime)obj).ToString ("u") : Convert.ToString (obj);
|
||||
return JsonConvert.DeserializeObject(json, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the JSON string into a proper object
|
||||
/// </summary>
|
||||
/// <param name="json"> JSON string
|
||||
/// <param name="type"> Object type
|
||||
/// <returns>Object representation of the JSON string</returns>
|
||||
public static object deserialize(string json, Type type) {
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject(json, type);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new ApiException(500, e.Message);
|
||||
}
|
||||
|
||||
catch (IOException e) {
|
||||
throw new ApiException(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static string serialize(object obj) {
|
||||
try
|
||||
{
|
||||
return obj != null ? JsonConvert.SerializeObject(obj) : null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ApiException(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public string invokeAPI(string host, string path, string method, Dictionary<String, String> queryParams, object body, Dictionary<String, String> headerParams, Dictionary<String, object> formParams)
|
||||
/// <summary>
|
||||
/// Serialize an object into JSON string
|
||||
/// </summary>
|
||||
/// <param name="obj"> Object
|
||||
/// <returns>JSON string</returns>
|
||||
public static string Serialize(object obj) {
|
||||
try
|
||||
{
|
||||
return invokeAPIInternal(host, path, method, false, queryParams, body, headerParams, formParams) as string;
|
||||
return obj != null ? JsonConvert.SerializeObject(obj) : null;
|
||||
}
|
||||
|
||||
public byte[] invokeBinaryAPI(string host, string path, string method, Dictionary<String, String> queryParams, object body, Dictionary<String, String> headerParams, Dictionary<String, object> formParams)
|
||||
{
|
||||
return invokeAPIInternal(host, path, method, true, queryParams, body, headerParams, formParams) as byte[];
|
||||
}
|
||||
|
||||
private object invokeAPIInternal(string host, string path, string method, bool binaryResponse, Dictionary<String, String> queryParams, object body, Dictionary<String, String> headerParams, Dictionary<String, object> formParams) {
|
||||
var b = new StringBuilder();
|
||||
|
||||
foreach (var queryParamItem in queryParams)
|
||||
{
|
||||
var value = queryParamItem.Value;
|
||||
if (value == null) continue;
|
||||
b.Append(b.ToString().Length == 0 ? "?" : "&");
|
||||
b.Append(escapeString(queryParamItem.Key)).Append("=").Append(escapeString(value));
|
||||
}
|
||||
|
||||
var querystring = b.ToString();
|
||||
|
||||
host = host.EndsWith("/") ? host.Substring(0, host.Length - 1) : host;
|
||||
|
||||
var client = WebRequest.Create(host + path + querystring);
|
||||
client.Method = method;
|
||||
|
||||
byte[] formData = null;
|
||||
if (formParams.Count > 0)
|
||||
{
|
||||
string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
|
||||
client.ContentType = "multipart/form-data; boundary=" + formDataBoundary;
|
||||
formData = GetMultipartFormData(formParams, formDataBoundary);
|
||||
client.ContentLength = formData.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
client.ContentType = "application/json";
|
||||
}
|
||||
|
||||
foreach (var headerParamsItem in headerParams)
|
||||
{
|
||||
client.Headers.Add(headerParamsItem.Key, headerParamsItem.Value);
|
||||
}
|
||||
foreach (var defaultHeaderMapItem in defaultHeaderMap.Where(defaultHeaderMapItem => !headerParams.ContainsKey(defaultHeaderMapItem.Key)))
|
||||
{
|
||||
client.Headers.Add(defaultHeaderMapItem.Key, defaultHeaderMapItem.Value);
|
||||
}
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case "GET":
|
||||
break;
|
||||
case "POST":
|
||||
case "PATCH":
|
||||
case "PUT":
|
||||
case "DELETE":
|
||||
using (Stream requestStream = client.GetRequestStream())
|
||||
{
|
||||
if (formData != null)
|
||||
{
|
||||
requestStream.Write(formData, 0, formData.Length);
|
||||
}
|
||||
|
||||
var swRequestWriter = new StreamWriter(requestStream);
|
||||
swRequestWriter.Write(serialize(body));
|
||||
swRequestWriter.Close();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ApiException(500, "unknown method type " + method);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var webResponse = (HttpWebResponse)client.GetResponse();
|
||||
if (webResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
webResponse.Close();
|
||||
throw new ApiException((int)webResponse.StatusCode, webResponse.StatusDescription);
|
||||
}
|
||||
|
||||
if (binaryResponse)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
webResponse.GetResponseStream().CopyTo(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var responseReader = new StreamReader(webResponse.GetResponseStream()))
|
||||
{
|
||||
var responseData = responseReader.ReadToEnd();
|
||||
return responseData;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(WebException ex)
|
||||
{
|
||||
var response = ex.Response as HttpWebResponse;
|
||||
int statusCode = 0;
|
||||
if (response != null)
|
||||
{
|
||||
statusCode = (int)response.StatusCode;
|
||||
response.Close();
|
||||
}
|
||||
throw new ApiException(statusCode, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
|
||||
{
|
||||
Stream formDataStream = new System.IO.MemoryStream();
|
||||
bool needsCLRF = false;
|
||||
|
||||
foreach (var param in postParameters)
|
||||
{
|
||||
// Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
|
||||
// Skip it on the first parameter, add it to subsequent parameters.
|
||||
if (needsCLRF)
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n"));
|
||||
|
||||
needsCLRF = true;
|
||||
|
||||
if (param.Value is byte[])
|
||||
{
|
||||
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n",
|
||||
boundary,
|
||||
param.Key,
|
||||
"application/octet-stream");
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData));
|
||||
|
||||
// Write the file data directly to the Stream, rather than serializing it to a string.
|
||||
formDataStream.Write((param.Value as byte[]), 0, (param.Value as byte[]).Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
|
||||
boundary,
|
||||
param.Key,
|
||||
param.Value);
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData));
|
||||
}
|
||||
}
|
||||
|
||||
// Add the end of the request. Start with a newline
|
||||
string footer = "\r\n--" + boundary + "--\r\n";
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer));
|
||||
|
||||
// Dump the Stream into a byte[]
|
||||
formDataStream.Position = 0;
|
||||
byte[] formData = new byte[formDataStream.Length];
|
||||
formDataStream.Read(formData, 0, formData.Length);
|
||||
formDataStream.Close();
|
||||
|
||||
return formData;
|
||||
catch (Exception e) {
|
||||
throw new ApiException(500, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,19 @@ using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
namespace {{package}} {
|
||||
[DataContract]
|
||||
public class {{classname}} {
|
||||
{{#vars}}
|
||||
|
||||
{{#description}}/* {{{description}}} */
|
||||
{{/description}}
|
||||
{{#description}}/* {{{description}}} */{{/description}}
|
||||
[DataMember(Name="{{baseName}}", EmitDefaultValue=false)]
|
||||
public {{{datatype}}} {{name}} { get; set; }
|
||||
|
||||
{{/vars}}
|
||||
|
||||
public override string ToString() {
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("class {{classname}} {\n");
|
||||
@ -27,4 +27,4 @@ namespace {{package}} {
|
||||
}
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
{{#examples}}
|
||||
<h3 class="field-label">Example data</h3>
|
||||
<div class="example-data-content-type">Content-Type: {{{contentType}}}</div>
|
||||
<pre class="example"><code>{{{example}}}</code></pre>
|
||||
<pre class="example"><code>{{example}}</code></pre>
|
||||
{{/examples}}
|
||||
</div> <!-- method -->
|
||||
<hr>
|
||||
|
@ -0,0 +1,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <ISO8601/ISO8601.h>
|
||||
#import <JSONModel/JSONValueTransformer.h>
|
||||
|
||||
@interface JSONValueTransformer (ISO8601)
|
||||
@end
|
@ -0,0 +1,10 @@
|
||||
#import "JSONValueTransformer+ISO8601.h"
|
||||
|
||||
@implementation JSONValueTransformer (ISO8601)
|
||||
|
||||
- (NSDate *) NSDateFromNSString:(NSString *)string
|
||||
{
|
||||
return [NSDate dateWithISO8601String:string];
|
||||
}
|
||||
|
||||
@end
|
@ -2,3 +2,4 @@ platform :ios, '6.0'
|
||||
xcodeproj '{{projectName}}/{{projectName}}.xcodeproj'
|
||||
pod 'AFNetworking', '~> 2.1'
|
||||
pod 'JSONModel', '~> 1.0'
|
||||
pod 'ISO8601'
|
||||
|
@ -1,12 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SWGObject.h"
|
||||
|
||||
@interface SWGDate : SWGObject {
|
||||
@private
|
||||
NSDate *_date;
|
||||
}
|
||||
@property(nonatomic, readonly) NSDate* date;
|
||||
|
||||
- (id) initWithValues: (NSString*)input;
|
||||
-(NSString*) toString;
|
||||
@end
|
@ -1,34 +0,0 @@
|
||||
#import "SWGDate.h"
|
||||
|
||||
@implementation SWGDate
|
||||
|
||||
@synthesize date = _date;
|
||||
|
||||
- (id) initWithValues:(NSString*)input {
|
||||
if([input isKindOfClass:[NSString class]]){
|
||||
NSDateFormatter* df = [NSDateFormatter new];
|
||||
NSLocale *locale = [[NSLocale new]
|
||||
initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
[df setLocale:locale];
|
||||
[df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
||||
|
||||
_date = [df dateFromString:input];
|
||||
}
|
||||
else if([input isKindOfClass:[NSNumber class]]) {
|
||||
NSTimeInterval interval = [input doubleValue];
|
||||
_date = [[NSDate alloc] initWithTimeIntervalSince1970:interval];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(NSString*) toString {
|
||||
NSDateFormatter* df = [NSDateFormatter new];
|
||||
NSLocale *locale = [[NSLocale new]
|
||||
initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
[df setLocale:locale];
|
||||
[df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
||||
|
||||
return [df stringFromDate:_date];
|
||||
}
|
||||
|
||||
@end
|
@ -69,6 +69,11 @@ static NSString * basePath = @"{{basePath}}";
|
||||
{{#returnBaseType}}{{#hasParams}}completionHandler: {{/hasParams}}(void (^)({{{returnType}}} output, NSError* error))completionBlock{{/returnBaseType}}
|
||||
{{^returnBaseType}}{{#hasParams}}completionHandler: {{/hasParams}}(void (^)(NSError* error))completionBlock{{/returnBaseType}} {
|
||||
|
||||
{{#allParams}}{{#required}}
|
||||
// verify the required parameter '{{paramName}}' is set
|
||||
NSAssert({{paramName}} != nil, @"Missing the required parameter `{{paramName}}` when calling {{nickname}}");
|
||||
{{/required}}{{/allParams}}
|
||||
|
||||
NSMutableString* requestUrl = [NSMutableString stringWithFormat:@"%@{{path}}", basePath];
|
||||
|
||||
// remove format in URL if needed
|
||||
|
@ -24,6 +24,8 @@ class APIClient {
|
||||
public static $GET = "GET";
|
||||
public static $PUT = "PUT";
|
||||
public static $DELETE = "DELETE";
|
||||
|
||||
private static $default_header = array();
|
||||
|
||||
/*
|
||||
* @var string timeout (second) of the HTTP request, by default set to 0, no timeout
|
||||
@ -36,37 +38,110 @@ class APIClient {
|
||||
protected $user_agent = "PHP-Swagger";
|
||||
|
||||
/**
|
||||
* @param string $host the address of the API server
|
||||
* @param string $headerName a header to pass on requests
|
||||
* @param string $host Base url of the API server (optional)
|
||||
*/
|
||||
function __construct($host, $headerName = null, $headerValue = null) {
|
||||
$this->host = $host;
|
||||
$this->headerName = $headerName;
|
||||
$this->headerValue = $headerValue;
|
||||
function __construct($host = null) {
|
||||
if ($host == null) {
|
||||
$this->host = '{{basePath}}';
|
||||
} else {
|
||||
$this->host = $host;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user agent of the API client
|
||||
* add default header
|
||||
*
|
||||
* @param string $user_agent The user agent of the API client
|
||||
* @param string $header_name header name (e.g. Token)
|
||||
* @param string $header_value header value (e.g. 1z8wp3)
|
||||
*/
|
||||
public function addDefaultHeader($header_name, $header_value) {
|
||||
if (!is_string($header_name))
|
||||
throw new \InvalidArgumentException('Header name must be a string.');
|
||||
|
||||
self::$default_header[$header_name] = $header_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the default header
|
||||
*
|
||||
* @return array default header
|
||||
*/
|
||||
public function getDefaultHeader() {
|
||||
return self::$default_header;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete the default header based on header name
|
||||
*
|
||||
* @param string $header_name header name (e.g. Token)
|
||||
*/
|
||||
public function deleteDefaultHeader($header_name) {
|
||||
unset(self::$default_header[$header_name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the user agent of the api client
|
||||
*
|
||||
* @param string $user_agent the user agent of the api client
|
||||
*/
|
||||
public function setUserAgent($user_agent) {
|
||||
if (!is_string($user_agent)) {
|
||||
throw new Exception('User-agent must be a string.');
|
||||
}
|
||||
if (!is_string($user_agent))
|
||||
throw new \InvalidArgumentException('User-agent must be a string.');
|
||||
|
||||
$this->user_agent= $user_agent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $seconds Number of seconds before timing out [set to 0 for no timeout]
|
||||
*/
|
||||
*/
|
||||
public function setTimeout($seconds) {
|
||||
if (!is_numeric($seconds)) {
|
||||
throw new Exception('Timeout variable must be numeric.');
|
||||
}
|
||||
if (!is_numeric($seconds))
|
||||
throw new \InvalidArgumentException('Timeout variable must be numeric.');
|
||||
|
||||
$this->curl_timeout = $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API key (with prefix if set)
|
||||
* @param string key name
|
||||
* @return string API key with the prefix
|
||||
*/
|
||||
public function getApiKeyWithPrefix($apiKey) {
|
||||
if (Configuration::$apiKeyPrefix[$apiKey]) {
|
||||
return Configuration::$apiKeyPrefix[$apiKey]." ".Configuration::$apiKey[$apiKey];
|
||||
} else {
|
||||
return Configuration::$apiKey[$apiKey];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update hearder and query param based on authentication setting
|
||||
*
|
||||
* @param array $headerParams header parameters (by ref)
|
||||
* @param array $queryParams query parameters (by ref)
|
||||
* @param array $authSettings array of authentication scheme (e.g ['api_key'])
|
||||
*/
|
||||
public function updateParamsForAuth(&$headerParams, &$queryParams, $authSettings)
|
||||
{
|
||||
if (count($authSettings) == 0)
|
||||
return;
|
||||
|
||||
// one endpoint can have more than 1 auth settings
|
||||
foreach($authSettings as $auth) {
|
||||
// determine which one to use
|
||||
switch($auth) {
|
||||
{{#authMethods}}
|
||||
case '{{name}}':
|
||||
{{#isApiKey}}{{#isKeyInHeader}}$headerParams['{{keyParamName}}'] = $this->getApiKeyWithPrefix('{{keyParamName}}');{{/isKeyInHeader}}{{#isKeyInQuery}}$queryParams['{{keyParamName}}'] = $this->getApiKeyWithPrefix('{{keyParamName}}');{{/isKeyInQuery}}{{/isApiKey}}{{#isBasic}}$headerParams['Authorization'] = 'Basic '.base64_encode(Configuration::$username.":".Configuration::$password);{{/isBasic}}
|
||||
{{#isOAuth}}//TODO support oauth{{/isOAuth}}
|
||||
break;
|
||||
{{/authMethods}}
|
||||
default:
|
||||
//TODO show warning about security definition not found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $resourcePath path to method endpoint
|
||||
* @param string $method method to call
|
||||
@ -76,23 +151,22 @@ class APIClient {
|
||||
* @return mixed
|
||||
*/
|
||||
public function callAPI($resourcePath, $method, $queryParams, $postData,
|
||||
$headerParams) {
|
||||
$headerParams, $authSettings) {
|
||||
|
||||
$headers = array();
|
||||
|
||||
# Allow API key from $headerParams to override default
|
||||
$added_api_key = False;
|
||||
# determine authentication setting
|
||||
$this->updateParamsForAuth($headerParams, $queryParams, $authSettings);
|
||||
|
||||
# construct the http header
|
||||
if ($headerParams != null) {
|
||||
# add default header
|
||||
$headerParams = array_merge((array)self::$default_header, $headerParams);
|
||||
|
||||
foreach ($headerParams as $key => $val) {
|
||||
$headers[] = "$key: $val";
|
||||
if ($key == $this->headerName) {
|
||||
$added_api_key = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! $added_api_key && $this->headerName != null) {
|
||||
$headers[] = $this->headerName . ": " . $this->headerValue;
|
||||
}
|
||||
|
||||
// form data
|
||||
if ($postData and in_array('Content-Type: application/x-www-form-urlencoded', $headers)) {
|
||||
@ -111,6 +185,7 @@ class APIClient {
|
||||
}
|
||||
// return the result on success, rather than just TRUE
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
if (! empty($queryParams)) {
|
||||
@ -130,7 +205,7 @@ class APIClient {
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
|
||||
} else if ($method != self::$GET) {
|
||||
throw new Exception('Method ' . $method . ' is not recognized.');
|
||||
throw new APIClientException('Method ' . $method . ' is not recognized.');
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
|
||||
@ -261,7 +336,6 @@ class APIClient {
|
||||
* @param string $class class name is passed as a string
|
||||
* @return object an instance of $class
|
||||
*/
|
||||
|
||||
public static function deserialize($data, $class)
|
||||
{
|
||||
if (null === $data) {
|
||||
@ -304,5 +378,37 @@ class APIClient {
|
||||
return $deserialized;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the header 'Accept' based on an array of Accept provided
|
||||
*
|
||||
* @param array[string] $accept Array of header
|
||||
* @return string Accept (e.g. application/json)
|
||||
*/
|
||||
public static function selectHeaderAccept($accept) {
|
||||
if (count($accept) === 0 or (count($accept) === 1 and $accept[0] === '')) {
|
||||
return NULL;
|
||||
} elseif (preg_grep("/application\/json/i", $accept)) {
|
||||
return 'application/json';
|
||||
} else {
|
||||
return implode(',', $accept);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return the content type based on an array of content-type provided
|
||||
*
|
||||
* @param array[string] content_type_array Array fo content-type
|
||||
* @return string Content-Type (e.g. application/json)
|
||||
*/
|
||||
public static function selectHeaderContentType($content_type) {
|
||||
if (count($content_type) === 0 or (count($content_type) === 1 and $content_type[0] === '')) {
|
||||
return 'application/json';
|
||||
} elseif (preg_grep("/application\/json/i", $content_type)) {
|
||||
return 'application/json';
|
||||
} else {
|
||||
return implode(',', $content_type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ class {{classname}} {
|
||||
{{#allParams}}{{#required}}
|
||||
// verify the required parameter '{{paramName}}' is set
|
||||
if (${{paramName}} === null) {
|
||||
throw new \Exception("Missing the required parameter ${{paramName}} when calling {{nickname}}");
|
||||
throw new \InvalidArgumentException('Missing the required parameter ${{paramName}} when calling {{nickname}}');
|
||||
}
|
||||
{{/required}}{{/allParams}}
|
||||
|
||||
@ -54,12 +54,11 @@ class {{classname}} {
|
||||
$queryParams = array();
|
||||
$headerParams = array();
|
||||
$formParams = array();
|
||||
$_header_accept = '{{#produces}}{{mediaType}}{{#hasMore}}, {{/hasMore}}{{/produces}}';
|
||||
if ($_header_accept !== '') {
|
||||
$_header_accept = $this->apiClient->selectHeaderAccept(array({{#produces}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/produces}}));
|
||||
if (!is_null($_header_accept)) {
|
||||
$headerParams['Accept'] = $_header_accept;
|
||||
}
|
||||
$_header_content_type = array({{#consumes}}'{{mediaType}}'{{#hasMore}},{{/hasMore}}{{/consumes}});
|
||||
$headerParams['Content-Type'] = count($_header_content_type) > 0 ? $_header_content_type[0] : 'application/json';
|
||||
$headerParams['Content-Type'] = $this->apiClient->selectHeaderContentType(array({{#consumes}}'{{mediaType}}'{{#hasMore}},{{/hasMore}}{{/consumes}}));
|
||||
|
||||
{{#queryParams}}// query params
|
||||
if(${{paramName}} !== null) {
|
||||
@ -92,18 +91,20 @@ class {{classname}} {
|
||||
$httpBody = $formParams;
|
||||
}
|
||||
|
||||
// authentication setting, if any
|
||||
$authSettings = array({{#authMethods}}'{{name}}'{{#hasMore}}, {{/hasMore}}{{/authMethods}});
|
||||
|
||||
// make the API Call
|
||||
$response = $this->apiClient->callAPI($resourcePath, $method,
|
||||
$queryParams, $httpBody,
|
||||
$headerParams);
|
||||
$headerParams, $authSettings);
|
||||
|
||||
{{#returnType}}if(! $response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$responseObject = $this->apiClient->deserialize($response,
|
||||
'{{returnType}}');
|
||||
return $responseObject;{{/returnType}}
|
||||
$responseObject = $this->apiClient->deserialize($response,'{{returnType}}');
|
||||
return $responseObject;{{/returnType}}
|
||||
}
|
||||
{{/operation}}
|
||||
{{newline}}
|
||||
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2015 Reverb Technologies, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace {{invokerPackage}};
|
||||
|
||||
class Configuration {
|
||||
|
||||
public static $PATCH = "PATCH";
|
||||
public static $POST = "POST";
|
||||
public static $GET = "GET";
|
||||
public static $PUT = "PUT";
|
||||
public static $DELETE = "DELETE";
|
||||
|
||||
// authentication setting
|
||||
public static $apiKey = array();
|
||||
public static $apiKeyPrefix = array();
|
||||
public static $username = '';
|
||||
public static $password = '';
|
||||
|
||||
|
||||
}
|
||||
|
@ -38,5 +38,37 @@ TODO
|
||||
|
||||
## Tests
|
||||
|
||||
TODO
|
||||
(Make sure you are running it inside of a [virtualenv](http://docs.python-guide.org/en/latest/dev/virtualenvs/))
|
||||
|
||||
You can run the tests in the current python platform:
|
||||
|
||||
```sh
|
||||
$ make test
|
||||
[... magically installs dependencies and runs tests on your virtualenv]
|
||||
Ran 7 tests in 19.289s
|
||||
|
||||
OK
|
||||
```
|
||||
or
|
||||
|
||||
```
|
||||
$ mvn integration-test -rf :PythonPetstoreClientTests
|
||||
Using 2195432783 as seed
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 37.594 s
|
||||
[INFO] Finished at: 2015-05-16T18:00:35+08:00
|
||||
[INFO] Final Memory: 11M/156M
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
```
|
||||
If you want to run the tests in all the python platforms:
|
||||
|
||||
```sh
|
||||
$ make test-all
|
||||
[... tox creates a virtualenv for every platform and runs tests inside of each]
|
||||
py27: commands succeeded
|
||||
py34: commands succeeded
|
||||
congratulations :)
|
||||
```
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
# import apis into api package
|
||||
{{#apiInfo}}{{#apis}}from .{{classVarName}} import {{classname}}
|
||||
{{/apis}}{{/apiInfo}}
|
@ -1,13 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
"""Add all of the modules in the current directory to __all__"""
|
||||
import os
|
||||
from __future__ import absolute_import
|
||||
|
||||
{{#models}}{{#model}}
|
||||
from .{{classVarName}} import {{classname}}
|
||||
# import models into model package
|
||||
{{#models}}{{#model}}from .{{classVarName}} import {{classname}}
|
||||
{{/model}}{{/models}}
|
||||
|
||||
__all__ = []
|
||||
|
||||
for module in os.listdir(os.path.dirname(__file__)):
|
||||
if module != '__init__.py' and module[-3:] == '.py':
|
||||
__all__.append(module[:-3])
|
||||
|
@ -1,22 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
"""Add all of the modules in the current directory to __all__"""
|
||||
import os
|
||||
from __future__ import absolute_import
|
||||
|
||||
# import models into package
|
||||
{{#models}}{{#model}}
|
||||
from .models.{{classVarName}} import {{classname}}
|
||||
# import models into sdk package
|
||||
{{#models}}{{#model}}from .models.{{classVarName}} import {{classname}}
|
||||
{{/model}}{{/models}}
|
||||
|
||||
# import apis into package
|
||||
{{#apiInfo}}{{#apis}}
|
||||
from .{{classVarName}} import {{classname}}
|
||||
# import apis into sdk package
|
||||
{{#apiInfo}}{{#apis}}from .apis.{{classVarName}} import {{classname}}
|
||||
{{/apis}}{{/apiInfo}}
|
||||
|
||||
# import ApiClient
|
||||
from .swagger import ApiClient
|
||||
|
||||
__all__ = []
|
||||
|
||||
for module in os.listdir(os.path.dirname(__file__)):
|
||||
if module != '__init__.py' and module[-3:] == '.py':
|
||||
__all__.append(module[:-3])
|
||||
|
@ -19,100 +19,74 @@ Copyright 2015 Reverb Technologies, Inc.
|
||||
|
||||
NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
import os
|
||||
import urllib
|
||||
|
||||
from models import *
|
||||
# python 2 and python 3 compatibility library
|
||||
from six import iteritems
|
||||
|
||||
from ..util import remove_none
|
||||
|
||||
{{#operations}}
|
||||
class {{classname}}(object):
|
||||
|
||||
def __init__(self, apiClient):
|
||||
self.apiClient = apiClient
|
||||
|
||||
{{newline}}
|
||||
def __init__(self, api_client):
|
||||
self.api_client = api_client
|
||||
{{#operation}}
|
||||
def {{nickname}}(self, {{#requiredParams}}{{paramName}}{{#defaultValue}} = None{{/defaultValue}}, {{/requiredParams}}**kwargs):
|
||||
"""{{{summary}}}
|
||||
def {{nickname}}(self, {{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}**kwargs):
|
||||
"""
|
||||
{{{summary}}}
|
||||
{{{notes}}}
|
||||
|
||||
Args:
|
||||
{{#allParams}}{{paramName}}, {{dataType}}: {{{description}}} {{^optional}}(required){{/optional}}{{#optional}}(optional){{/optional}}
|
||||
{{/allParams}}
|
||||
|
||||
Returns: {{returnType}}
|
||||
{{#allParams}}:param {{dataType}} {{paramName}}: {{{description}}} {{#required}}(required){{/required}}{{#optional}}(optional){{/optional}}
|
||||
{{/allParams}}
|
||||
:return: {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}None{{/returnType}}
|
||||
"""
|
||||
|
||||
allParams = [{{#allParams}}'{{paramName}}'{{#hasMore}}, {{/hasMore}}{{/allParams}}]
|
||||
{{#allParams}}{{#required}}
|
||||
# verify the required parameter '{{paramName}}' is set
|
||||
if {{paramName}} is None:
|
||||
raise ValueError("Missing the required parameter `{{paramName}}` when calling `{{nickname}}`")
|
||||
{{/required}}{{/allParams}}
|
||||
all_params = [{{#allParams}}'{{paramName}}'{{#hasMore}}, {{/hasMore}}{{/allParams}}]
|
||||
|
||||
params = locals()
|
||||
for (key, val) in params['kwargs'].iteritems():
|
||||
if key not in allParams:
|
||||
for key, val in iteritems(params['kwargs']):
|
||||
if key not in all_params:
|
||||
raise TypeError("Got an unexpected keyword argument '%s' to method {{nickname}}" % key)
|
||||
params[key] = val
|
||||
del params['kwargs']
|
||||
|
||||
resourcePath = '{{path}}'
|
||||
resourcePath = resourcePath.replace('{format}', 'json')
|
||||
resource_path = '{{path}}'.replace('{format}', 'json')
|
||||
method = '{{httpMethod}}'
|
||||
|
||||
queryParams = {}
|
||||
headerParams = {}
|
||||
formParams = {}
|
||||
files = {}
|
||||
bodyParam = None
|
||||
path_params = remove_none(dict({{#pathParams}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/pathParams}}))
|
||||
query_params = remove_none(dict({{#queryParams}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/queryParams}}))
|
||||
header_params = remove_none(dict({{#headerParams}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/headerParams}}))
|
||||
form_params = remove_none(dict({{#formParams}}{{^isFile}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/isFile}}{{/formParams}}))
|
||||
files = remove_none(dict({{#formParams}}{{#isFile}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/isFile}}{{/formParams}}))
|
||||
body_params = {{#bodyParam}}params.get('{{paramName}}'){{/bodyParam}}{{^bodyParam}}None{{/bodyParam}}
|
||||
|
||||
accepts = [{{#produces}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/produces}}]
|
||||
headerParams['Accept'] = ', '.join(accepts)
|
||||
header_params['Accept'] = ', '.join(accepts)
|
||||
|
||||
content_types = [{{#consumes}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/consumes}}]
|
||||
headerParams['Content-Type'] = content_types[0] if len(content_types) > 0 else 'application/json'
|
||||
|
||||
{{#queryParams}}
|
||||
if ('{{paramName}}' in params):
|
||||
queryParams['{{baseName}}'] = self.apiClient.toPathValue(params['{{paramName}}'])
|
||||
{{/queryParams}}
|
||||
|
||||
{{#headerParams}}
|
||||
if ('{{paramName}}' in params):
|
||||
headerParams['{{baseName}}'] = params['{{paramName}}']
|
||||
{{/headerParams}}
|
||||
|
||||
{{#pathParams}}
|
||||
if ('{{paramName}}' in params):
|
||||
replacement = str(self.apiClient.toPathValue(params['{{paramName}}']))
|
||||
replacement = urllib.quote(replacement)
|
||||
resourcePath = resourcePath.replace('{' + '{{baseName}}' + '}',
|
||||
replacement)
|
||||
{{/pathParams}}
|
||||
|
||||
{{#formParams}}
|
||||
if ('{{paramName}}' in params):
|
||||
{{#notFile}}formParams['{{baseName}}'] = params['{{paramName}}']{{/notFile}}{{#isFile}}files['{{baseName}}'] = params['{{paramName}}']{{/isFile}}
|
||||
{{/formParams}}
|
||||
|
||||
{{#bodyParam}}
|
||||
if ('{{paramName}}' in params):
|
||||
bodyParam = params['{{paramName}}']
|
||||
{{/bodyParam}}
|
||||
|
||||
postData = (formParams if formParams else bodyParam)
|
||||
|
||||
response = self.apiClient.callAPI(resourcePath, method, queryParams,
|
||||
postData, headerParams, files=files)
|
||||
header_params['Content-Type'] = content_types[0] if len(content_types) > 0 else 'application/json'
|
||||
|
||||
response = self.api_client.call_api(resource_path, method, path_params, query_params, header_params,
|
||||
body=body_params, post_params=form_params, files=files,
|
||||
response={{#returnType}}'{{returnType}}'{{/returnType}}{{^returnType}}None{{/returnType}})
|
||||
{{#returnType}}
|
||||
if not response:
|
||||
return None
|
||||
|
||||
responseObject = self.apiClient.deserialize(response, '{{returnType}}')
|
||||
return responseObject
|
||||
{{/returnType}}
|
||||
{{newline}}
|
||||
{{newline}}
|
||||
{{/operation}}
|
||||
{{newline}}
|
||||
return response
|
||||
{{/returnType}}{{/operation}}
|
||||
{{/operations}}
|
||||
{{newline}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -20,33 +20,40 @@ Copyright 2015 Reverb Technologies, Inc.
|
||||
{{#model}}
|
||||
|
||||
class {{classname}}(object):
|
||||
"""NOTE: This class is auto generated by the swagger code generator program.
|
||||
Do not edit the class manually."""
|
||||
|
||||
"""
|
||||
NOTE: This class is auto generated by the swagger code generator program.
|
||||
Do not edit the class manually.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Attributes:
|
||||
swaggerTypes (dict): The key is attribute name and the value is attribute type.
|
||||
attributeMap (dict): The key is attribute name and the value is json key in definition.
|
||||
Swagger model
|
||||
|
||||
:param dict swaggerTypes: The key is attribute name and the value is attribute type.
|
||||
:param dict attributeMap: The key is attribute name and the value is json key in definition.
|
||||
"""
|
||||
self.swaggerTypes = {
|
||||
{{#vars}}
|
||||
'{{name}}': '{{{datatype}}}'{{#hasMore}},
|
||||
{{/hasMore}}
|
||||
{{/vars}}{{newline}}
|
||||
self.swagger_types = {
|
||||
{{#vars}}'{{name}}': '{{{datatype}}}'{{#hasMore}},
|
||||
{{/hasMore}}{{/vars}}
|
||||
}
|
||||
|
||||
self.attributeMap = {
|
||||
{{#vars}}
|
||||
'{{name}}': '{{baseName}}'{{#hasMore}},{{/hasMore}}
|
||||
{{/vars}}
|
||||
self.attribute_map = {
|
||||
{{#vars}}'{{name}}': '{{baseName}}'{{#hasMore}},
|
||||
{{/hasMore}}{{/vars}}
|
||||
}
|
||||
|
||||
{{#vars}}
|
||||
{{#description}}#{{description}}
|
||||
{{/description}}
|
||||
self.{{name}} = None # {{{datatype}}}
|
||||
{{#description}}# {{description}}{{/description}}
|
||||
self.{{name}} = None # {{{datatype}}}
|
||||
{{/vars}}
|
||||
|
||||
def __repr__(self):
|
||||
properties = []
|
||||
for p in self.__dict__:
|
||||
if p != 'swaggerTypes' and p != 'attributeMap':
|
||||
properties.append('{prop}={val!r}'.format(prop=p, val=self.__dict__[p]))
|
||||
|
||||
return '<{name} {props}>'.format(name=__name__, props=' '.join(properties))
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
|
||||
|
||||
|
223
modules/swagger-codegen/src/main/resources/python/rest.mustache
Normal file
223
modules/swagger-codegen/src/main/resources/python/rest.mustache
Normal file
@ -0,0 +1,223 @@
|
||||
# coding: utf-8
|
||||
import sys
|
||||
import io
|
||||
import json
|
||||
|
||||
# python 2 and python 3 compatibility library
|
||||
from six import iteritems
|
||||
|
||||
try:
|
||||
import urllib3
|
||||
except ImportError:
|
||||
raise ImportError('Swagger python client requires urllib3.')
|
||||
|
||||
try:
|
||||
# for python3
|
||||
from urllib.parse import urlencode
|
||||
except ImportError:
|
||||
# for python2
|
||||
from urllib import urlencode
|
||||
|
||||
|
||||
class RESTResponse(io.IOBase):
|
||||
|
||||
def __init__(self, resp):
|
||||
self.urllib3_response = resp
|
||||
self.status = resp.status
|
||||
self.reason = resp.reason
|
||||
self.data = resp.data
|
||||
|
||||
def getheaders(self):
|
||||
"""
|
||||
Returns a dictionary of the response headers.
|
||||
"""
|
||||
return self.urllib3_response.getheaders()
|
||||
|
||||
def getheader(self, name, default=None):
|
||||
"""
|
||||
Returns a given response header.
|
||||
"""
|
||||
return self.urllib3_response.getheader(name, default)
|
||||
|
||||
class RESTClientObject(object):
|
||||
|
||||
def __init__(self, pools_size=4):
|
||||
self.pool_manager = urllib3.PoolManager(
|
||||
num_pools=pools_size
|
||||
)
|
||||
|
||||
def request(self, method, url, query_params=None, headers=None,
|
||||
body=None, post_params=None):
|
||||
"""
|
||||
:param method: http request method
|
||||
:param url: http request url
|
||||
:param query_params: query parameters in the url
|
||||
:param headers: http request headers
|
||||
:param body: request json body, for `application/json`
|
||||
:param post_params: request post parameters, `application/x-www-form-urlencode`
|
||||
and `multipart/form-data`
|
||||
:param raw_response: if return the raw response
|
||||
"""
|
||||
method = method.upper()
|
||||
assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', 'PATCH']
|
||||
|
||||
if post_params and body:
|
||||
raise ValueError("body parameter cannot be used with post_params parameter.")
|
||||
|
||||
post_params = post_params or {}
|
||||
headers = headers or {}
|
||||
|
||||
if 'Content-Type' not in headers:
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
# For `POST`, `PUT`, `PATCH`
|
||||
if method in ['POST', 'PUT', 'PATCH']:
|
||||
if query_params:
|
||||
url += '?' + urlencode(query_params)
|
||||
if headers['Content-Type'] == 'application/json':
|
||||
r = self.pool_manager.request(method, url,
|
||||
body=json.dumps(body),
|
||||
headers=headers)
|
||||
if headers['Content-Type'] == 'application/x-www-form-urlencoded':
|
||||
r = self.pool_manager.request(method, url,
|
||||
fields=post_params,
|
||||
encode_multipart=False,
|
||||
headers=headers)
|
||||
if headers['Content-Type'] == 'multipart/form-data':
|
||||
# must del headers['Content-Type'], or the correct Content-Type
|
||||
# which generated by urllib3 will be overwritten.
|
||||
del headers['Content-Type']
|
||||
r = self.pool_manager.request(method, url,
|
||||
fields=post_params,
|
||||
encode_multipart=True,
|
||||
headers=headers)
|
||||
# For `GET`, `HEAD`, `DELETE`
|
||||
else:
|
||||
r = self.pool_manager.request(method, url,
|
||||
fields=query_params,
|
||||
headers=headers)
|
||||
r = RESTResponse(r)
|
||||
|
||||
if r.status not in range(200, 206):
|
||||
raise ErrorResponse(r)
|
||||
|
||||
return self.process_response(r)
|
||||
|
||||
def process_response(self, response):
|
||||
# In the python 3, the response.data is bytes.
|
||||
# we need to decode it to string.
|
||||
if sys.version_info > (3,):
|
||||
data = response.data.decode('utf8')
|
||||
else:
|
||||
data = response.data
|
||||
try:
|
||||
resp = json.loads(data)
|
||||
except ValueError:
|
||||
resp = data
|
||||
|
||||
return resp
|
||||
|
||||
def GET(self, url, headers=None, query_params=None):
|
||||
return self.request("GET", url, headers=headers, query_params=query_params)
|
||||
|
||||
def HEAD(self, url, headers=None, query_params=None):
|
||||
return self.request("HEAD", url, headers=headers, query_params=query_params)
|
||||
|
||||
def DELETE(self, url, headers=None, query_params=None):
|
||||
return self.request("DELETE", url, headers=headers, query_params=query_params)
|
||||
|
||||
def POST(self, url, headers=None, post_params=None, body=None):
|
||||
return self.request("POST", url, headers=headers, post_params=post_params, body=body)
|
||||
|
||||
def PUT(self, url, headers=None, post_params=None, body=None):
|
||||
return self.request("PUT", url, headers=headers, post_params=post_params, body=body)
|
||||
|
||||
def PATCH(self, url, headers=None, post_params=None, body=None):
|
||||
return self.request("PATCH", url, headers=headers, post_params=post_params, body=body)
|
||||
|
||||
|
||||
class ErrorResponse(Exception):
|
||||
"""
|
||||
Non-2xx HTTP response
|
||||
"""
|
||||
|
||||
def __init__(self, http_resp):
|
||||
self.status = http_resp.status
|
||||
self.reason = http_resp.reason
|
||||
self.body = http_resp.data
|
||||
self.headers = http_resp.getheaders()
|
||||
|
||||
# In the python 3, the self.body is bytes.
|
||||
# we need to decode it to string.
|
||||
if sys.version_info > (3,):
|
||||
data = self.body.decode('utf8')
|
||||
else:
|
||||
data = self.body
|
||||
|
||||
try:
|
||||
self.body = json.loads(data)
|
||||
except ValueError:
|
||||
self.body = data
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Custom error response messages
|
||||
"""
|
||||
return "({0})\nReason: {1}\nHeader: {2}\nBody: {3}\n".\
|
||||
format(self.status, self.reason, self.headers, self.body)
|
||||
|
||||
class RESTClient(object):
|
||||
"""
|
||||
A class with all class methods to perform JSON requests.
|
||||
"""
|
||||
|
||||
IMPL = RESTClientObject()
|
||||
|
||||
@classmethod
|
||||
def request(cls, *n, **kw):
|
||||
"""
|
||||
Perform a REST request and parse the response.
|
||||
"""
|
||||
return cls.IMPL.request(*n, **kw)
|
||||
|
||||
@classmethod
|
||||
def GET(cls, *n, **kw):
|
||||
"""
|
||||
Perform a GET request using `RESTClient.request()`.
|
||||
"""
|
||||
return cls.IMPL.GET(*n, **kw)
|
||||
|
||||
@classmethod
|
||||
def HEAD(cls, *n, **kw):
|
||||
"""
|
||||
Perform a HEAD request using `RESTClient.request()`.
|
||||
"""
|
||||
return cls.IMPL.GET(*n, **kw)
|
||||
|
||||
@classmethod
|
||||
def POST(cls, *n, **kw):
|
||||
"""
|
||||
Perform a POST request using `RESTClient.request()`
|
||||
"""
|
||||
return cls.IMPL.POST(*n, **kw)
|
||||
|
||||
@classmethod
|
||||
def PUT(cls, *n, **kw):
|
||||
"""
|
||||
Perform a PUT request using `RESTClient.request()`
|
||||
"""
|
||||
return cls.IMPL.PUT(*n, **kw)
|
||||
|
||||
@classmethod
|
||||
def PATCH(cls, *n, **kw):
|
||||
"""
|
||||
Perform a PATCH request using `RESTClient.request()`
|
||||
"""
|
||||
return cls.IMPL.PATCH(*n, **kw)
|
||||
|
||||
@classmethod
|
||||
def DELETE(cls, *n, **kw):
|
||||
"""
|
||||
Perform a DELETE request using `RESTClient.request()`
|
||||
"""
|
||||
return cls.IMPL.DELETE(*n, **kw)
|
@ -12,7 +12,7 @@ from setuptools import setup, find_packages
|
||||
# Try reading the setuptools documentation:
|
||||
# http://pypi.python.org/pypi/setuptools
|
||||
|
||||
REQUIRES = []
|
||||
REQUIRES = ["urllib3 >= 1.10", "six >= 1.9"]
|
||||
|
||||
setup(
|
||||
name="{{module}}",
|
||||
@ -30,3 +30,11 @@ setup(
|
||||
)
|
||||
|
||||
{{/hasMore}}{{/apis}}{{/apiInfo}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,118 +6,109 @@ server communication, and is invariant across implementations. Specifics of
|
||||
the methods and models for each application are generated from the Swagger
|
||||
templates."""
|
||||
|
||||
import sys
|
||||
from __future__ import absolute_import
|
||||
from . import models
|
||||
from .rest import RESTClient
|
||||
|
||||
import os
|
||||
import re
|
||||
import urllib
|
||||
import urllib2
|
||||
import httplib
|
||||
import json
|
||||
import datetime
|
||||
import mimetypes
|
||||
import random
|
||||
import string
|
||||
import models
|
||||
|
||||
# python 2 and python 3 compatibility library
|
||||
from six import iteritems
|
||||
|
||||
try:
|
||||
# for python3
|
||||
from urllib.parse import quote
|
||||
except ImportError:
|
||||
# for python2
|
||||
from urllib import quote
|
||||
|
||||
|
||||
class ApiClient(object):
|
||||
"""Generic API client for Swagger client library builds
|
||||
|
||||
Attributes:
|
||||
host: The base path for the server to call
|
||||
headerName: a header to pass when making calls to the API
|
||||
headerValue: a header value to pass when making calls to the API
|
||||
"""
|
||||
def __init__(self, host=None, headerName=None, headerValue=None):
|
||||
self.defaultHeaders = {}
|
||||
if (headerName is not None):
|
||||
self.defaultHeaders[headerName] = headerValue
|
||||
Generic API client for Swagger client library builds
|
||||
|
||||
:param host: The base path for the server to call
|
||||
:param header_name: a header to pass when making calls to the API
|
||||
:param header_value: a header value to pass when making calls to the API
|
||||
"""
|
||||
def __init__(self, host=None, header_name=None, header_value=None):
|
||||
self.default_headers = {}
|
||||
if header_name is not None:
|
||||
self.default_headers[header_name] = header_value
|
||||
self.host = host
|
||||
self.cookie = None
|
||||
self.boundary = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(30))
|
||||
# Set default User-Agent.
|
||||
self.user_agent = 'Python-Swagger'
|
||||
|
||||
@property
|
||||
def user_agent(self):
|
||||
return self.defaultHeaders['User-Agent']
|
||||
return self.default_headers['User-Agent']
|
||||
|
||||
@user_agent.setter
|
||||
def user_agent(self, value):
|
||||
self.defaultHeaders['User-Agent'] = value
|
||||
self.default_headers['User-Agent'] = value
|
||||
|
||||
def setDefaultHeader(self, headerName, headerValue):
|
||||
self.defaultHeaders[headerName] = headerValue
|
||||
def set_default_header(self, header_name, header_value):
|
||||
self.default_headers[header_name] = header_value
|
||||
|
||||
def callAPI(self, resourcePath, method, queryParams, postData,
|
||||
headerParams=None, files=None):
|
||||
|
||||
url = self.host + resourcePath
|
||||
|
||||
mergedHeaderParams = self.defaultHeaders.copy()
|
||||
mergedHeaderParams.update(headerParams)
|
||||
headers = {}
|
||||
if mergedHeaderParams:
|
||||
for param, value in mergedHeaderParams.iteritems():
|
||||
headers[param] = ApiClient.sanitizeForSerialization(value)
|
||||
def call_api(self, resource_path, method, path_params=None, query_params=None, header_params=None,
|
||||
body=None, post_params=None, files=None, response=None):
|
||||
|
||||
# headers parameters
|
||||
headers = self.default_headers.copy()
|
||||
headers.update(header_params)
|
||||
if self.cookie:
|
||||
headers['Cookie'] = ApiClient.sanitizeForSerialization(self.cookie)
|
||||
headers['Cookie'] = self.cookie
|
||||
if headers:
|
||||
headers = ApiClient.sanitize_for_serialization(headers)
|
||||
|
||||
data = None
|
||||
# path parameters
|
||||
if path_params:
|
||||
path_params = ApiClient.sanitize_for_serialization(path_params)
|
||||
for k, v in iteritems(path_params):
|
||||
replacement = quote(str(self.to_path_value(v)))
|
||||
resource_path = resource_path.replace('{' + k + '}', replacement)
|
||||
|
||||
if queryParams:
|
||||
# Need to remove None values, these should not be sent
|
||||
sentQueryParams = {}
|
||||
for param, value in queryParams.items():
|
||||
if value is not None:
|
||||
sentQueryParams[param] = ApiClient.sanitizeForSerialization(value)
|
||||
url = url + '?' + urllib.urlencode(sentQueryParams)
|
||||
# query parameters
|
||||
if query_params:
|
||||
query_params = ApiClient.sanitize_for_serialization(query_params)
|
||||
query_params = {k: self.to_path_value(v) for k, v in iteritems(query_params)}
|
||||
|
||||
if method in ['GET']:
|
||||
#Options to add statements later on and for compatibility
|
||||
pass
|
||||
# post parameters
|
||||
if post_params:
|
||||
post_params = self.prepare_post_parameters(post_params, files)
|
||||
post_params = ApiClient.sanitize_for_serialization(post_params)
|
||||
|
||||
elif method in ['POST', 'PUT', 'DELETE']:
|
||||
if postData:
|
||||
postData = ApiClient.sanitizeForSerialization(postData)
|
||||
if 'Content-Type' not in headers:
|
||||
headers['Content-Type'] = 'application/json'
|
||||
data = json.dumps(postData)
|
||||
elif headers['Content-Type'] == 'application/json':
|
||||
data = json.dumps(postData)
|
||||
elif headers['Content-Type'] == 'multipart/form-data':
|
||||
data = self.buildMultipartFormData(postData, files)
|
||||
headers['Content-Type'] = 'multipart/form-data; boundary={0}'.format(self.boundary)
|
||||
headers['Content-length'] = str(len(data))
|
||||
else:
|
||||
data = urllib.urlencode(postData)
|
||||
# body
|
||||
if body:
|
||||
body = ApiClient.sanitize_for_serialization(body)
|
||||
|
||||
# request url
|
||||
url = self.host + resource_path
|
||||
|
||||
# perform request and return response
|
||||
response_data = self.request(method, url, query_params=query_params, headers=headers,
|
||||
post_params=post_params, body=body)
|
||||
|
||||
# deserialize response data
|
||||
if response:
|
||||
return self.deserialize(response_data, response)
|
||||
else:
|
||||
raise Exception('Method ' + method + ' is not recognized.')
|
||||
return None
|
||||
|
||||
request = MethodRequest(method=method, url=url, headers=headers,
|
||||
data=data)
|
||||
def to_path_value(self, obj):
|
||||
"""
|
||||
Convert a string or object to a path-friendly value
|
||||
|
||||
:param obj: object or string value
|
||||
|
||||
# Make the request
|
||||
response = urllib2.urlopen(request)
|
||||
if 'Set-Cookie' in response.headers:
|
||||
self.cookie = response.headers['Set-Cookie']
|
||||
string = response.read()
|
||||
|
||||
try:
|
||||
data = json.loads(string)
|
||||
except ValueError: # PUT requests don't return anything
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
||||
def toPathValue(self, obj):
|
||||
"""Convert a string or object to a path-friendly value
|
||||
Args:
|
||||
obj -- object or string value
|
||||
Returns:
|
||||
string -- quoted value
|
||||
:return string: quoted value
|
||||
"""
|
||||
if type(obj) == list:
|
||||
return ','.join(obj)
|
||||
@ -125,12 +116,12 @@ class ApiClient(object):
|
||||
return str(obj)
|
||||
|
||||
@staticmethod
|
||||
def sanitizeForSerialization(obj):
|
||||
def sanitize_for_serialization(obj):
|
||||
"""
|
||||
Sanitize an object for Request.
|
||||
|
||||
If obj is None, return None.
|
||||
If obj is str, int, long, float, bool, return directly.
|
||||
If obj is str, int, float, bool, return directly.
|
||||
If obj is datetime.datetime, datetime.date convert to string in iso8601 format.
|
||||
If obj is list, santize each element in the list.
|
||||
If obj is dict, return the dict.
|
||||
@ -138,113 +129,80 @@ class ApiClient(object):
|
||||
"""
|
||||
if isinstance(obj, type(None)):
|
||||
return None
|
||||
elif isinstance(obj, (str, int, long, float, bool, file)):
|
||||
elif isinstance(obj, (str, int, float, bool, tuple)):
|
||||
return obj
|
||||
elif isinstance(obj, list):
|
||||
return [ApiClient.sanitizeForSerialization(subObj) for subObj in obj]
|
||||
return [ApiClient.sanitize_for_serialization(sub_obj) for sub_obj in obj]
|
||||
elif isinstance(obj, (datetime.datetime, datetime.date)):
|
||||
return obj.isoformat()
|
||||
else:
|
||||
if isinstance(obj, dict):
|
||||
objDict = obj
|
||||
obj_dict = obj
|
||||
else:
|
||||
# Convert model obj to dict except attributes `swaggerTypes`, `attributeMap`
|
||||
# Convert model obj to dict except attributes `swagger_types`, `attribute_map`
|
||||
# and attributes which value is not None.
|
||||
# Convert attribute name to json key in model definition for request.
|
||||
objDict = {obj.attributeMap[key]: val
|
||||
for key, val in obj.__dict__.iteritems()
|
||||
if key != 'swaggerTypes' and key != 'attributeMap' and val is not None}
|
||||
return {key: ApiClient.sanitizeForSerialization(val)
|
||||
for (key, val) in objDict.iteritems()}
|
||||
obj_dict = {obj.attribute_map[key]: val
|
||||
for key, val in iteritems(obj.__dict__)
|
||||
if key != 'swagger_types' and key != 'attribute_map' and val is not None}
|
||||
return {key: ApiClient.sanitize_for_serialization(val)
|
||||
for key, val in iteritems(obj_dict)}
|
||||
|
||||
def buildMultipartFormData(self, postData, files):
|
||||
def escape_quotes(s):
|
||||
return s.replace('"', '\\"')
|
||||
def deserialize(self, obj, obj_class):
|
||||
"""
|
||||
Derialize a JSON string into an object.
|
||||
|
||||
lines = []
|
||||
:param obj: string or object to be deserialized
|
||||
:param obj_class: class literal for deserialzied object, or string of class name
|
||||
|
||||
for name, value in postData.items():
|
||||
lines.extend((
|
||||
'--{0}'.format(self.boundary),
|
||||
'Content-Disposition: form-data; name="{0}"'.format(escape_quotes(name)),
|
||||
'',
|
||||
str(value),
|
||||
))
|
||||
|
||||
for name, filepath in files.items():
|
||||
f = open(filepath, 'r')
|
||||
filename = filepath.split('/')[-1]
|
||||
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
lines.extend((
|
||||
'--{0}'.format(self.boundary),
|
||||
'Content-Disposition: form-data; name="{0}"; filename="{1}"'.format(escape_quotes(name), escape_quotes(filename)),
|
||||
'Content-Type: {0}'.format(mimetype),
|
||||
'',
|
||||
f.read()
|
||||
))
|
||||
|
||||
lines.extend((
|
||||
'--{0}--'.format(self.boundary),
|
||||
''
|
||||
))
|
||||
return '\r\n'.join(lines)
|
||||
|
||||
def deserialize(self, obj, objClass):
|
||||
"""Derialize a JSON string into an object.
|
||||
|
||||
Args:
|
||||
obj -- string or object to be deserialized
|
||||
objClass -- class literal for deserialzied object, or string
|
||||
of class name
|
||||
Returns:
|
||||
object -- deserialized object"""
|
||||
|
||||
# Have to accept objClass as string or actual type. Type could be a
|
||||
:return object: deserialized object
|
||||
"""
|
||||
# Have to accept obj_class as string or actual type. Type could be a
|
||||
# native Python type, or one of the model classes.
|
||||
if type(objClass) == str:
|
||||
if 'list[' in objClass:
|
||||
match = re.match('list\[(.*)\]', objClass)
|
||||
subClass = match.group(1)
|
||||
return [self.deserialize(subObj, subClass) for subObj in obj]
|
||||
if type(obj_class) == str:
|
||||
if 'list[' in obj_class:
|
||||
match = re.match('list\[(.*)\]', obj_class)
|
||||
sub_class = match.group(1)
|
||||
return [self.deserialize(sub_obj, sub_class) for sub_obj in obj]
|
||||
|
||||
if (objClass in ['int', 'float', 'long', 'dict', 'list', 'str', 'bool', 'datetime']):
|
||||
objClass = eval(objClass)
|
||||
if obj_class in ['int', 'float', 'dict', 'list', 'str', 'bool', 'datetime']:
|
||||
obj_class = eval(obj_class)
|
||||
else: # not a native type, must be model class
|
||||
objClass = eval('models.' + objClass)
|
||||
obj_class = eval('models.' + obj_class)
|
||||
|
||||
if objClass in [int, long, float, dict, list, str, bool]:
|
||||
return objClass(obj)
|
||||
elif objClass == datetime:
|
||||
if obj_class in [int, float, dict, list, str, bool]:
|
||||
return obj_class(obj)
|
||||
elif obj_class == datetime:
|
||||
return self.__parse_string_to_datetime(obj)
|
||||
|
||||
instance = objClass()
|
||||
instance = obj_class()
|
||||
|
||||
for attr, attrType in instance.swaggerTypes.iteritems():
|
||||
if obj is not None and instance.attributeMap[attr] in obj and type(obj) in [list, dict]:
|
||||
value = obj[instance.attributeMap[attr]]
|
||||
if attrType in ['str', 'int', 'long', 'float', 'bool']:
|
||||
attrType = eval(attrType)
|
||||
for attr, attr_type in iteritems(instance.swagger_types):
|
||||
if obj is not None and instance.attribute_map[attr] in obj and type(obj) in [list, dict]:
|
||||
value = obj[instance.attribute_map[attr]]
|
||||
if attr_type in ['str', 'int', 'float', 'bool']:
|
||||
attr_type = eval(attr_type)
|
||||
try:
|
||||
value = attrType(value)
|
||||
value = attr_type(value)
|
||||
except UnicodeEncodeError:
|
||||
value = unicode(value)
|
||||
except TypeError:
|
||||
value = value
|
||||
setattr(instance, attr, value)
|
||||
elif (attrType == 'datetime'):
|
||||
elif attr_type == 'datetime':
|
||||
setattr(instance, attr, self.__parse_string_to_datetime(value))
|
||||
elif 'list[' in attrType:
|
||||
match = re.match('list\[(.*)\]', attrType)
|
||||
subClass = match.group(1)
|
||||
subValues = []
|
||||
elif 'list[' in attr_type:
|
||||
match = re.match('list\[(.*)\]', attr_type)
|
||||
sub_class = match.group(1)
|
||||
sub_values = []
|
||||
if not value:
|
||||
setattr(instance, attr, None)
|
||||
else:
|
||||
for subValue in value:
|
||||
subValues.append(self.deserialize(subValue, subClass))
|
||||
setattr(instance, attr, subValues)
|
||||
for sub_value in value:
|
||||
sub_values.append(self.deserialize(sub_value, sub_class))
|
||||
setattr(instance, attr, sub_values)
|
||||
else:
|
||||
setattr(instance, attr, self.deserialize(value, attrType))
|
||||
setattr(instance, attr, self.deserialize(value, attr_type))
|
||||
|
||||
return instance
|
||||
|
||||
@ -260,16 +218,42 @@ class ApiClient(object):
|
||||
except ImportError:
|
||||
return string
|
||||
|
||||
class MethodRequest(urllib2.Request):
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Construct a MethodRequest. Usage is the same as for
|
||||
`urllib2.Request` except it also takes an optional `method`
|
||||
keyword argument. If supplied, `method` will be used instead of
|
||||
the default."""
|
||||
def request(self, method, url, query_params=None, headers=None, post_params=None, body=None):
|
||||
"""
|
||||
Perform http request using RESTClient.
|
||||
"""
|
||||
if method == "GET":
|
||||
return RESTClient.GET(url, query_params=query_params, headers=headers)
|
||||
elif method == "HEAD":
|
||||
return RESTClient.HEAD(url, query_params=query_params, headers=headers)
|
||||
elif method == "POST":
|
||||
return RESTClient.POST(url, headers=headers, post_params=post_params, body=body)
|
||||
elif method == "PUT":
|
||||
return RESTClient.PUT(url, headers=headers, post_params=post_params, body=body)
|
||||
elif method == "PATCH":
|
||||
return RESTClient.PATCH(url, headers=headers, post_params=post_params, body=body)
|
||||
elif method == "DELETE":
|
||||
return RESTClient.DELETE(url, query_params=query_params, headers=headers)
|
||||
else:
|
||||
raise ValueError("http method must be `GET`, `HEAD`, `POST`, `PATCH`, `PUT` or `DELETE`")
|
||||
|
||||
def prepare_post_parameters(self, post_params=None, files=None):
|
||||
params = {}
|
||||
|
||||
if post_params:
|
||||
params.update(post_params)
|
||||
|
||||
if files:
|
||||
for k, v in iteritems(files):
|
||||
with open(v, 'rb') as f:
|
||||
filename = os.path.basename(f.name)
|
||||
filedata = f.read()
|
||||
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
params[k] = tuple([filename, filedata, mimetype])
|
||||
|
||||
return params
|
||||
|
||||
|
||||
|
||||
|
||||
if 'method' in kwargs:
|
||||
self.method = kwargs.pop('method')
|
||||
return urllib2.Request.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_method(self):
|
||||
return getattr(self, 'method', urllib2.Request.get_method(self))
|
||||
|
@ -0,0 +1,17 @@
|
||||
from six import iteritems
|
||||
|
||||
def remove_none(obj):
|
||||
if isinstance(obj, (list, tuple, set)):
|
||||
return type(obj)(remove_none(x) for x in obj if x is not None)
|
||||
elif isinstance(obj, dict):
|
||||
return type(obj)((remove_none(k), remove_none(v))
|
||||
for k, v in iteritems(obj) if k is not None and v is not None)
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
def inspect_vars(obj):
|
||||
if not hasattr(obj, '__dict__'):
|
||||
return obj
|
||||
else:
|
||||
return {k: inspect_vars(getattr(obj, k)) for k in dir(obj)}
|
@ -1,57 +1,59 @@
|
||||
require "uri"
|
||||
|
||||
module {{moduleName}}
|
||||
{{#operations}}
|
||||
class {{classname}}
|
||||
basePath = "{{basePath}}"
|
||||
# apiInvoker = APIInvoker
|
||||
class {{classname}}
|
||||
basePath = "{{basePath}}"
|
||||
# apiInvoker = APIInvoker
|
||||
{{#operation}}
|
||||
{{newline}}
|
||||
# {{summary}}
|
||||
# {{notes}}
|
||||
{{#allParams}}{{#required}} # @param {{paramName}} {{description}}
|
||||
{{/required}}{{/allParams}} # @param [Hash] opts the optional parameters
|
||||
{{#allParams}}{{^required}} # @option opts [{{dataType}}] :{{paramName}} {{description}}
|
||||
{{/required}}{{/allParams}} # @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}
|
||||
def self.{{nickname}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}opts = {})
|
||||
{{#allParams}}{{#required}}
|
||||
# verify the required parameter '{{paramName}}' is set
|
||||
raise "Missing the required parameter '{{paramName}}' when calling {{nickname}}" if {{{paramName}}}.nil?
|
||||
{{/required}}{{/allParams}}
|
||||
# {{summary}}
|
||||
# {{notes}}
|
||||
{{#allParams}}{{#required}} # @param {{paramName}} {{description}}
|
||||
{{/required}}{{/allParams}} # @param [Hash] opts the optional parameters
|
||||
{{#allParams}}{{^required}} # @option opts [{{dataType}}] :{{paramName}} {{description}}
|
||||
{{/required}}{{/allParams}} # @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}
|
||||
def self.{{nickname}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}opts = {})
|
||||
{{#allParams}}{{#required}}
|
||||
# verify the required parameter '{{paramName}}' is set
|
||||
raise "Missing the required parameter '{{paramName}}' when calling {{nickname}}" if {{{paramName}}}.nil?
|
||||
{{/required}}{{/allParams}}
|
||||
|
||||
# resource path
|
||||
path = "{{path}}".sub('{format}','json'){{#pathParams}}.sub('{' + '{{baseName}}' + '}', {{paramName}}.to_s){{/pathParams}}
|
||||
# resource path
|
||||
path = "{{path}}".sub('{format}','json'){{#pathParams}}.sub('{' + '{{baseName}}' + '}', {{paramName}}.to_s){{/pathParams}}
|
||||
|
||||
# query parameters
|
||||
query_params = {}{{#queryParams}}{{#required}}
|
||||
query_params[:'{{{baseName}}}'] = {{{paramName}}}{{/required}}{{/queryParams}}{{#queryParams}}{{^required}}
|
||||
query_params[:'{{{baseName}}}'] = opts[:'{{{paramName}}}'] if opts[:'{{{paramName}}}']{{/required}}{{/queryParams}}
|
||||
# query parameters
|
||||
query_params = {}{{#queryParams}}{{#required}}
|
||||
query_params[:'{{{baseName}}}'] = {{{paramName}}}{{/required}}{{/queryParams}}{{#queryParams}}{{^required}}
|
||||
query_params[:'{{{baseName}}}'] = opts[:'{{{paramName}}}'] if opts[:'{{{paramName}}}']{{/required}}{{/queryParams}}
|
||||
|
||||
# header parameters
|
||||
header_params = {}
|
||||
# header parameters
|
||||
header_params = {}
|
||||
|
||||
# HTTP header 'Accept' (if needed)
|
||||
_header_accept = [{{#produces}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/produces}}]
|
||||
_header_accept_result = Swagger::Request.select_header_accept(_header_accept) and header_params['Accept'] = _header_accept_result
|
||||
# HTTP header 'Accept' (if needed)
|
||||
_header_accept = [{{#produces}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/produces}}]
|
||||
_header_accept_result = Swagger::Request.select_header_accept(_header_accept) and header_params['Accept'] = _header_accept_result
|
||||
|
||||
# HTTP header 'Content-Type'
|
||||
_header_content_type = [{{#consumes}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/consumes}}]
|
||||
header_params['Content-Type'] = Swagger::Request.select_header_content_type(_header_content_type){{#headerParams}}{{#required}}
|
||||
header_params[:'{{{baseName}}}'] = {{{paramName}}}{{/required}}{{/headerParams}}{{#headerParams}}{{^required}}
|
||||
header_params[:'{{{baseName}}}'] = opts[:'{{{paramName}}}'] if opts[:'{{{paramName}}}']{{/required}}{{/headerParams}}
|
||||
# HTTP header 'Content-Type'
|
||||
_header_content_type = [{{#consumes}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/consumes}}]
|
||||
header_params['Content-Type'] = Swagger::Request.select_header_content_type(_header_content_type){{#headerParams}}{{#required}}
|
||||
header_params[:'{{{baseName}}}'] = {{{paramName}}}{{/required}}{{/headerParams}}{{#headerParams}}{{^required}}
|
||||
header_params[:'{{{baseName}}}'] = opts[:'{{{paramName}}}'] if opts[:'{{{paramName}}}']{{/required}}{{/headerParams}}
|
||||
|
||||
# form parameters
|
||||
form_params = {}{{#formParams}}{{#required}}
|
||||
form_params["{{baseName}}"] = {{paramName}}{{/required}}{{/formParams}}{{#formParams}}{{^required}}
|
||||
form_params["{{baseName}}"] = opts[:'{{paramName}}'] if opts[:'{{paramName}}']{{/required}}{{/formParams}}
|
||||
# form parameters
|
||||
form_params = {}{{#formParams}}{{#required}}
|
||||
form_params["{{baseName}}"] = {{paramName}}{{/required}}{{/formParams}}{{#formParams}}{{^required}}
|
||||
form_params["{{baseName}}"] = opts[:'{{paramName}}'] if opts[:'{{paramName}}']{{/required}}{{/formParams}}
|
||||
|
||||
# http body (model)
|
||||
{{^bodyParam}}post_body = nil
|
||||
{{/bodyParam}}{{#bodyParam}}post_body = Swagger::Request.object_to_http_body({{#required}}{{{paramName}}}{{/required}}{{^required}}opts[:'{{{paramName}}}']{{/required}})
|
||||
{{/bodyParam}}
|
||||
# http body (model)
|
||||
{{^bodyParam}}post_body = nil
|
||||
{{/bodyParam}}{{#bodyParam}}post_body = Swagger::Request.object_to_http_body({{#required}}{{{paramName}}}{{/required}}{{^required}}opts[:'{{{paramName}}}']{{/required}})
|
||||
{{/bodyParam}}
|
||||
|
||||
{{#returnType}}response = Swagger::Request.new(:{{httpMethod}}, path, {:params => query_params, :headers => header_params, :form_params => form_params, :body => post_body}).make.body
|
||||
{{#returnContainer}}response.map {|response| {{/returnContainer}}obj = {{returnBaseType}}.new() and obj.build_from_hash(response){{#returnContainer}} }{{/returnContainer}}{{/returnType}}{{^returnType}} Swagger::Request.new(:{{httpMethod}}, path, {:params => query_params,:headers => header_params, :form_params => form_params, :body => post_body}).make{{/returnType}}
|
||||
{{#returnType}}response = Swagger::Request.new(:{{httpMethod}}, path, {:params => query_params, :headers => header_params, :form_params => form_params, :body => post_body}).make.body
|
||||
{{#returnContainer}}response.map {|response| {{/returnContainer}}obj = {{returnBaseType}}.new() and obj.build_from_hash(response){{#returnContainer}} }{{/returnContainer}}{{/returnType}}{{^returnType}} Swagger::Request.new(:{{httpMethod}}, path, {:params => query_params,:headers => header_params, :form_params => form_params, :body => post_body}).make{{/returnType}}
|
||||
end
|
||||
{{/operation}}
|
||||
end
|
||||
end
|
||||
{{/operations}}
|
||||
end
|
||||
|
@ -1,83 +1,83 @@
|
||||
# base class containing fundamental method such as to_hash, build_from_hash and more
|
||||
class BaseObject
|
||||
module {{moduleName}}
|
||||
# base class containing fundamental method such as to_hash, build_from_hash and more
|
||||
class BaseObject
|
||||
|
||||
# return the object in the form of hash
|
||||
def to_body
|
||||
body = {}
|
||||
self.class.attribute_map.each_pair do |key, value|
|
||||
body[value] = self.send(key) unless self.send(key).nil?
|
||||
# return the object in the form of hash
|
||||
def to_body
|
||||
body = {}
|
||||
self.class.attribute_map.each_pair do |key, value|
|
||||
body[value] = self.send(key) unless self.send(key).nil?
|
||||
end
|
||||
body
|
||||
end
|
||||
body
|
||||
end
|
||||
|
||||
# build the object from hash
|
||||
def build_from_hash(attributes)
|
||||
return nil unless attributes.is_a?(Hash)
|
||||
self.class.swagger_types.each_pair do |key, type|
|
||||
if type =~ /^array\[(.*)\]/i
|
||||
if attributes[self.class.attribute_map[key]].is_a?(Array)
|
||||
self.send("#{key}=", attributes[self.class.attribute_map[key]].map{ |v| _deserialize($1, v) } )
|
||||
# build the object from hash
|
||||
def build_from_hash(attributes)
|
||||
return nil unless attributes.is_a?(Hash)
|
||||
self.class.swagger_types.each_pair do |key, type|
|
||||
if type =~ /^array\[(.*)\]/i
|
||||
if attributes[self.class.attribute_map[key]].is_a?(Array)
|
||||
self.send("#{key}=", attributes[self.class.attribute_map[key]].map{ |v| _deserialize($1, v) } )
|
||||
else
|
||||
#TODO show warning in debug mode
|
||||
end
|
||||
elsif !attributes[self.class.attribute_map[key]].nil?
|
||||
self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
|
||||
else
|
||||
#TODO show warning in debug mode
|
||||
end
|
||||
elsif !attributes[self.class.attribute_map[key]].nil?
|
||||
self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
|
||||
else
|
||||
# data not found in attributes(hash), not an issue as the data can be optional
|
||||
end
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def _deserialize(type, value)
|
||||
case type.to_sym
|
||||
when :DateTime
|
||||
DateTime.parse(value)
|
||||
when :string
|
||||
value.to_s
|
||||
when :int
|
||||
value.to_i
|
||||
when :double
|
||||
value.to_f
|
||||
when :boolean
|
||||
if value =~ /^(true|t|yes|y|1)$/i
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
else # model
|
||||
_model = Object.const_get(type).new
|
||||
_model.build_from_hash(value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# to_body is an alias to to_body (backward compatibility)
|
||||
def to_hash
|
||||
hash = {}
|
||||
self.class.attribute_map.each_pair do |key, value|
|
||||
if self.send(key).is_a?(Array)
|
||||
next if self.send(key).empty?
|
||||
hash[value] = self.send(key).select{|v| !v.nil?}.map{ |v| _to_hash v} unless self.send(key).nil?
|
||||
else
|
||||
unless (_tmp_value = _to_hash self.send(key)).nil?
|
||||
hash[value] = _tmp_value
|
||||
# data not found in attributes(hash), not an issue as the data can be optional
|
||||
end
|
||||
end
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
# Method to output non-array value in the form of hash
|
||||
# For object, use to_hash. Otherwise, just return the value
|
||||
def _to_hash(value)
|
||||
if value.respond_to? :to_hash
|
||||
value.to_hash
|
||||
else
|
||||
value
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
def _deserialize(type, value)
|
||||
case type.to_sym
|
||||
when :DateTime
|
||||
DateTime.parse(value)
|
||||
when :string
|
||||
value.to_s
|
||||
when :int
|
||||
value.to_i
|
||||
when :double
|
||||
value.to_f
|
||||
when :boolean
|
||||
if value =~ /^(true|t|yes|y|1)$/i
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
else # model
|
||||
_model = {{moduleName}}.const_get(type).new
|
||||
_model.build_from_hash(value)
|
||||
end
|
||||
end
|
||||
|
||||
# to_body is an alias to to_body (backward compatibility)
|
||||
def to_hash
|
||||
hash = {}
|
||||
self.class.attribute_map.each_pair do |key, value|
|
||||
if self.send(key).is_a?(Array)
|
||||
next if self.send(key).empty?
|
||||
hash[value] = self.send(key).select{|v| !v.nil?}.map{ |v| _to_hash v} unless self.send(key).nil?
|
||||
else
|
||||
unless (_tmp_value = _to_hash self.send(key)).nil?
|
||||
hash[value] = _tmp_value
|
||||
end
|
||||
end
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
# Method to output non-array value in the form of hash
|
||||
# For object, use to_hash. Otherwise, just return the value
|
||||
def _to_hash(value)
|
||||
if value.respond_to? :to_hash
|
||||
value.to_hash
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,41 +1,40 @@
|
||||
require_relative 'base_object'
|
||||
|
||||
{{#models}}#{{description}}
|
||||
{{#model}}class {{classname}} < BaseObject
|
||||
attr_accessor {{#vars}}:{{{name}}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{newline}}
|
||||
# attribute mapping from ruby-style variable name to JSON key
|
||||
def self.attribute_map
|
||||
{
|
||||
{{#vars}}
|
||||
# {{description}}
|
||||
:'{{{name}}}' => :'{{{baseName}}}'{{#hasMore}},{{/hasMore}}
|
||||
{{/vars}}
|
||||
}
|
||||
end
|
||||
|
||||
# attribute type
|
||||
def self.swagger_types
|
||||
{
|
||||
{{#vars}}:'{{{name}}}' => :'{{{datatype}}}'{{#hasMore}},{{/hasMore}}
|
||||
{{/vars}}
|
||||
}
|
||||
end
|
||||
|
||||
def initialize(attributes = {})
|
||||
return if !attributes.is_a?(Hash) || attributes.empty?
|
||||
|
||||
# convert string to symbol for hash key
|
||||
attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
||||
|
||||
{{#vars}}
|
||||
if attributes[:'{{{baseName}}}']
|
||||
{{#isContainer}}if (value = attributes[:'{{{baseName}}}']).is_a?(Array)
|
||||
@{{{name}}} = value
|
||||
end{{/isContainer}}{{^isContainer}}@{{{name}}} = attributes[:'{{{baseName}}}']{{/isContainer}}
|
||||
module {{moduleName}}
|
||||
{{#models}} # {{description}}
|
||||
{{#model}} class {{classname}} < BaseObject
|
||||
attr_accessor {{#vars}}:{{{name}}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{newline}}
|
||||
# attribute mapping from ruby-style variable name to JSON key
|
||||
def self.attribute_map
|
||||
{
|
||||
{{#vars}}
|
||||
# {{description}}
|
||||
:'{{{name}}}' => :'{{{baseName}}}'{{#hasMore}},{{/hasMore}}
|
||||
{{/vars}}
|
||||
}
|
||||
end
|
||||
{{/vars}}
|
||||
end
|
||||
|
||||
end
|
||||
# attribute type
|
||||
def self.swagger_types
|
||||
{
|
||||
{{#vars}}:'{{{name}}}' => :'{{{datatype}}}'{{#hasMore}},{{/hasMore}}
|
||||
{{/vars}}
|
||||
}
|
||||
end
|
||||
|
||||
def initialize(attributes = {})
|
||||
return if !attributes.is_a?(Hash) || attributes.empty?
|
||||
|
||||
# convert string to symbol for hash key
|
||||
attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
||||
|
||||
{{#vars}}
|
||||
if attributes[:'{{{baseName}}}']
|
||||
{{#isContainer}}if (value = attributes[:'{{{baseName}}}']).is_a?(Array)
|
||||
@{{{name}}} = value
|
||||
end{{/isContainer}}{{^isContainer}}@{{{name}}} = attributes[:'{{{baseName}}}']{{/isContainer}}
|
||||
end
|
||||
{{/vars}}
|
||||
end
|
||||
end
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
end
|
||||
|
@ -1,33 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
$:.push File.expand_path("../lib", __FILE__)
|
||||
require "swagger/version"
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "{{artifactId}}"
|
||||
s.version = Swagger::VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.authors = ["Zeke Sikelianos", "Tony Tam"]
|
||||
s.email = ["zeke@wordnik.com", "tony@wordnik.com"]
|
||||
s.homepage = "http://developer.wordnik.com"
|
||||
s.summary = %q{A ruby wrapper for the swagger APIs}
|
||||
s.description = %q{This gem maps to a swagger API}
|
||||
|
||||
s.rubyforge_project = "{{artifactId}}"
|
||||
|
||||
s.add_dependency 'typhoeus', '>=0.2.1'
|
||||
s.add_dependency 'addressable', '>=2.2.4'
|
||||
s.add_dependency 'json', '>=1.4.6'
|
||||
|
||||
s.add_development_dependency 'rspec', '>=2.5.0'
|
||||
s.add_development_dependency 'vcr', '>=1.5.1'
|
||||
s.add_development_dependency 'webmock', '>=1.6.2'
|
||||
s.add_development_dependency 'autotest'
|
||||
s.add_development_dependency 'autotest-rails-pure'
|
||||
s.add_development_dependency 'autotest-growl'
|
||||
s.add_development_dependency 'autotest-fsevent'
|
||||
|
||||
s.files = `find *`.split("\n").uniq.sort.select{|f| !f.empty? }
|
||||
s.test_files = `find spec/*`.split("\n")
|
||||
s.executables = []
|
||||
s.require_paths = ["lib"]
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
require 'monkey'
|
||||
require 'swagger'
|
||||
|
||||
Dir[File.join(File.dirname(__FILE__), "../lib/*.rb")].each {|file| require file if file !~ /swagger-client\.rb\z/ }
|
||||
Dir[File.join(File.dirname(__FILE__), "../models/*.rb")].each {|file| require file }
|
@ -1,86 +1,78 @@
|
||||
require 'monkey'
|
||||
require 'swagger/configuration'
|
||||
require 'swagger/request'
|
||||
require 'swagger/response'
|
||||
require 'swagger/version'
|
||||
require 'logger'
|
||||
require 'json'
|
||||
|
||||
module Swagger
|
||||
|
||||
@configuration = Configuration.new
|
||||
module {{moduleName}}
|
||||
module Swagger
|
||||
class << self
|
||||
attr_accessor :logger
|
||||
|
||||
class << self
|
||||
attr_accessor :logger
|
||||
|
||||
# A Swagger configuration object. Must act like a hash and return sensible
|
||||
# values for all Swagger configuration options. See Swagger::Configuration.
|
||||
attr_accessor :configuration
|
||||
# A Swagger configuration object. Must act like a hash and return sensible
|
||||
# values for all Swagger configuration options. See Swagger::Configuration.
|
||||
attr_accessor :configuration
|
||||
|
||||
attr_accessor :resources
|
||||
|
||||
# Call this method to modify defaults in your initializers.
|
||||
#
|
||||
# @example
|
||||
# Swagger.configure do |config|
|
||||
# config.api_key = '1234567890abcdef' # required
|
||||
# config.username = 'wordlover' # optional, but needed for user-related functions
|
||||
# config.password = 'i<3words' # optional, but needed for user-related functions
|
||||
# config.format = 'json' # optional, defaults to 'json'
|
||||
# end
|
||||
#
|
||||
def configure
|
||||
yield(configuration) if block_given?
|
||||
attr_accessor :resources
|
||||
|
||||
# Configure logger. Default to use Rails
|
||||
self.logger ||= configuration.logger || (defined?(Rails) ? Rails.logger : Logger.new(STDOUT))
|
||||
# Call this method to modify defaults in your initializers.
|
||||
#
|
||||
# @example
|
||||
# Swagger.configure do |config|
|
||||
# config.api_key = '1234567890abcdef' # required
|
||||
# config.username = 'wordlover' # optional, but needed for user-related functions
|
||||
# config.password = 'i<3words' # optional, but needed for user-related functions
|
||||
# config.format = 'json' # optional, defaults to 'json'
|
||||
# end
|
||||
#
|
||||
def configure
|
||||
yield(configuration) if block_given?
|
||||
|
||||
# remove :// from scheme
|
||||
configuration.scheme.sub!(/:\/\//, '')
|
||||
# Configure logger. Default to use Rails
|
||||
self.logger ||= configuration.logger || (defined?(Rails) ? Rails.logger : Logger.new(STDOUT))
|
||||
|
||||
# remove http(s):// and anything after a slash
|
||||
configuration.host.sub!(/https?:\/\//, '')
|
||||
configuration.host = configuration.host.split('/').first
|
||||
# remove :// from scheme
|
||||
configuration.scheme.sub!(/:\/\//, '')
|
||||
|
||||
# Add leading and trailing slashes to base_path
|
||||
configuration.base_path = "/#{configuration.base_path}".gsub(/\/+/, '/')
|
||||
configuration.base_path = "" if configuration.base_path == "/"
|
||||
end
|
||||
|
||||
def authenticated?
|
||||
Swagger.configuration.auth_token.present?
|
||||
end
|
||||
|
||||
def de_authenticate
|
||||
Swagger.configuration.auth_token = nil
|
||||
end
|
||||
|
||||
def authenticate
|
||||
return if Swagger.authenticated?
|
||||
|
||||
if Swagger.configuration.username.blank? || Swagger.configuration.password.blank?
|
||||
raise ClientError, "Username and password are required to authenticate."
|
||||
# remove http(s):// and anything after a slash
|
||||
configuration.host.sub!(/https?:\/\//, '')
|
||||
configuration.host = configuration.host.split('/').first
|
||||
|
||||
# Add leading and trailing slashes to base_path
|
||||
configuration.base_path = "/#{configuration.base_path}".gsub(/\/+/, '/')
|
||||
configuration.base_path = "" if configuration.base_path == "/"
|
||||
end
|
||||
|
||||
def authenticated?
|
||||
Swagger.configuration.auth_token.present?
|
||||
end
|
||||
|
||||
def de_authenticate
|
||||
Swagger.configuration.auth_token = nil
|
||||
end
|
||||
|
||||
def authenticate
|
||||
return if Swagger.authenticated?
|
||||
|
||||
if Swagger.configuration.username.blank? || Swagger.configuration.password.blank?
|
||||
raise ClientError, "Username and password are required to authenticate."
|
||||
end
|
||||
|
||||
request = Swagger::Request.new(
|
||||
:get,
|
||||
"account/authenticate/{username}",
|
||||
:params => {
|
||||
:username => Swagger.configuration.username,
|
||||
:password => Swagger.configuration.password
|
||||
}
|
||||
)
|
||||
|
||||
response_body = request.response.body
|
||||
Swagger.configuration.auth_token = response_body['token']
|
||||
end
|
||||
|
||||
request = Swagger::Request.new(
|
||||
:get,
|
||||
"account/authenticate/{username}",
|
||||
:params => {
|
||||
:username => Swagger.configuration.username,
|
||||
:password => Swagger.configuration.password
|
||||
}
|
||||
)
|
||||
|
||||
response_body = request.response.body
|
||||
Swagger.configuration.auth_token = response_body['token']
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class ServerError < StandardError
|
||||
end
|
||||
class ServerError < StandardError
|
||||
end
|
||||
|
||||
class ClientError < StandardError
|
||||
class ClientError < StandardError
|
||||
end
|
||||
end
|
||||
|
@ -1,22 +1,19 @@
|
||||
module Swagger
|
||||
|
||||
class Configuration
|
||||
require 'swagger/version'
|
||||
module {{moduleName}}
|
||||
module Swagger
|
||||
class Configuration
|
||||
attr_accessor :format, :api_key, :username, :password, :auth_token, :scheme, :host, :base_path, :user_agent, :logger, :inject_format, :force_ending_format, :camelize_params, :user_agent
|
||||
|
||||
attr_accessor :format, :api_key, :username, :password, :auth_token, :scheme, :host, :base_path, :user_agent, :logger, :inject_format, :force_ending_format, :camelize_params, :user_agent
|
||||
|
||||
# Defaults go in here..
|
||||
def initialize
|
||||
@format = 'json'
|
||||
@scheme = '{{scheme}}'
|
||||
@host = '{{host}}'
|
||||
@base_path = '{{contextPath}}'
|
||||
@user_agent = "ruby-swagger-#{Swagger::VERSION}"
|
||||
@inject_format = false
|
||||
@force_ending_format = false
|
||||
@camelize_params = true
|
||||
# Defaults go in here..
|
||||
def initialize
|
||||
@format = 'json'
|
||||
@scheme = '{{scheme}}'
|
||||
@host = '{{host}}'
|
||||
@base_path = '{{contextPath}}'
|
||||
@user_agent = "ruby-swagger-#{Swagger::VERSION}"
|
||||
@inject_format = false
|
||||
@force_ending_format = false
|
||||
@camelize_params = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,263 +1,257 @@
|
||||
module Swagger
|
||||
module {{moduleName}}
|
||||
module Swagger
|
||||
class Request
|
||||
require 'uri'
|
||||
require 'addressable/uri'
|
||||
require 'typhoeus'
|
||||
|
||||
class Request
|
||||
require 'uri'
|
||||
require 'addressable/uri'
|
||||
require 'typhoeus'
|
||||
require "swagger/version"
|
||||
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers, :form_params
|
||||
|
||||
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers, :form_params
|
||||
# All requests must have an HTTP method and a path
|
||||
# Optionals parameters are :params, :headers, :body, :format, :host
|
||||
def initialize(http_method, path, attributes={})
|
||||
attributes[:format] ||= Swagger.configuration.format
|
||||
attributes[:params] ||= {}
|
||||
|
||||
# Set default headers
|
||||
default_headers = {
|
||||
'Content-Type' => "application/#{attributes[:format].downcase}",
|
||||
:api_key => Swagger.configuration.api_key,
|
||||
'User-Agent' => Swagger.configuration.user_agent
|
||||
}
|
||||
|
||||
# All requests must have an HTTP method and a path
|
||||
# Optionals parameters are :params, :headers, :body, :format, :host
|
||||
#
|
||||
def initialize(http_method, path, attributes={})
|
||||
attributes[:format] ||= Swagger.configuration.format
|
||||
attributes[:params] ||= {}
|
||||
# api_key from headers hash trumps the default, even if its value is blank
|
||||
if attributes[:headers].present? && attributes[:headers].has_key?(:api_key)
|
||||
default_headers.delete(:api_key)
|
||||
end
|
||||
|
||||
# Set default headers
|
||||
default_headers = {
|
||||
'Content-Type' => "application/#{attributes[:format].downcase}",
|
||||
:api_key => Swagger.configuration.api_key,
|
||||
'User-Agent' => Swagger.configuration.user_agent
|
||||
}
|
||||
# api_key from params hash trumps all others (headers and default_headers)
|
||||
if attributes[:params].present? && attributes[:params].has_key?(:api_key)
|
||||
default_headers.delete(:api_key)
|
||||
attributes[:headers].delete(:api_key) if attributes[:headers].present?
|
||||
end
|
||||
|
||||
# api_key from headers hash trumps the default, even if its value is blank
|
||||
if attributes[:headers].present? && attributes[:headers].has_key?(:api_key)
|
||||
default_headers.delete(:api_key)
|
||||
end
|
||||
|
||||
# api_key from params hash trumps all others (headers and default_headers)
|
||||
if attributes[:params].present? && attributes[:params].has_key?(:api_key)
|
||||
default_headers.delete(:api_key)
|
||||
attributes[:headers].delete(:api_key) if attributes[:headers].present?
|
||||
end
|
||||
|
||||
# Merge argument headers into defaults
|
||||
attributes[:headers] = default_headers.merge(attributes[:headers] || {})
|
||||
|
||||
# Stick in the auth token if there is one
|
||||
if Swagger.authenticated?
|
||||
attributes[:headers].merge!({:auth_token => Swagger.configuration.auth_token})
|
||||
end
|
||||
|
||||
self.http_method = http_method.to_sym
|
||||
self.path = path
|
||||
attributes.each do |name, value|
|
||||
send("#{name.to_s.underscore.to_sym}=", value)
|
||||
end
|
||||
end
|
||||
# Merge argument headers into defaults
|
||||
attributes[:headers] = default_headers.merge(attributes[:headers] || {})
|
||||
|
||||
# Construct a base URL
|
||||
#
|
||||
def url(options = {})
|
||||
u = Addressable::URI.new(
|
||||
:scheme => Swagger.configuration.scheme,
|
||||
:host => Swagger.configuration.host,
|
||||
:path => self.interpreted_path,
|
||||
:query => self.query_string.sub(/\?/, '')
|
||||
).to_s
|
||||
|
||||
# Drop trailing question mark, if present
|
||||
u.sub! /\?$/, ''
|
||||
|
||||
# Obfuscate API key?
|
||||
u.sub! /api\_key=\w+/, 'api_key=YOUR_API_KEY' if options[:obfuscated]
|
||||
|
||||
u
|
||||
end
|
||||
# Stick in the auth token if there is one
|
||||
if Swagger.authenticated?
|
||||
attributes[:headers].merge!({:auth_token => Swagger.configuration.auth_token})
|
||||
end
|
||||
|
||||
# Iterate over the params hash, injecting any path values into the path string
|
||||
#
|
||||
# e.g. /word.{format}/{word}/entries => /word.json/cat/entries
|
||||
def interpreted_path
|
||||
p = self.path.dup
|
||||
|
||||
# Stick a .{format} placeholder into the path if there isn't
|
||||
# one already or an actual format like json or xml
|
||||
# e.g. /words/blah => /words.{format}/blah
|
||||
if Swagger.configuration.inject_format
|
||||
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
|
||||
p = p.sub(/^(\/?\w+)/, "\\1.#{format}")
|
||||
self.http_method = http_method.to_sym
|
||||
self.path = path
|
||||
attributes.each do |name, value|
|
||||
send("#{name.to_s.underscore.to_sym}=", value)
|
||||
end
|
||||
end
|
||||
|
||||
# Stick a .{format} placeholder on the end of the path if there isn't
|
||||
# one already or an actual format like json or xml
|
||||
# e.g. /words/blah => /words/blah.{format}
|
||||
if Swagger.configuration.force_ending_format
|
||||
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
|
||||
p = "#{p}.#{format}"
|
||||
# Construct a base URL
|
||||
def url(options = {})
|
||||
u = Addressable::URI.new(
|
||||
:scheme => Swagger.configuration.scheme,
|
||||
:host => Swagger.configuration.host,
|
||||
:path => self.interpreted_path,
|
||||
:query => self.query_string.sub(/\?/, '')
|
||||
).to_s
|
||||
|
||||
# Drop trailing question mark, if present
|
||||
u.sub! /\?$/, ''
|
||||
|
||||
# Obfuscate API key?
|
||||
u.sub! /api\_key=\w+/, 'api_key=YOUR_API_KEY' if options[:obfuscated]
|
||||
|
||||
u
|
||||
end
|
||||
|
||||
# Iterate over the params hash, injecting any path values into the path string
|
||||
# e.g. /word.{format}/{word}/entries => /word.json/cat/entries
|
||||
def interpreted_path
|
||||
p = self.path.dup
|
||||
|
||||
# Stick a .{format} placeholder into the path if there isn't
|
||||
# one already or an actual format like json or xml
|
||||
# e.g. /words/blah => /words.{format}/blah
|
||||
if Swagger.configuration.inject_format
|
||||
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
|
||||
p = p.sub(/^(\/?\w+)/, "\\1.#{format}")
|
||||
end
|
||||
end
|
||||
|
||||
# Stick a .{format} placeholder on the end of the path if there isn't
|
||||
# one already or an actual format like json or xml
|
||||
# e.g. /words/blah => /words/blah.{format}
|
||||
if Swagger.configuration.force_ending_format
|
||||
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
|
||||
p = "#{p}.#{format}"
|
||||
end
|
||||
end
|
||||
|
||||
p = p.sub("{format}", self.format.to_s)
|
||||
|
||||
URI.encode [Swagger.configuration.base_path, p].join("/").gsub(/\/+/, '/')
|
||||
end
|
||||
|
||||
# Massage the request body into a state of readiness
|
||||
# If body is a hash, camelize all keys then convert to a json string
|
||||
def body=(value)
|
||||
if value.is_a?(Hash)
|
||||
value = value.inject({}) do |memo, (k,v)|
|
||||
memo[k.to_s.camelize(:lower).to_sym] = v
|
||||
memo
|
||||
end
|
||||
end
|
||||
@body = value
|
||||
end
|
||||
|
||||
# If body is an object, JSONify it before making the actual request.
|
||||
# For form parameters, remove empty value
|
||||
def outgoing_body
|
||||
# http form
|
||||
if @body.nil? && @form_params && !@form_params.empty?
|
||||
data = form_params.dup
|
||||
data.each do |key, value|
|
||||
data[key] = value.to_s if value && !value.is_a?(File) # remove emtpy form parameter
|
||||
end
|
||||
data
|
||||
else # http body is JSON
|
||||
@body.is_a?(String) ? @body : @body.to_json
|
||||
end
|
||||
end
|
||||
|
||||
p = p.sub("{format}", self.format.to_s)
|
||||
|
||||
URI.encode [Swagger.configuration.base_path, p].join("/").gsub(/\/+/, '/')
|
||||
end
|
||||
|
||||
# Massage the request body into a state of readiness
|
||||
# If body is a hash, camelize all keys then convert to a json string
|
||||
#
|
||||
def body=(value)
|
||||
if value.is_a?(Hash)
|
||||
value = value.inject({}) do |memo, (k,v)|
|
||||
memo[k.to_s.camelize(:lower).to_sym] = v
|
||||
memo
|
||||
# Construct a query string from the query-string-type params
|
||||
def query_string
|
||||
# Iterate over all params,
|
||||
# .. removing the ones that are part of the path itself.
|
||||
# .. stringifying values so Addressable doesn't blow up.
|
||||
query_values = {}
|
||||
self.params.each_pair do |key, value|
|
||||
next if self.path.include? "{#{key}}" # skip path params
|
||||
next if value.blank? && value.class != FalseClass # skip empties
|
||||
if Swagger.configuration.camelize_params
|
||||
key = key.to_s.camelize(:lower).to_sym unless key.to_sym == :api_key # api_key is not a camelCased param
|
||||
end
|
||||
query_values[key] = value.to_s
|
||||
end
|
||||
|
||||
# We don't want to end up with '?' as our query string
|
||||
# if there aren't really any params
|
||||
return "" if query_values.blank?
|
||||
|
||||
# Addressable requires query_values to be set after initialization..
|
||||
qs = Addressable::URI.new
|
||||
qs.query_values = query_values
|
||||
qs.to_s
|
||||
end
|
||||
|
||||
def make
|
||||
#TODO use configuration setting to determine if debugging
|
||||
#logger = Logger.new STDOUT
|
||||
#logger.debug self.url
|
||||
response = case self.http_method.to_sym
|
||||
when :get,:GET
|
||||
Typhoeus::Request.get(
|
||||
self.url,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :post,:POST
|
||||
Typhoeus::Request.post(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :patch,:PATCH
|
||||
Typhoeus::Request.patch(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :put,:PUT
|
||||
Typhoeus::Request.put(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :delete,:DELETE
|
||||
Typhoeus::Request.delete(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
end
|
||||
Response.new(response)
|
||||
end
|
||||
|
||||
def response
|
||||
self.make
|
||||
end
|
||||
|
||||
def response_code_pretty
|
||||
return unless @response.present?
|
||||
@response.code.to_s
|
||||
end
|
||||
|
||||
def response_headers_pretty
|
||||
return unless @response.present?
|
||||
# JSON.pretty_generate(@response.headers).gsub(/\n/, '<br/>') # <- This was for RestClient
|
||||
@response.headers.gsub(/\n/, '<br/>') # <- This is for Typhoeus
|
||||
end
|
||||
|
||||
# return 'Accept' based on an array of accept provided
|
||||
# @param [Array] header_accept_array Array fo 'Accept'
|
||||
# @return String Accept (e.g. application/json)
|
||||
def self.select_header_accept header_accept_array
|
||||
if header_accept_array.empty?
|
||||
return
|
||||
elsif header_accept_array.any?{ |s| s.casecmp('application/json')==0 }
|
||||
'application/json' # look for json data by default
|
||||
else
|
||||
header_accept_array.join(',')
|
||||
end
|
||||
end
|
||||
@body = value
|
||||
end
|
||||
|
||||
# If body is an object, JSONify it before making the actual request.
|
||||
# For form parameters, remove empty value
|
||||
def outgoing_body
|
||||
# http form
|
||||
if @body.nil? && @form_params && !@form_params.empty?
|
||||
data = form_params.dup
|
||||
data.each do |key, value|
|
||||
data[key] = value.to_s if value && !value.is_a?(File) # remove emtpy form parameter
|
||||
|
||||
# return the content type based on an array of content-type provided
|
||||
# @param [Array] content_type_array Array fo content-type
|
||||
# @return String Content-Type (e.g. application/json)
|
||||
def self.select_header_content_type content_type_array
|
||||
if content_type_array.empty?
|
||||
'application/json' # use application/json by default
|
||||
elsif content_type_array.any?{ |s| s.casecmp('application/json')==0 }
|
||||
'application/json' # use application/json if it's included
|
||||
else
|
||||
content_type_array[0]; # otherwise, use the first one
|
||||
end
|
||||
data
|
||||
else # http body is JSON
|
||||
@body.is_a?(String) ? @body : @body.to_json
|
||||
end
|
||||
end
|
||||
|
||||
# Construct a query string from the query-string-type params
|
||||
def query_string
|
||||
|
||||
# Iterate over all params,
|
||||
# .. removing the ones that are part of the path itself.
|
||||
# .. stringifying values so Addressable doesn't blow up.
|
||||
query_values = {}
|
||||
self.params.each_pair do |key, value|
|
||||
next if self.path.include? "{#{key}}" # skip path params
|
||||
next if value.blank? && value.class != FalseClass # skip empties
|
||||
if Swagger.configuration.camelize_params
|
||||
key = key.to_s.camelize(:lower).to_sym unless key.to_sym == :api_key # api_key is not a camelCased param
|
||||
# static method to convert object (array, hash, object, etc) to JSON string
|
||||
# @param model object to be converted into JSON string
|
||||
# @return string JSON string representation of the object
|
||||
def self.object_to_http_body model
|
||||
return if model.nil?
|
||||
_body = nil
|
||||
if model.is_a?(Array)
|
||||
_body = model.map{|m| object_to_hash(m) }
|
||||
else
|
||||
_body = object_to_hash(model)
|
||||
end
|
||||
query_values[key] = value.to_s
|
||||
_body.to_json
|
||||
end
|
||||
|
||||
# We don't want to end up with '?' as our query string
|
||||
# if there aren't really any params
|
||||
return "" if query_values.blank?
|
||||
|
||||
# Addressable requires query_values to be set after initialization..
|
||||
qs = Addressable::URI.new
|
||||
qs.query_values = query_values
|
||||
qs.to_s
|
||||
end
|
||||
|
||||
def make
|
||||
#TODO use configuration setting to determine if debugging
|
||||
#logger = Logger.new STDOUT
|
||||
#logger.debug self.url
|
||||
response = case self.http_method.to_sym
|
||||
when :get,:GET
|
||||
Typhoeus::Request.get(
|
||||
self.url,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :post,:POST
|
||||
Typhoeus::Request.post(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :patch,:PATCH
|
||||
Typhoeus::Request.patch(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :put,:PUT
|
||||
Typhoeus::Request.put(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
|
||||
when :delete,:DELETE
|
||||
Typhoeus::Request.delete(
|
||||
self.url,
|
||||
:body => self.outgoing_body,
|
||||
:headers => self.headers.stringify_keys,
|
||||
)
|
||||
# static method to convert object(non-array) to hash
|
||||
# @param obj object to be converted into JSON string
|
||||
# @return string JSON string representation of the object
|
||||
def self.object_to_hash obj
|
||||
if obj.respond_to?(:to_hash)
|
||||
obj.to_hash
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
Response.new(response)
|
||||
end
|
||||
|
||||
def response
|
||||
self.make
|
||||
end
|
||||
|
||||
def response_code_pretty
|
||||
return unless @response.present?
|
||||
@response.code.to_s
|
||||
end
|
||||
|
||||
def response_headers_pretty
|
||||
return unless @response.present?
|
||||
# JSON.pretty_generate(@response.headers).gsub(/\n/, '<br/>') # <- This was for RestClient
|
||||
@response.headers.gsub(/\n/, '<br/>') # <- This is for Typhoeus
|
||||
end
|
||||
|
||||
# return 'Accept' based on an array of accept provided
|
||||
# @param [Array] header_accept_array Array fo 'Accept'
|
||||
# @return String Accept (e.g. application/json)
|
||||
def self.select_header_accept header_accept_array
|
||||
if header_accept_array.empty?
|
||||
return
|
||||
elsif header_accept_array.any?{ |s| s.casecmp('application/json')==0 }
|
||||
'application/json' # look for json data by default
|
||||
else
|
||||
header_accept_array.join(',')
|
||||
end
|
||||
end
|
||||
|
||||
# return the content type based on an array of content-type provided
|
||||
# @param [Array] content_type_array Array fo content-type
|
||||
# @return String Content-Type (e.g. application/json)
|
||||
def self.select_header_content_type content_type_array
|
||||
if content_type_array.empty?
|
||||
'application/json' # use application/json by default
|
||||
elsif content_type_array.any?{ |s| s.casecmp('application/json')==0 }
|
||||
'application/json' # use application/json if it's included
|
||||
else
|
||||
content_type_array[0]; # otherwise, use the first one
|
||||
end
|
||||
end
|
||||
|
||||
# static method to convert object (array, hash, object, etc) to JSON string
|
||||
# @param model object to be converted into JSON string
|
||||
# @return string JSON string representation of the object
|
||||
def self.object_to_http_body model
|
||||
return if model.nil?
|
||||
_body = nil
|
||||
if model.is_a?(Array)
|
||||
_body = model.map{|m| object_to_hash(m) }
|
||||
else
|
||||
_body = object_to_hash(model)
|
||||
end
|
||||
_body.to_json
|
||||
end
|
||||
|
||||
# static method to convert object(non-array) to hash
|
||||
# @param obj object to be converted into JSON string
|
||||
# @return string JSON string representation of the object
|
||||
def self.object_to_hash obj
|
||||
if obj.respond_to?(:to_hash)
|
||||
obj.to_hash
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,70 +1,70 @@
|
||||
module Swagger
|
||||
module {{moduleName}}
|
||||
module Swagger
|
||||
class Response
|
||||
require 'json'
|
||||
|
||||
class Response
|
||||
require 'json'
|
||||
attr_accessor :raw
|
||||
|
||||
attr_accessor :raw
|
||||
def initialize(raw)
|
||||
self.raw = raw
|
||||
|
||||
def initialize(raw)
|
||||
self.raw = raw
|
||||
case self.code
|
||||
when 500..510 then raise(ServerError, self.error_message)
|
||||
when 299..426 then raise(ClientError, self.error_message)
|
||||
end
|
||||
end
|
||||
|
||||
case self.code
|
||||
when 500..510 then raise(ServerError, self.error_message)
|
||||
when 299..426 then raise(ClientError, self.error_message)
|
||||
def code
|
||||
raw.code
|
||||
end
|
||||
|
||||
# Account for error messages that take different forms...
|
||||
def error_message
|
||||
body['message']
|
||||
rescue
|
||||
body
|
||||
end
|
||||
|
||||
# If body is JSON, parse it
|
||||
# Otherwise return raw string
|
||||
def body
|
||||
JSON.parse(raw.body, :symbolize_names => true)
|
||||
rescue
|
||||
raw.body
|
||||
end
|
||||
|
||||
# `headers_hash` is a Typhoeus-specific extension of Hash,
|
||||
# so simplify it back into a regular old Hash.
|
||||
def headers
|
||||
h = {}
|
||||
raw.headers_hash.each {|k,v| h[k] = v }
|
||||
h
|
||||
end
|
||||
|
||||
# Extract the response format from the header hash
|
||||
# e.g. {'Content-Type' => 'application/json'}
|
||||
def format
|
||||
headers['Content-Type'].split("/").last.downcase
|
||||
end
|
||||
|
||||
def json?
|
||||
format == 'json'
|
||||
end
|
||||
|
||||
def xml?
|
||||
format == 'xml'
|
||||
end
|
||||
|
||||
def pretty_body
|
||||
return unless body.present?
|
||||
case format
|
||||
when 'json' then JSON.pretty_generate(body).gsub(/\n/, '<br/>')
|
||||
end
|
||||
end
|
||||
|
||||
def pretty_headers
|
||||
JSON.pretty_generate(headers).gsub(/\n/, '<br/>')
|
||||
end
|
||||
end
|
||||
|
||||
def code
|
||||
raw.code
|
||||
end
|
||||
|
||||
# Account for error messages that take different forms...
|
||||
def error_message
|
||||
body['message']
|
||||
rescue
|
||||
body
|
||||
end
|
||||
|
||||
# If body is JSON, parse it
|
||||
# Otherwise return raw string
|
||||
def body
|
||||
JSON.parse(raw.body, :symbolize_names => true)
|
||||
rescue
|
||||
raw.body
|
||||
end
|
||||
|
||||
# `headers_hash` is a Typhoeus-specific extension of Hash,
|
||||
# so simplify it back into a regular old Hash.
|
||||
def headers
|
||||
h = {}
|
||||
raw.headers_hash.each {|k,v| h[k] = v }
|
||||
h
|
||||
end
|
||||
|
||||
# Extract the response format from the header hash
|
||||
# e.g. {'Content-Type' => 'application/json'}
|
||||
def format
|
||||
headers['Content-Type'].split("/").last.downcase
|
||||
end
|
||||
|
||||
def json?
|
||||
format == 'json'
|
||||
end
|
||||
|
||||
def xml?
|
||||
format == 'xml'
|
||||
end
|
||||
|
||||
def pretty_body
|
||||
return unless body.present?
|
||||
case format
|
||||
when 'json' then JSON.pretty_generate(body).gsub(/\n/, '<br/>')
|
||||
end
|
||||
end
|
||||
|
||||
def pretty_headers
|
||||
JSON.pretty_generate(headers).gsub(/\n/, '<br/>')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,5 @@
|
||||
module Swagger
|
||||
VERSION = "4.06.08"
|
||||
module {{moduleName}}
|
||||
module Swagger
|
||||
VERSION = "{{appVersion}}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
$:.push File.expand_path("../lib", __FILE__)
|
||||
require "{{gemName}}/swagger/version"
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "{{gemName}}"
|
||||
s.version = {{moduleName}}::Swagger::VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.authors = ["Zeke Sikelianos", "Tony Tam"]
|
||||
s.email = ["zeke@wordnik.com", "tony@wordnik.com"]
|
||||
s.homepage = "http://developer.wordnik.com"
|
||||
s.summary = %q{A ruby wrapper for the swagger APIs}
|
||||
s.description = %q{This gem maps to a swagger API}
|
||||
s.license = "Apache-2.0"
|
||||
|
||||
s.add_runtime_dependency 'typhoeus', '~> 0.2', '>= 0.2.1'
|
||||
s.add_runtime_dependency 'addressable', '~> 2.2', '>= 2.2.4'
|
||||
s.add_runtime_dependency 'json', '~> 1.4', '>= 1.4.6'
|
||||
|
||||
s.add_development_dependency 'rspec', '~> 3.2', '>= 3.2.0'
|
||||
s.add_development_dependency 'vcr', '~> 2.9', '>= 2.9.3'
|
||||
s.add_development_dependency 'webmock', '~> 1.6', '>= 1.6.2'
|
||||
s.add_development_dependency 'autotest', '~> 4.4', '>= 4.4.6'
|
||||
s.add_development_dependency 'autotest-rails-pure', '~> 4.1', '>= 4.1.2'
|
||||
s.add_development_dependency 'autotest-growl', '~> 0.2', '>= 0.2.16'
|
||||
s.add_development_dependency 'autotest-fsevent', '~> 0.2', '>= 0.2.10'
|
||||
|
||||
s.files = `find *`.split("\n").uniq.sort.select{|f| !f.empty? }
|
||||
s.test_files = `find spec/*`.split("\n")
|
||||
s.executables = []
|
||||
s.require_paths = ["lib"]
|
||||
end
|
@ -0,0 +1,25 @@
|
||||
# Swagger common files
|
||||
require '{{gemName}}/monkey'
|
||||
require '{{gemName}}/swagger'
|
||||
require '{{gemName}}/swagger/configuration'
|
||||
require '{{gemName}}/swagger/request'
|
||||
require '{{gemName}}/swagger/response'
|
||||
require '{{gemName}}/swagger/version'
|
||||
|
||||
# Models
|
||||
require '{{modelPackage}}/base_object'
|
||||
{{#models}}
|
||||
require '{{importPath}}'
|
||||
{{/models}}
|
||||
|
||||
# APIs
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
require '{{importPath}}'
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
module {{moduleName}}
|
||||
# Initialize the default configuration
|
||||
Swagger.configuration ||= Swagger::Configuration.new
|
||||
end
|
@ -720,6 +720,18 @@
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/User"
|
||||
},
|
||||
"examples": {
|
||||
"application/json": {
|
||||
"id": 1,
|
||||
"username": "johnp",
|
||||
"firstName": "John",
|
||||
"lastName": "Public",
|
||||
"email": "johnp@swagger.io",
|
||||
"password": "-secret-",
|
||||
"phone": "0123456789",
|
||||
"userStatus": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
|
@ -0,0 +1,93 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is a sample server Petstore server. You can find out more about Swagger at <a href=\"http://swagger.io\">http://swagger.io</a> or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters",
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore",
|
||||
"termsOfService": "http://helloreverb.com/terms/",
|
||||
"contact": {
|
||||
"email": "apiteam@wordnik.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
}
|
||||
},
|
||||
"host": "petstore.swagger.io",
|
||||
"basePath": "/v2",
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"paths": {
|
||||
"/tests/requiredParams": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"tests"
|
||||
],
|
||||
"summary": "Operation with required parameters",
|
||||
"description": "",
|
||||
"operationId": "requiredParams",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "param1",
|
||||
"in": "formData",
|
||||
"description": "Some required parameter",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
{
|
||||
"name": "param2",
|
||||
"in": "formData",
|
||||
"description": "Some optional parameter",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation. Retuning a simple int.",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"api_key": {
|
||||
"type": "apiKey",
|
||||
"name": "api_key",
|
||||
"in": "header"
|
||||
},
|
||||
"petstore_auth": {
|
||||
"type": "oauth2",
|
||||
"authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog",
|
||||
"flow": "implicit",
|
||||
"scopes": {
|
||||
"write:pets": "modify pets in your account",
|
||||
"read:pets": "read your pets"
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"CustomModel": {
|
||||
"required": ["id"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "doggie"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
316
modules/swagger-codegen/src/test/resources/2_0/v1beta3.json
Normal file
316
modules/swagger-codegen/src/test/resources/2_0/v1beta3.json
Normal file
@ -0,0 +1,316 @@
|
||||
{
|
||||
"swaggerVersion": "1.2",
|
||||
"apiVersion": "v1beta3",
|
||||
"basePath": "https://127.0.0.1:6443",
|
||||
"resourcePath": "/api/v1beta3",
|
||||
"apis": [
|
||||
{
|
||||
"path": "/api/v1beta3/namespaces/{namespaces}/bindings",
|
||||
"description": "API at /api/v1beta3 version v1beta3",
|
||||
"operations": [
|
||||
{
|
||||
"type": "v1beta3.Binding",
|
||||
"method": "POST",
|
||||
"summary": "create a Binding",
|
||||
"nickname": "createBinding",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespaces",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "v1beta3.Binding",
|
||||
"paramType": "body",
|
||||
"name": "body",
|
||||
"description": "",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1beta3.Binding"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/api/v1beta3/namespaces/{namespaces}/componentstatuses",
|
||||
"description": "API at /api/v1beta3 version v1beta3",
|
||||
"operations": [
|
||||
{
|
||||
"type": "v1beta3.ComponentStatusList",
|
||||
"method": "GET",
|
||||
"summary": "list objects of kind ComponentStatus",
|
||||
"nickname": "listComponentStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespaces",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "fieldSelector",
|
||||
"description": "a selector to restrict the list of returned objects by their fields; defaults to everything",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "labelSelector",
|
||||
"description": "a selector to restrict the list of returned objects by their labels; defaults to everything",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "resourceVersion",
|
||||
"description": "when specified with a watch call, shows changes that occur after that particular version of a resource; defaults to changes from the beginning of history",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"paramType": "query",
|
||||
"name": "watch",
|
||||
"description": "watch for changes to the described resources and return them as a stream of add, update, and remove notifications; specify resourceVersion",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1beta3.ComponentStatusList"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/api/v1beta3/namespaces/{namespaces}/componentstatuses/{name}",
|
||||
"description": "API at /api/v1beta3 version v1beta3",
|
||||
"operations": [
|
||||
{
|
||||
"type": "v1beta3.ComponentStatus",
|
||||
"method": "GET",
|
||||
"summary": "read the specified ComponentStatus",
|
||||
"nickname": "readComponentStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "name",
|
||||
"description": "name of the ComponentStatus",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespaces",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1beta3.ComponentStatus"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"models": {
|
||||
"v1beta3.ComponentStatus": {
|
||||
"id": "v1beta3.ComponentStatus",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"description": "version of the schema the object should have"
|
||||
},
|
||||
"conditions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "v1beta3.ObjectReference"
|
||||
},
|
||||
"description": "list of component conditions observed"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "kind of object, in CamelCase; cannot be updated"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "v1beta3.ObjectMeta",
|
||||
"description": "standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta3.ComponentStatusList": {
|
||||
"id": "v1beta3.ComponentStatusList",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"description": "version of the schema the object should have"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "v1beta3.ComponentStatus"
|
||||
},
|
||||
"description": "list of component status objects"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "kind of object, in CamelCase; cannot be updated"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "v1beta3.ObjectMeta",
|
||||
"description": "standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta3.Binding": {
|
||||
"id": "v1beta3.Binding",
|
||||
"required": [
|
||||
"target"
|
||||
],
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"description": "version of the schema the object should have"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "kind of object, in CamelCase; cannot be updated"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "v1beta3.ObjectMeta",
|
||||
"description": "standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"
|
||||
},
|
||||
"target": {
|
||||
"$ref": "v1beta3.ObjectReference",
|
||||
"description": "an object to bind to"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta3.ObjectReference": {
|
||||
"id": "v1beta3.ObjectReference",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"description": "API version of the referent"
|
||||
},
|
||||
"fieldPath": {
|
||||
"type": "string",
|
||||
"description": "if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "kind of the referent"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "name of the referent"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "namespace of the referent"
|
||||
},
|
||||
"resourceVersion": {
|
||||
"type": "string",
|
||||
"description": "specific resourceVersion to which this reference is made, if any: http://docs.k8s.io/api-conventions.md#concurrency-control-and-consistency"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string",
|
||||
"description": "uid of the referent"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta3.ObjectMeta": {
|
||||
"id": "v1beta3.ObjectMeta",
|
||||
"properties": {
|
||||
"annotations": {
|
||||
"type": "any",
|
||||
"description": "map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about objects"
|
||||
},
|
||||
"creationTimestamp": {
|
||||
"type": "string",
|
||||
"description": "RFC 3339 date and time at which the object was created; populated by the system, read-only; null for lists"
|
||||
},
|
||||
"deletionTimestamp": {
|
||||
"type": "string",
|
||||
"description": "RFC 3339 date and time at which the object will be deleted; populated by the system when a graceful deletion is requested, read-only; if not set, graceful deletion of the object has not been requested"
|
||||
},
|
||||
"generateName": {
|
||||
"type": "string",
|
||||
"description": "an optional prefix to use to generate a unique name; has the same validation rules as name; optional, and is applied only name if is not specified"
|
||||
},
|
||||
"labels": {
|
||||
"type": "any",
|
||||
"description": "map of string keys and values that can be used to organize and categorize objects; may match selectors of replication controllers and services"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "string that identifies an object. Must be unique within a namespace; cannot be updated"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "namespace of the object; cannot be updated"
|
||||
},
|
||||
"resourceVersion": {
|
||||
"type": "string",
|
||||
"description": "string that identifies the internal version of this object that can be used by clients to determine when objects have changed; populated by the system, read-only; value must be treated as opaque by clients and passed unmodified back to the server: http://docs.k8s.io/api-conventions.md#concurrency-control-and-consistency"
|
||||
},
|
||||
"selfLink": {
|
||||
"type": "string",
|
||||
"description": "URL for the object; populated by the system, read-only"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string",
|
||||
"description": "unique UUID across space and time; populated by the system; read-only"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,9 @@
|
||||
import com.wordnik.swagger.models._
|
||||
import com.wordnik.swagger.util.Json
|
||||
import io.swagger.parser._
|
||||
|
||||
import com.wordnik.swagger.codegen.DefaultCodegen
|
||||
|
||||
import com.wordnik.swagger.models.properties.Property
|
||||
import io.swagger.parser._
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.Matchers
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
import org.scalatest.{FlatSpec, Matchers}
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class CodegenTest extends FlatSpec with Matchers {
|
||||
@ -95,6 +89,32 @@ class CodegenTest extends FlatSpec with Matchers {
|
||||
statusParam.hasMore should be (null)
|
||||
}
|
||||
|
||||
it should "handle required parameters from a 2.0 spec as required when figuring out Swagger types" in {
|
||||
val model = new SwaggerParser()
|
||||
.read("src/test/resources/2_0/requiredTest.json")
|
||||
|
||||
val codegen = new DefaultCodegen() {
|
||||
override def getSwaggerType(p: Property) = Option(p) match {
|
||||
case Some(property) if !property.getRequired =>
|
||||
"Optional<" + super.getSwaggerType(p) + ">"
|
||||
case other => super.getSwaggerType(p)
|
||||
}
|
||||
}
|
||||
val path = "/tests/requiredParams"
|
||||
val p = model.getPaths().get(path).getGet()
|
||||
val op = codegen.fromOperation(path, "get", p, model.getDefinitions)
|
||||
|
||||
val formParams = op.formParams
|
||||
formParams.size should be(2)
|
||||
val requiredParam = formParams.get(0)
|
||||
requiredParam.dataType should be("Long")
|
||||
|
||||
val optionalParam = formParams.get(1)
|
||||
optionalParam.dataType should be("Optional<string>")
|
||||
|
||||
op.returnType should be("Long")
|
||||
}
|
||||
|
||||
it should "select main response from a 2.0 spec using the lowest 2XX code" in {
|
||||
val model = new SwaggerParser()
|
||||
.read("src/test/resources/2_0/responseSelectionTest.json")
|
||||
|
@ -0,0 +1,67 @@
|
||||
import scala.collection.JavaConverters.asScalaBufferConverter
|
||||
import scala.collection.JavaConverters.mapAsJavaMapConverter
|
||||
import scala.collection.JavaConverters.seqAsJavaListConverter
|
||||
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.Matchers
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
||||
import com.wordnik.swagger.codegen.examples.ExampleGenerator
|
||||
import com.wordnik.swagger.models.Model
|
||||
import com.wordnik.swagger.models.ModelImpl
|
||||
import com.wordnik.swagger.models.Xml
|
||||
import com.wordnik.swagger.models.properties.ArrayProperty
|
||||
import com.wordnik.swagger.models.properties.RefProperty
|
||||
import com.wordnik.swagger.models.properties.StringProperty
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class ExampleGeneratorTest extends FlatSpec with Matchers {
|
||||
val json = "application/json"
|
||||
val xml = "application/xml"
|
||||
|
||||
it should "check handling of recursive models" in {
|
||||
val nodeType = "Node"
|
||||
val ref = new RefProperty(nodeType)
|
||||
val node = new ModelImpl().name(nodeType).property("name", new StringProperty())
|
||||
node.property("parent", ref)
|
||||
node.property("children", new ArrayProperty(ref))
|
||||
node.property("wrappedChildren", new ArrayProperty(ref).xml(new Xml().wrapped(true)))
|
||||
val pairType = "Pair"
|
||||
val pair = new ModelImpl().name(pairType)
|
||||
for (item <- Map("first" -> "First", "second" -> "Second")) {
|
||||
val property = new RefProperty(nodeType)
|
||||
property.setXml(new Xml().name(item._2))
|
||||
pair.property(item._1, property);
|
||||
}
|
||||
val types = scala.collection.mutable.Buffer[String]()
|
||||
val expectedTypes = List(json, xml)
|
||||
val eg = new ExampleGenerator(Map[String, Model](nodeType -> node, pairType -> pair).asJava)
|
||||
for (item <- eg.generate(null, expectedTypes.asJava, new RefProperty(pairType)).asScala) {
|
||||
val example = item.get("example")
|
||||
item.get("contentType") match {
|
||||
case `xml` => {
|
||||
types += xml
|
||||
example should be ("<Pair>\n" +
|
||||
" <Node>\n" +
|
||||
" <name>string</name>\n" +
|
||||
" <wrappedChildren>\n" +
|
||||
" </wrappedChildren>\n" +
|
||||
" </Node>\n" +
|
||||
" <Node>\n" +
|
||||
" <name>string</name>\n" +
|
||||
" <wrappedChildren>\n" +
|
||||
" </wrappedChildren>\n" +
|
||||
" </Node>\n" +
|
||||
"</Pair>")
|
||||
}
|
||||
case `json` => {
|
||||
types += json
|
||||
// TODO - add JSON validation
|
||||
example should not be (null)
|
||||
}
|
||||
}
|
||||
}
|
||||
types should be (expectedTypes)
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package python
|
||||
|
||||
import com.wordnik.swagger.codegen.languages.{PythonClientCodegen}
|
||||
import io.swagger.parser.SwaggerParser
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.Matchers
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class PythonTest extends FlatSpec with Matchers {
|
||||
it should "convert a python model with dots" in {
|
||||
val swagger = new SwaggerParser()
|
||||
.read("src/test/resources/2_0/v1beta3.json")
|
||||
|
||||
val codegen = new PythonClientCodegen()
|
||||
val simpleName = codegen.fromModel("v1beta3.Binding", swagger.getDefinitions().get("v1beta3.Binding"))
|
||||
simpleName.name should be("v1beta3.Binding")
|
||||
simpleName.classname should be("V1beta3Binding")
|
||||
simpleName.classVarName should be("v1beta3_binding")
|
||||
|
||||
val compoundName = codegen.fromModel("v1beta3.ComponentStatus", swagger.getDefinitions().get("v1beta3.ComponentStatus"))
|
||||
compoundName.name should be("v1beta3.ComponentStatus")
|
||||
compoundName.classname should be("V1beta3ComponentStatus")
|
||||
compoundName.classVarName should be("v1beta3_component_status")
|
||||
|
||||
val path = "/api/v1beta3/namespaces/{namespaces}/bindings"
|
||||
val operation = swagger.getPaths().get(path).getPost()
|
||||
val codegenOperation = codegen.fromOperation(path, "get", operation, swagger.getDefinitions())
|
||||
codegenOperation.returnType should be("V1beta3Binding")
|
||||
codegenOperation.returnBaseType should be("V1beta3Binding")
|
||||
}
|
||||
}
|
@ -6,11 +6,9 @@
|
||||
<version>2.1.1-M2-SNAPSHOT</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
<groupId>com.wordnik</groupId>
|
||||
<artifactId>swagger-generator</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>swagger-generator</name>
|
||||
<version>2.1.1-M2-SNAPSHOT</version>
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<resources>
|
||||
|
4
pom.xml
4
pom.xml
@ -450,10 +450,10 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
<properties>
|
||||
<swagger-parser-version>1.0.6-SNAPSHOT</swagger-parser-version>
|
||||
<swagger-parser-version>1.0.7</swagger-parser-version>
|
||||
<scala-version>2.10.4</scala-version>
|
||||
<felix-version>2.3.4</felix-version>
|
||||
<swagger-core-version>1.5.1-M2</swagger-core-version>
|
||||
<swagger-core-version>1.5.2-M2</swagger-core-version>
|
||||
<scala-test-version>2.1.4</scala-test-version>
|
||||
<commons-io-version>2.3</commons-io-version>
|
||||
<commons-cli-version>1.2</commons-cli-version>
|
||||
|
227
samples/client/petstore/akka-scala/pom.xml
Normal file
227
samples/client/petstore/akka-scala/pom.xml
Normal file
@ -0,0 +1,227 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.wordnik</groupId>
|
||||
<artifactId>swagger-client</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>swagger-client</name>
|
||||
<version>1.0.0</version>
|
||||
<prerequisites>
|
||||
<maven>2.2.0</maven>
|
||||
</prerequisites>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>maven-mongodb-plugin-repo</id>
|
||||
<name>maven mongodb plugin repository</name>
|
||||
<url>http://maven-mongodb-plugin.googlecode.com/svn/maven/repo</url>
|
||||
<layout>default</layout>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.12</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>loggerPath</name>
|
||||
<value>conf/log4j.properties</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<argLine>-Xms512m -Xmx1500m</argLine>
|
||||
<parallel>methods</parallel>
|
||||
<forkMode>pertest</forkMode>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- attach test jar -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add_sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>
|
||||
src/main/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add_test_sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>add-test-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>
|
||||
src/test/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>
|
||||
1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.alchim31.maven</groupId>
|
||||
<artifactId>scala-maven-plugin</artifactId>
|
||||
<version>${scala-maven-plugin-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>scala-compile-first</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>scala-test-compile</id>
|
||||
<phase>process-test-resources</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<args>
|
||||
<arg>-feature</arg>
|
||||
</args>
|
||||
<jvmArgs>
|
||||
<jvmArg>-Xms128m</jvmArg>
|
||||
<jvmArg>-Xmx1500m</jvmArg>
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
<configuration>
|
||||
<scalaVersion>${scala-version}</scalaVersion>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>${scala-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.wordnik</groupId>
|
||||
<artifactId>swagger-core</artifactId>
|
||||
<version>${swagger-core-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scalatest</groupId>
|
||||
<artifactId>scalatest_2.10</artifactId>
|
||||
<version>${scala-test-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${joda-time-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.joda</groupId>
|
||||
<artifactId>joda-convert</artifactId>
|
||||
<version>${joda-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe</groupId>
|
||||
<artifactId>config</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_2.10</artifactId>
|
||||
<version>${akka-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spray</groupId>
|
||||
<artifactId>spray-client</artifactId>
|
||||
<version>${spray-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json4s</groupId>
|
||||
<artifactId>json4s-jackson_2.10</artifactId>
|
||||
<version>${json4s-jackson-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<scala-version>2.10.4</scala-version>
|
||||
<json4s-jackson-version>3.2.11</json4s-jackson-version>
|
||||
<json4s-ext-version>3.2.11</json4s-ext-version>
|
||||
<spray-version>1.3.1</spray-version>
|
||||
<akka-version>2.3.9</akka-version>
|
||||
<joda-version>1.2</joda-version>
|
||||
<joda-time-version>2.2</joda-time-version>
|
||||
<swagger-core-version>1.5.0-M1</swagger-core-version>
|
||||
<maven-plugin.version>1.0.0</maven-plugin.version>
|
||||
|
||||
<junit-version>4.8.1</junit-version>
|
||||
<scala-maven-plugin-version>3.1.5</scala-maven-plugin-version>
|
||||
<scala-test-version>2.1.3</scala-test-version>
|
||||
</properties>
|
||||
</project>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user