Merge branch 'develop_2.0' into objc-dictionary-fix-dev2_0

Conflicts:
	modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java
This commit is contained in:
gandrianakis 2015-03-19 10:59:47 +02:00
commit 37303745df
130 changed files with 4713 additions and 1770 deletions

View File

@ -13,12 +13,12 @@ The goal of Swagger™ is to define a standard, language-agnostic interface to R
Check out [Swagger-Spec](https://github.com/swagger-api/swagger-spec) for additional information about the Swagger project, including additional libraries with support for other languages and more.
## Compatibility
The Swagger Specification has undergone 3 revisions since initial creation in 2010. The swagger-codegen project has the following compatibilities with the swagger specification:
## Compatability
The Swagger Specification has undergone 3 revisions since initial creation in 2010. The swagger-codegen project has the following compatibilies with the swagger specification:
Swagger Codegen Version | Release Date | Swagger Spec compatibility | Notes
----------------------- | ------------ | -------------------------- | -----
2.1.2-M1 (master) | 2015-02-23 | 1.0, 1.1, 1.2, 2.0 | [tag v2.1.0-M1](https://github.com/swagger-api/swagger-codegen)
2.1.3-M1-SNAPSHOT | 2015-02-23 | 1.0, 1.1, 1.2, 2.0 | [tag v2.1.0-M1](https://github.com/swagger-api/swagger-codegen)
2.0.17 | 2014-08-22 | 1.1, 1.2 | [tag v2.0.17](https://github.com/swagger-api/swagger-codegen/tree/v2.0.17)
1.0.4 | 2012-04-12 | 1.0, 1.1 | [tag v1.0.4](https://github.com/swagger-api/swagger-codegen/tree/swagger-codegen_2.9.1-1.1)
@ -46,7 +46,7 @@ You can build a client against the swagger sample [petstore](http://petstore.swa
This will run the generator with this command:
```
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.2-M1.jar \
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.3-M1-SNAPSHOT.jar \
-i http://petstore.swagger.io/v2/swagger.json \
-l java \
-o samples/client/petstore/java
@ -64,9 +64,9 @@ usage: Codegen
-i,--input-spec <arg> location of the swagger spec, as URL or file
-l,--lang <arg> client language to generate.
Available languages include:
[android, java, jaxrs, nodejs, objc, scalatra,
scala, dynamic-html, html, swagger, tizen, php,
python]
[android, async-scala, java, jaxrs, nodejs,
objc, scalatra, scala, dynamic-html, html,
swagger, tizen, php, ruby, python]
-o,--output <arg> where to write the generated files
-t,--template-dir <arg> folder containing the template files
```
@ -93,6 +93,17 @@ Don't like the default swagger client syntax? Want a different language support
You can look at `modules/swagger-codegen/src/main/resources/${your-language}` for examples. To make your own templates, create your own files and use the `-t` flag to specify your tempalte folder. It actually is that easy.
### Making your own codegen modules
If you're starting a project with a new language and don't see what you need, swagger-codegen can help you create a project to generate your own libraries:
```
java -cp modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.3-M1-SNAPSHOT.jar \
com.wordnik.swagger.codegen.MetaGenerator \
-o output/myLibrary -n myClientCodegen -p com.my.company.codegen
```
This will write, in the folder `output/myLibrary`, all the files you need to get started, including a README.md. Once modified and compiled, you can load your library with the codegen and generate clients with your own, custom-rolled logic.
### Where is Javascript???
See our [javascript library](http://github.com/swagger-api/swagger-js)--it's completely dynamic and doesn't require
static code generation.
@ -189,7 +200,7 @@ You can also use the codegen to generate a server for a couple different framewo
### node.js
```
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.2-M1.jar \
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.3-M1-SNAPSHOT.jar \
-i http://petstore.swagger.io/v2/swagger.json \
-l nodejs \
-o samples/server/petstore/nodejs
@ -201,7 +212,7 @@ java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distributi
### scala scalatra
```
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.2-M1.jar \
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.3-M1-SNAPSHOT.jar \
-i http://petstore.swagger.io/v2/swagger.json \
-l scalatra \
-o samples/server/petstore/scalatra
@ -210,7 +221,7 @@ java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distributi
### java jax-rs
```
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.2-M1.jar \
java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.3-M1-SNAPSHOT.jar \
-i http://petstore.swagger.io/v2/swagger.json \
-l jaxrs \
-o samples/server/petstore/jaxrs

36
bin/ruby-petstore.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/sh
SCRIPT="$0"
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done
if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi
root=./modules/swagger-codegen-distribution/pom.xml
# gets version of swagger-codegen
version=$(sed '/<project>/,/<\/project>/d;/<version>/!d;s/ *<\/\?version> *//g' $root | sed -n '2p' | sed -e 's,.*<version>\([^<]*\)</version>.*,\1,g')
executable="./modules/swagger-codegen-distribution/target/swagger-codegen-distribution-$version.jar"
if [ ! -f "$executable" ]
then
mvn clean package
fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="$@ -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l ruby -o samples/client/petstore/ruby"
java $JAVA_OPTS -jar $executable $ags

View File

@ -2,7 +2,7 @@
<parent>
<groupId>com.wordnik</groupId>
<artifactId>swagger-codegen-project</artifactId>
<version>2.1.2-M1</version>
<version>2.1.3-M1-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -10,7 +10,7 @@
<artifactId>swagger-codegen-distribution</artifactId>
<packaging>jar</packaging>
<name>swagger-codegen (executable)</name>
<version>2.1.2-M1</version>
<version>2.1.3-M1-SNAPSHOT</version>
<build>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<outputDirectory>target/classes</outputDirectory>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>com.wordnik</groupId>
<artifactId>swagger-codegen-project</artifactId>
<version>2.1.2-M1</version>
<version>2.1.3-M1-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -10,7 +10,7 @@
<artifactId>swagger-codegen</artifactId>
<packaging>jar</packaging>
<name>swagger-codegen (core library)</name>
<version>2.1.2-M1</version>
<version>2.1.3-M1-SNAPSHOT</version>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<defaultGoal>install</defaultGoal>

View File

@ -0,0 +1,60 @@
package com.wordnik.swagger.codegen;
import com.samskivert.mustache.*;
import java.util.regex.Pattern;
import java.io.*;
public abstract class AbstractGenerator {
public File writeToFile(String filename, String contents) throws IOException {
System.out.println("writing file " + filename);
File output = new File(filename);
if(output.getParent() != null && !new File(output.getParent()).exists()) {
File parent = new File(output.getParent());
parent.mkdirs();
}
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(output), "UTF-8"));
out.write(contents);
out.close();
return output;
}
public String readTemplate(String name) {
try{
Reader reader = getTemplateReader(name);
if(reader == null)
throw new RuntimeException("no file found");
java.util.Scanner s = new java.util.Scanner(reader).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
catch(Exception e) {
e.printStackTrace();
}
throw new RuntimeException("can't load template " + name);
}
public Reader getTemplateReader(String name) {
try{
InputStream is = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(name));
if(is == null)
is = new FileInputStream(new File(name));
if(is == null)
throw new RuntimeException("no file found");
return new InputStreamReader(is);
}
catch(Exception e) {
e.printStackTrace();
}
throw new RuntimeException("can't load template " + name);
}
private String getCPResourcePath(String name) {
if (!"/".equals(File.separator))
return name.replaceAll(Pattern.quote(File.separator), "/");
return name;
}
}

View File

@ -1,6 +1,7 @@
package com.wordnik.swagger.codegen;
import com.wordnik.swagger.models.*;
import com.wordnik.swagger.models.auth.SecuritySchemeDefinition;
import com.wordnik.swagger.models.properties.*;
import java.util.*;
@ -35,6 +36,8 @@ public interface CodegenConfig {
CodegenModel fromModel(String name, Model model);
CodegenOperation fromOperation(String resourcePath, String httpMethod, Operation operation);
List<CodegenSecurity> fromSecurity(Map<String, SecuritySchemeDefinition> schemes);
Set<String> defaultIncludes();
Map<String, String> typeMapping();
Map<String, String> instantiationTypes();

View File

@ -6,7 +6,8 @@ public enum CodegenModelType {
OPERATION(CodegenOperation.class),
PARAMETER(CodegenParameter.class),
PROPERTY(CodegenProperty.class),
RESPONSE(CodegenResponse.class);
RESPONSE(CodegenResponse.class),
SECURITY(CodegenSecurity.class);
private final Class<?> defaultImplementation;

View File

@ -6,7 +6,8 @@ import java.util.*;
public class CodegenOperation {
public Boolean hasConsumes, hasProduces, hasParams, returnTypeIsPrimitive,
returnSimpleType, subresourceOperation, isMapContainer, isListContainer;
returnSimpleType, subresourceOperation, isMapContainer, isListContainer,
hasMore = Boolean.TRUE;
public String path, operationId, returnType, httpMethod, returnBaseType,
returnContainer, summary, notes, baseName, defaultResponse;
@ -18,6 +19,7 @@ public class CodegenOperation {
public List<CodegenParameter> queryParams = new ArrayList<CodegenParameter>();
public List<CodegenParameter> headerParams = new ArrayList<CodegenParameter>();
public List<CodegenParameter> formParams = new ArrayList<CodegenParameter>();
public List<CodegenSecurity> authMethods;
public List<String> tags;
public List<CodegenResponse> responses = new ArrayList<CodegenResponse>();
public final List<CodegenProperty> responseHeaders = new ArrayList<CodegenProperty>();

View File

@ -4,6 +4,8 @@ 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 jsonSchema;
/**
* Determines whether this parameter is mandatory. If the parameter is in "path",
* this property is required and its value MUST be true. Otherwise, the property
@ -31,6 +33,7 @@ public class CodegenParameter {
output.isCookieParam = this.isCookieParam;
output.isBodyParam = this.isBodyParam;
output.required = this.required;
output.jsonSchema = this.jsonSchema;
return output;
}

View File

@ -15,6 +15,7 @@ public class CodegenProperty {
/** A free-form property to include an example of an instance for this schema. */
public String example;
public String jsonSchema;
public Double minimum, maximum, exclusiveMinimum, exclusiveMaximum;
public Boolean hasMore = null, required = null, secondaryParam = null;
public Boolean isPrimitiveType, isContainer, isNotContainer;

View File

@ -6,5 +6,12 @@ public class CodegenResponse {
public String code, message;
public Boolean hasMore;
public List<Map<String, String>> examples;
Object schema;
public final List<CodegenProperty> headers = new ArrayList<CodegenProperty>();
public String dataType, baseType, containerType;
public Boolean simpleType;
public Boolean primitiveType;
public Boolean isMapContainer;
public Boolean isListContainer;
public Object schema;
public String jsonSchema;
}

View File

@ -0,0 +1,11 @@
package com.wordnik.swagger.codegen;
public class CodegenSecurity {
String name;
String type;
Boolean hasMore, isBasic, isOAuth, isApiKey;
// ApiKey specific
String keyParamName;
Boolean isKeyInQuery, isKeyInHeader;
}

View File

@ -1,17 +1,19 @@
package com.wordnik.swagger.codegen;
import com.wordnik.swagger.models.*;
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.util.Json;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.io.File;
import java.util.*;
public class DefaultCodegen {
Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class);
@ -142,6 +144,8 @@ public class DefaultCodegen {
return name;
}
public String toOperationId(String operationId) { return operationId; }
public String toVarName(String name) {
if(reservedWords.contains(name))
return escapeReservedWord(name);
@ -156,6 +160,7 @@ public class DefaultCodegen {
return name;
}
public String escapeReservedWord(String name) {
throw new RuntimeException("reserved word " + name + " not allowed");
}
@ -312,7 +317,7 @@ public class DefaultCodegen {
}
public String snakeCase(String name) {
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
return (name.length() > 0) ? (Character.toLowerCase(name.charAt(0)) + name.substring(1)) : "";
}
public String initialCaps(String name) {
@ -397,7 +402,14 @@ public class DefaultCodegen {
LOGGER.warn("null property for " + key);
}
else {
CodegenProperty cp = fromProperty(key, prop);
CodegenProperty cp;
try{
cp = fromProperty(key, prop);
}
catch(Exception e) {
System.out.println("failed to process model " + name);
throw new RuntimeException(e);
}
cp.required = false;
if(impl.getRequired() != null) {
for(String req : impl.getRequired()) {
@ -439,6 +451,20 @@ public class DefaultCodegen {
return m;
}
public String getterAndSetterCapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
name = toVarName(name);
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isLowerCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
}
public CodegenProperty fromProperty(String name, Property p) {
if(p == null) {
LOGGER.error("unexpected missing property for name " + null);
@ -449,13 +475,13 @@ public class DefaultCodegen {
property.name = toVarName(name);
property.baseName = name;
property.description = escapeText(p.getDescription());
property.getter = "get" + initialCaps(name);
property.setter = "set" + initialCaps(name);
property.getter = "get" + getterAndSetterCapitalize(name);
property.setter = "set" + getterAndSetterCapitalize(name);
property.example = p.getExample();
property.defaultValue = toDefaultValue(p);
property.jsonSchema = Json.pretty(p);
String type = getSwaggerType(p);
if(p instanceof AbstractNumericProperty) {
AbstractNumericProperty np = (AbstractNumericProperty) p;
property.minimum = np.getMinimum();
@ -528,18 +554,29 @@ public class DefaultCodegen {
property.isPrimitiveType = true;
}
else {
setNonArrayMapProperty(property, type);
}
return property;
}
protected void setNonArrayMapProperty(CodegenProperty property, String type) {
property.isNotContainer = true;
if(languageSpecificPrimitives().contains(type))
property.isPrimitiveType = true;
else
property.complexType = property.baseType;
}
return property;
}
private Response findMethodResponse(Map<String, Response> responses) {
String code = null;
for(String responseCode : responses.keySet()) {
if (responseCode.startsWith("2") || responseCode.equals("default")) {
if (code == null || code.compareTo(responseCode) > 0) {
code = responseCode;
}
}
}
if (code == null)
return null;
return responses.get(code);
}
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation){
CodegenOperation op = CodegenModelFactory.newInstance(CodegenModelType.OPERATION);
@ -570,13 +607,11 @@ public class DefaultCodegen {
LOGGER.warn("generated operationId " + operationId);
}
op.path = path;
op.operationId = operationId;
op.operationId = toOperationId(operationId);
op.summary = escapeText(operation.getSummary());
op.notes = escapeText(operation.getDescription());
op.tags = operation.getTags();
Response methodResponse = null;
if(operation.getConsumes() != null && operation.getConsumes().size() > 0) {
List<Map<String, String>> c = new ArrayList<Map<String, String>>();
int count = 0;
@ -586,6 +621,8 @@ public class DefaultCodegen {
count += 1;
if (count < operation.getConsumes().size())
mediaType.put("hasMore", "true");
else
mediaType.put("hasMore", null);
c.add(mediaType);
}
op.consumes = c;
@ -601,81 +638,52 @@ public class DefaultCodegen {
count += 1;
if (count < operation.getProduces().size())
mediaType.put("hasMore", "true");
else
mediaType.put("hasMore", null);
c.add(mediaType);
}
op.produces = c;
op.hasProduces = true;
}
if(operation.getResponses() != null) {
for(String responseCode: new TreeSet<String>(operation.getResponses().keySet())) {
Response response = operation.getResponses().get(responseCode);
if (responseCode.startsWith("2")) {
// use the first, i.e. the smallest 2xx response status as methodResponse
methodResponse = response;
break;
}
}
if(methodResponse == null && operation.getResponses().keySet().contains("default")) {
methodResponse = operation.getResponses().get("default");
}
for(String responseCode: operation.getResponses().keySet()) {
Response response = operation.getResponses().get(responseCode);
if(response != methodResponse) {
CodegenResponse r = fromResponse(responseCode, response);
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();
CodegenResponse r = fromResponse(entry.getKey(), response);
r.hasMore = true;
if(r.baseType != null &&
!defaultIncludes.contains(r.baseType) &&
!languageSpecificPrimitives.contains(r.baseType))
imports.add(r.baseType);
if (response == methodResponse)
methodCodegenResponse = r;
op.responses.add(r);
}
for(int i = 0; i < op.responses.size() - 1; i++) {
CodegenResponse r = op.responses.get(i);
r.hasMore = new Boolean(true);
}
}
}
op.responses.get(op.responses.size() - 1).hasMore = false;
if (methodResponse != null) {
op.returnType = methodCodegenResponse.dataType;
op.returnBaseType = methodCodegenResponse.baseType;
op.returnSimpleType = methodCodegenResponse.simpleType;
op.returnTypeIsPrimitive = methodCodegenResponse.primitiveType;
op.returnContainer = methodCodegenResponse.containerType;
op.isListContainer = methodCodegenResponse.isListContainer;
op.isMapContainer = methodCodegenResponse.isMapContainer;
if (methodResponse.getSchema() != null) {
CodegenProperty cm = fromProperty("response", methodResponse.getSchema());
Property responseProperty = methodResponse.getSchema();
if(responseProperty instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) responseProperty;
CodegenProperty innerProperty = fromProperty("response", ap.getItems());
op.returnBaseType = innerProperty.baseType;
}
else {
if(cm.complexType != null)
op.returnBaseType = cm.complexType;
else
op.returnBaseType = cm.baseType;
}
responseProperty.setRequired(true);
CodegenProperty cm = fromProperty("response", responseProperty);
op.examples = toExamples(methodResponse.getExamples());
op.defaultResponse = toDefaultValue(responseProperty);
op.returnType = cm.datatype;
if(cm.isContainer != null) {
op.returnContainer = cm.containerType;
if("map".equals(cm.containerType))
op.isMapContainer = Boolean.TRUE;
else if ("list".equalsIgnoreCase(cm.containerType))
op.isListContainer = Boolean.TRUE;
}
else
op.returnSimpleType = true;
if (languageSpecificPrimitives().contains(op.returnBaseType) || op.returnBaseType == null)
op.returnTypeIsPrimitive = true;
}
addHeaders(methodResponse, op.responseHeaders);
}
if(op.returnBaseType == null) {
op.returnTypeIsPrimitive = true;
op.returnSimpleType = true;
}
if(op.returnBaseType != null &&
!defaultIncludes.contains(op.returnBaseType) &&
!languageSpecificPrimitives.contains(op.returnBaseType))
imports.add(op.returnBaseType);
}
List<Parameter> parameters = operation.getParameters();
CodegenParameter bodyParam = null;
@ -756,6 +764,42 @@ public class DefaultCodegen {
r.message = response.getDescription();
r.schema = response.getSchema();
r.examples = toExamples(response.getExamples());
r.jsonSchema = Json.pretty(response);
addHeaders(response, r.headers);
if (r.schema != null) {
Property responseProperty = response.getSchema();
responseProperty.setRequired(true);
CodegenProperty cm = fromProperty("response", responseProperty);
if(responseProperty instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) responseProperty;
CodegenProperty innerProperty = fromProperty("response", ap.getItems());
r.baseType = innerProperty.baseType;
}
else {
if(cm.complexType != null)
r.baseType = cm.complexType;
else
r.baseType = cm.baseType;
}
r.dataType = cm.datatype;
if(cm.isContainer != null) {
r.simpleType = false;
r.containerType = cm.containerType;
r.isMapContainer = "map".equals(cm.containerType);
r.isListContainer = "list".equals(cm.containerType);
}
else
r.simpleType = true;
r.primitiveType = (r.baseType == null ||languageSpecificPrimitives().contains(r.baseType));
}
if (r.baseType == null) {
r.isMapContainer = false;
r.isListContainer = false;
r.primitiveType = true;
r.simpleType = true;
}
return r;
}
@ -764,6 +808,7 @@ public class DefaultCodegen {
p.baseName = param.getName();
p.description = param.getDescription();
p.required = param.getRequired();
p.jsonSchema = Json.pretty(param);
if(param instanceof SerializableParameter) {
SerializableParameter qp = (SerializableParameter) param;
@ -853,6 +898,38 @@ public class DefaultCodegen {
return p;
}
public List<CodegenSecurity> fromSecurity(Map<String, SecuritySchemeDefinition> schemes) {
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();
final SecuritySchemeDefinition schemeDefinition = entry.getValue();
CodegenSecurity sec = CodegenModelFactory.newInstance(CodegenModelType.SECURITY);
sec.name = entry.getKey();
sec.type = schemeDefinition.getType();
if (schemeDefinition instanceof ApiKeyAuthDefinition) {
final ApiKeyAuthDefinition apiKeyDefinition = (ApiKeyAuthDefinition) schemeDefinition;
sec.isBasic = sec.isOAuth = false;
sec.isApiKey = true;
sec.keyParamName = apiKeyDefinition.getName();
sec.isKeyInHeader = apiKeyDefinition.getIn() == In.HEADER;
sec.isKeyInQuery = !sec.isKeyInHeader;
} else {
sec.isKeyInHeader = sec.isKeyInQuery = sec.isApiKey = false;
sec.isBasic = schemeDefinition instanceof BasicAuthDefinition;
sec.isOAuth = !sec.isBasic;
}
sec.hasMore = entries.hasNext();
secs.add(sec);
}
return secs;
}
protected List<Map<String, String>> toExamples(Map<String, String> examples) {
if(examples == null)
return null;

View File

@ -1,6 +1,7 @@
package com.wordnik.swagger.codegen;
import com.wordnik.swagger.models.*;
import com.wordnik.swagger.models.auth.SecuritySchemeDefinition;
import com.wordnik.swagger.util.*;
import com.samskivert.mustache.*;
@ -10,7 +11,7 @@ import java.util.*;
import java.util.regex.*;
import java.io.*;
public class DefaultGenerator implements Generator {
public class DefaultGenerator extends AbstractGenerator implements Generator {
protected CodegenConfig config;
protected ClientOptInput opts = null;
protected Swagger swagger = null;
@ -55,6 +56,9 @@ public class DefaultGenerator implements Generator {
if(license.getUrl() != null)
config.additionalProperties().put("licenseUrl", license.getUrl());
}
if(info.getVersion() != null) {
config.additionalProperties().put("version", info.getVersion());
}
}
StringBuilder hostBuilder = new StringBuilder();
@ -64,9 +68,18 @@ public class DefaultGenerator implements Generator {
}
else
hostBuilder.append("https://");
hostBuilder.append(swagger.getHost()).append(swagger.getBasePath());
if(swagger.getHost() != null)
hostBuilder.append(swagger.getHost());
else
hostBuilder.append("localhost");
if(swagger.getBasePath() != null)
hostBuilder.append(swagger.getBasePath());
else
hostBuilder.append("/");
String contextPath = swagger.getBasePath() == null ? "/" : swagger.getBasePath();
String basePath = hostBuilder.toString();
List<Object> allOperations = new ArrayList<Object>();
List<Object> allModels = new ArrayList<Object>();
@ -110,12 +123,20 @@ public class DefaultGenerator implements Generator {
List<CodegenOperation> ops = paths.get(tag);
Map<String, Object> operation = processOperations(config, tag, ops);
operation.put("basePath", basePath);
operation.put("contextPath", contextPath);
operation.put("baseName", tag);
operation.put("modelPackage", config.modelPackage());
operation.putAll(config.additionalProperties());
operation.put("classname", config.toApiName(tag));
operation.put("classVarName", config.toApiVarName(tag));
allOperations.add(operation);
allOperations.add(new HashMap<String, Object>(operation));
for(int i = 0; i < allOperations.size(); i++) {
Map<String, Object> oo = (Map<String, Object>) allOperations.get(i);
if(i < (allOperations.size() -1))
oo.put("hasMore", "true");
}
for(String templateName : config.apiTemplateFiles().keySet()) {
String suffix = config.apiTemplateFiles().get(templateName);
String filename = config.apiFileFolder() +
@ -149,9 +170,11 @@ public class DefaultGenerator implements Generator {
Map<String, Object> apis = new HashMap<String, Object>();
apis.put("apis", allOperations);
if(swagger.getBasePath() != null) {
bundle.put("basePath", swagger.getBasePath());
if(swagger.getHost() != null) {
bundle.put("host", swagger.getHost());
}
bundle.put("basePath", basePath);
bundle.put("contextPath", contextPath);
bundle.put("apiInfo", apis);
bundle.put("models", allModels);
bundle.put("apiFolder", config.apiPackage().replace('.', File.separatorChar));
@ -227,6 +250,18 @@ public class DefaultGenerator implements Generator {
return ops;
}
public SecuritySchemeDefinition fromSecurity(String name) {
Map<String, SecuritySchemeDefinition> map = swagger.getSecurityDefinitions();
if(map == null)
return null;
SecuritySchemeDefinition scheme = map.get(name);
if(scheme == null)
return null;
return scheme;
}
public void processOperation(String resourcePath, String httpMethod, Operation operation, Map<String, List<CodegenOperation>> operations) {
if(operation != null) {
List<String> tags = operation.getTags();
@ -239,8 +274,25 @@ public class DefaultGenerator implements Generator {
CodegenOperation co = config.fromOperation(resourcePath, httpMethod, operation);
co.tags = new ArrayList<String>();
co.tags.add(sanitizeTag(tag));
config.addOperationToGroup(sanitizeTag(tag), resourcePath, operation, co, operations);
List<Map<String, List<String>>> securities = operation.getSecurity();
if(securities == null)
continue;
Map<String, SecuritySchemeDefinition> authMethods = new HashMap<String, SecuritySchemeDefinition>();
for (Map<String, List<String>> security : securities) {
if (security.size() != 1) {
//Not sure what to do
continue;
}
String securityName = security.keySet().iterator().next();
SecuritySchemeDefinition securityDefinition = fromSecurity(securityName);
if(securityDefinition != null)
authMethods.put(securityName, securityDefinition);
}
if(!authMethods.isEmpty()) {
co.authMethods = config.fromSecurity(authMethods);
}
}
}
}
@ -259,57 +311,6 @@ public class DefaultGenerator implements Generator {
return buf.toString().replaceAll("[^a-zA-Z ]", "");
}
public File writeToFile(String filename, String contents) throws IOException {
System.out.println("writing file " + filename);
File output = new File(filename);
if(output.getParent() != null && !new File(output.getParent()).exists()) {
File parent = new File(output.getParent());
parent.mkdirs();
}
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(output), "UTF-8"));
out.write(contents);
out.close();
return output;
}
public String readTemplate(String name) {
try{
Reader reader = getTemplateReader(name);
if(reader == null)
throw new RuntimeException("no file found");
java.util.Scanner s = new java.util.Scanner(reader).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
catch(Exception e) {
e.printStackTrace();
}
throw new RuntimeException("can't load template " + name);
}
public Reader getTemplateReader(String name) {
try{
InputStream is = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(name));
if(is == null)
is = new FileInputStream(new File(name));
if(is == null)
throw new RuntimeException("no file found");
return new InputStreamReader(is);
}
catch(Exception e) {
e.printStackTrace();
}
throw new RuntimeException("can't load template " + name);
}
private String getCPResourcePath(String name) {
if (!"/".equals(File.separator))
return name.replaceAll(Pattern.quote(File.separator), "/");
return name;
}
public Map<String, Object> processOperations(CodegenConfig config, String tag, List<CodegenOperation> ops) {
Map<String, Object> operations = new HashMap<String, Object>();
Map<String, Object> objs = new HashMap<String, Object>();
@ -337,6 +338,14 @@ public Map<String, Object> processOperations(CodegenConfig config, String tag, L
operations.put("imports", imports);
config.postProcessOperations(operations);
if(objs.size() > 0) {
List<CodegenOperation> os = (List<CodegenOperation>) objs.get("operation");
if(os != null && os.size() > 0) {
CodegenOperation op = os.get(os.size() - 1);
op.hasMore = null;
}
}
return operations;
}

View File

@ -0,0 +1,180 @@
package com.wordnik.swagger.codegen;
import com.wordnik.swagger.codegen.languages.*;
import com.wordnik.swagger.models.Swagger;
import com.wordnik.swagger.models.auth.AuthorizationValue;
import com.wordnik.swagger.util.*;
import io.swagger.parser.SwaggerParser;
import com.samskivert.mustache.*;
import org.apache.commons.cli.*;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.Reader;
import java.util.*;
public class MetaGenerator extends AbstractGenerator {
static Map<String, CodegenConfig> configs = new HashMap<String, CodegenConfig>();
static String configString;
static {
List<CodegenConfig> extensions = getExtensions();
StringBuilder sb = new StringBuilder();
for(CodegenConfig config : extensions) {
if(sb.toString().length() != 0)
sb.append(", ");
sb.append(config.getName());
configs.put(config.getName(), config);
configString = sb.toString();
}
}
public static void main(String[] args) {
new MetaGenerator().generate(args);
}
protected void generate(String[] args) {
StringBuilder sb = new StringBuilder();
String targetLanguage = null;
String outputFolder = null;
String name = null;
String targetPackage = "com.wordnik.swagger.codegen";
final String templateDir = "codegen";
Options options = new Options();
options.addOption("h", "help", false, "shows this message");
options.addOption("l", "lang", false, "client language to generate.\nAvailable languages include:\n\t[" + configString + "]");
options.addOption("o", "output", true, "where to write the generated files");
options.addOption("n", "name", true, "the human-readable name of the generator");
options.addOption("p", "package", true, "the package to put the main class into (defaults to com.wordnik.swagger.codegen");
ClientOptInput clientOptInput = new ClientOptInput();
Swagger swagger = null;
CommandLine cmd = null;
try {
CommandLineParser parser = new BasicParser();
cmd = parser.parse(options, args);
if (cmd.hasOption("h")) {
usage(options);
return;
}
if (cmd.hasOption("n"))
name = cmd.getOptionValue("n");
else {
System.out.println("name is required");
usage(options);
return;
}
if (cmd.hasOption("l"))
targetLanguage = cmd.getOptionValue("l");
if (cmd.hasOption("p"))
targetPackage = cmd.getOptionValue("p");
if (cmd.hasOption("o"))
outputFolder = cmd.getOptionValue("o");
else {
System.out.println("output folder is required");
usage(options);
return;
}
}
catch (Exception e) {
usage(options);
return;
}
System.out.println("writing to folder " + outputFolder);
File outputFolderLocation = new File(outputFolder);
if(!outputFolderLocation.exists())
outputFolderLocation.mkdirs();
File sourceFolder = new File(outputFolder + File.separator + "src/main/java/" + targetPackage.replace('.', File.separatorChar));
if(!sourceFolder.exists())
sourceFolder.mkdirs();
File resourcesFolder = new File(outputFolder + File.separator + "src/main/resources/META-INF/services");
if(!resourcesFolder.exists())
resourcesFolder.mkdirs();
String mainClass = Character.toUpperCase(name.charAt(0)) + name.substring(1) + "Generator";
List<SupportingFile> supportingFiles = new ArrayList<SupportingFile>();
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
supportingFiles.add(new SupportingFile("generatorClass.mustache",
"src/main/java/" + File.separator + targetPackage.replace('.', File.separatorChar),
mainClass + ".java"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("api.template", "src/main/resources" + File.separator + name, "api.mustache"));
supportingFiles.add(new SupportingFile("model.template", "src/main/resources" + File.separator + name, "model.mustache"));
supportingFiles.add(new SupportingFile("services.mustache", "src/main/resources/META-INF/services", "com.wordnik.swagger.codegen.CodegenConfig"));
List<File> files = new ArrayList<File>();
Map<String, Object> data = new HashMap<String, Object>();
data.put("generatorPackage", targetPackage);
data.put("generatorClass", mainClass);
data.put("name", name);
data.put("fullyQualifiedGeneratorClass", targetPackage + "." + mainClass);
for(SupportingFile support : supportingFiles) {
try {
String destinationFolder = outputFolder;
if(support.folder != null && !"".equals(support.folder))
destinationFolder += File.separator + support.folder;
File of = new File(destinationFolder);
if(!of.isDirectory())
of.mkdirs();
String outputFilename = destinationFolder + File.separator + support.destinationFilename;
if(support.templateFile.endsWith("mustache")) {
String template = readTemplate(templateDir + File.separator + support.templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
public Reader getTemplate (String name) {
return getTemplateReader(templateDir + File.separator + name + ".mustache");
};
})
.defaultValue("")
.compile(template);
writeToFile(outputFilename, tmpl.execute(data));
files.add(new File(outputFilename));
}
else {
String template = readTemplate(templateDir + File.separator + support.templateFile);
FileUtils.writeStringToFile(new File(outputFilename), template);
System.out.println("copying file to " + outputFilename);
files.add(new File(outputFilename));
}
}
catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
public static List<CodegenConfig> getExtensions() {
ServiceLoader<CodegenConfig> loader = ServiceLoader.load(CodegenConfig.class);
List<CodegenConfig> output = new ArrayList<CodegenConfig>();
Iterator<CodegenConfig> itr = loader.iterator();
while(itr.hasNext()) {
output.add(itr.next());
}
return output;
}
static void usage(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp( "MetaGenerator. Generator for creating a new template set " +
"and configuration for Codegen. The output will be based on the language you " +
"specify, and includes default templates to include.", options );
}
public static CodegenConfig getConfig(String name) {
if(configs.containsKey(name)) {
return configs.get(name);
}
return null;
}
}

View File

@ -1,86 +0,0 @@
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option dontlognull
option httpclose
option httplog
option forwardfor
option redispatch
timeout connect 10000 # default 10 second time out if a backend is not found
timeout client 300000
timeout server 300000
maxconn 60000
retries 3
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend main *:80
default_backend app
acl is_swagger_online hdr_beg(host) -i online.swagger.io
acl is_swagger_io hdr_beg(host) -i swagger.io
acl is_old hdr_beg(host) -i swagger.wordnik.com
acl is_old_editor hdr_beg(host) -i editor.swagger.wordnik.com
acl is_validator_swagger path_beg /swagger.json
# online spec validator
reqrep ([^\ ]*)\ /validator/(.*) \1\ /validator/validator/\2 if is_swagger_online
# something that didn't work
reqrep ([^\ ]*)\ /swagger.json(.*) \1\ /validator/swagger.json if is_validator_swagger
# swagger schema
reqrep ^([^\ :]*)\ /v2/schema.json(.*) \1\ /swagger-api/swagger-spec/master/schemas/v2.0/schema.json\2
acl is_swagger_spec path_beg /swagger-api/swagger-spec
# swagger docs
reqrep ^([^\ :]*)\ /swagger-core/documentation/annotations/apidocs/current(.*) \1\ /swagger-core/apidocs/\2
acl is_swagger_docs path_beg /swagger-core/apidocs
use_backend github_swagger_io if is_swagger_docs
use_backend validator if is_swagger_online
use_backend validator if is_validator_swagger
use_backend github_swagger_io if is_swagger_io !is_swagger_spec
use_backend github_swagger_spec if is_swagger_spec
redirect location http://editor.swagger.io if is_old_editor
redirect location http://swagger.io if is_old
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend github_swagger_io
balance roundrobin
server gh1 swagger-api.github.io:80 check
backend github_swagger_spec
http-request set-header Host raw.githubusercontent.com
rspirep ^Content-type:(.*) Content-Type:\ application/json
rspirep ^Access-Control-Allow-Origin:(.*) Access-Control-Allow-Origin:*
balance roundrobin
server gh2 raw.githubusercontent.com:443 check ssl verify none
backend validator
balance roundrobin
server app1 127.0.0.1:8000 check
backend app
balance roundrobin
server app1 127.0.0.1:8000 check

View File

@ -34,6 +34,17 @@ public class AndroidClientCodegen extends DefaultCodegen implements CodegenConfi
apiPackage = "io.swagger.client.api";
modelPackage = "io.swagger.client.model";
reservedWords = new HashSet<String> (
Arrays.asList(
"abstract", "continue", "for", "new", "switch", "assert",
"default", "if", "package", "synchronized", "boolean", "do", "goto", "private",
"this", "break", "double", "implements", "protected", "throw", "byte", "else",
"import", "public", "throws", "case", "enum", "instanceof", "return", "transient",
"catch", "extends", "int", "short", "try", "char", "final", "interface", "static",
"void", "class", "finally", "long", "strictfp", "volatile", "const", "float",
"native", "super", "while")
);
additionalProperties.put("invokerPackage", invokerPackage);
additionalProperties.put("groupId", groupId);
additionalProperties.put("artifactId", artifactId);

View File

@ -87,6 +87,15 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig {
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar);
}
@Override
public String toVarName(String name) {
if(reservedWords.contains(name))
return escapeReservedWord(name);
else {
return name.replaceAll("-", "_");
}
}
@Override
public String getTypeDeclaration(Property p) {
if(p instanceof ArrayProperty) {

View File

@ -1,110 +1,170 @@
package com.wordnik.swagger.codegen.languages;
import com.wordnik.swagger.codegen.*;
import com.wordnik.swagger.models.Model;
import com.wordnik.swagger.models.properties.*;
import com.wordnik.swagger.util.Json;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.*;
import com.wordnik.swagger.models.properties.*;
import java.util.*;
import java.io.File;
public class NodeJSServerCodegen 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 apiVersion = "1.0.0";
protected int serverPort = 8080;
protected String projectName = "swagger-server";
public String apiPackage() {
return "controllers";
}
/**
* Configures the type of generator.
*
* @return the CodegenType for this generator
* @see com.wordnik.swagger.codegen.CodegenType
*/
public CodegenType getTag() {
return CodegenType.SERVER;
}
/**
* Configures a friendly name for the generator. This will be used by the generator
* to select the library with the -l flag.
*
* @return the friendly name for the generator
*/
public String getName() {
return "nodejs";
}
/**
* Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
*/
public String getHelp() {
return "Generates a node.js server application compatible with the 1.2 swagger specification.";
return "Generates a nodejs server library.";
}
public NodeJSServerCodegen() {
super();
// set the output folder here
outputFolder = "generated-code/nodejs";
apiTemplateFiles.put("api.mustache", ".js");
/**
* Models. You can write model files using the modelTemplateFiles map.
* if you want to create one template for file, you can do so here.
* for multiple files for model, just put another entry in the `modelTemplateFiles` with
* a different extension
*/
modelTemplateFiles.clear();
/**
* Api classes. You can write classes for each Api file with the apiTemplateFiles map.
* as with models, add multiple entries with different extensions for multiple files per
* class
*/
apiTemplateFiles.put(
"controller.mustache", // the template to use
".js"); // the extension for each file to write
/**
* Template Location. This is the location which templates will be read from. The generator
* will use the resource stream to attempt to read the templates.
*/
templateDir = "nodejs";
apiPackage = "app.apis";
modelPackage = "app";
additionalProperties.put("invokerPackage", invokerPackage);
additionalProperties.put("groupId", groupId);
additionalProperties.put("artifactId", artifactId);
additionalProperties.put("artifactVersion", artifactVersion);
supportingFiles.add(new SupportingFile("package.mustache", "", "package.json"));
supportingFiles.add(new SupportingFile("models.mustache", modelPackage, "models.js"));
supportingFiles.add(new SupportingFile("main.mustache", "", "main.js"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
languageSpecificPrimitives = new HashSet<String>(
/**
* Reserved words. Override this with reserved words specific to your language
*/
reservedWords = new HashSet<String> (
Arrays.asList(
"String",
"boolean",
"Boolean",
"Double",
"Integer",
"Long",
"Float")
"break", "case", "class", "catch", "const", "continue", "debugger",
"default", "delete", "do", "else", "export", "extends", "finally",
"for", "function", "if", "import", "in", "instanceof", "let", "new",
"return", "super", "switch", "this", "throw", "try", "typeof", "var",
"void", "while", "with", "yield")
);
/**
* Additional Properties. These values can be passed to the templates and
* are available in models, apis, and supporting files
*/
additionalProperties.put("apiVersion", apiVersion);
additionalProperties.put("serverPort", serverPort);
/**
* Supporting Files. You can write single files for the generator with the
* entire object tree available. If the input file has a suffix of `.mustache
* it will be processed by the template engine. Otherwise, it will be copied
*/
// supportingFiles.add(new SupportingFile("controller.mustache",
// "controllers",
// "controller.js")
// );
supportingFiles.add(new SupportingFile("swagger.mustache",
"api",
"swagger.json")
);
supportingFiles.add(new SupportingFile("index.mustache",
"",
"index.js")
);
supportingFiles.add(new SupportingFile("package.mustache",
"",
"package.json")
);
typeMapping.put("array", "array");
}
@Override
public String toApiName(String name) {
if(name.length() == 0)
return "DefaultController";
return initialCaps(name);
}
@Override
public String toApiFilename(String name) {
return toApiName(name);
}
/**
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
* those terms here. This logic is only called if a variable matches the reseved words
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name) {
return "_" + name;
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
List<Map<String, Object>> o = (List<Map<String, Object>>)objs.get("models");
for(Map<String, Object> modelMap : o) {
try {
CodegenModel m = (CodegenModel) modelMap.get("model");
ObjectNode on = (ObjectNode) Json.mapper().readTree(m.modelJson);
// inject the id field
on.put("id", m.name);
// remove the definitions qualifier with this nasty hack
m.modelJson = Json.pretty(on).replaceAll("\"#/definitions/", "\"");
}
catch (Exception e) {
e.printStackTrace();
// skip conversion
}
}
return objs;
return "_" + name; // add an underscore to the name
}
/**
* Location to write api files. You can use the apiPackage() as defined when the class is
* instantiated
*/
@Override
public String apiFileFolder() {
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
}
public String modelFileFolder() {
return outputFolder + File.separator + modelPackage().replace('.', File.separatorChar);
}
@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if(typeMapping.containsKey(swaggerType)) {
return typeMapping.get(swaggerType);
}
else
type = swaggerType;
return toModelName(type);
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");
for(CodegenOperation operation : operations) {
operation.httpMethod = operation.httpMethod.toLowerCase();
List<CodegenParameter> params = operation.allParams;
if(params != null && params.size() == 0)
operation.allParams = null;
List<CodegenResponse> responses = operation.responses;
if(responses != null) {
for(CodegenResponse resp : responses) {
if("0".equals(resp.code))
resp.code = "default";
}
}
}
return objs;
}
}

View File

@ -0,0 +1,120 @@
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;
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";
public CodegenType getTag() {
return CodegenType.CLIENT;
}
public String getName() {
return "ruby";
}
public String getHelp() {
return "Generates a Ruby client library.";
}
public RubyClientCodegen() {
super();
modelPackage = "models";
apiPackage = "lib";
outputFolder = "generated-code/ruby";
modelTemplateFiles.put("model.mustache", ".rb");
apiTemplateFiles.put("api.mustache", ".rb");
templateDir = "ruby";
typeMapping.clear();
languageSpecificPrimitives.clear();
reservedWords = new HashSet<String> (
Arrays.asList(
"int")
);
additionalProperties.put("invokerPackage", invokerPackage);
additionalProperties.put("groupId", groupId);
additionalProperties.put("artifactId", artifactId);
additionalProperties.put("artifactVersion", artifactVersion);
languageSpecificPrimitives.add("int");
languageSpecificPrimitives.add("array");
languageSpecificPrimitives.add("map");
languageSpecificPrimitives.add("string");
languageSpecificPrimitives.add("DateTime");
typeMapping.put("long", "int");
typeMapping.put("integer", "int");
typeMapping.put("Array", "array");
typeMapping.put("String", "string");
typeMapping.put("List", "array");
typeMapping.put("map", "map");
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"));
}
@Override
public String escapeReservedWord(String name) {
return "_" + name;
}
@Override
public String apiFileFolder() {
return outputFolder + "/" + apiPackage().replace('.', File.separatorChar);
}
public String modelFileFolder() {
return outputFolder + "/" + modelPackage().replace('.', File.separatorChar);
}
@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 String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if(typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if(languageSpecificPrimitives.contains(type)) {
return type;
}
}
else
type = swaggerType;
if(type == null)
return null;
return type;
}
public String toDefaultValue(Property p) {
return "null";
}
}

View File

@ -11,7 +11,7 @@ public class ScalaClientCodegen extends DefaultCodegen implements CodegenConfig
protected String groupId = "com.wordnik";
protected String artifactId = "swagger-client";
protected String artifactVersion = "1.0.0";
protected String sourceFolder = "src/main/java";
protected String sourceFolder = "src/main/scala";
protected String authScheme = "";
protected boolean authPreemptive = false;
protected boolean asyncHttpClient = !authScheme.isEmpty();

View File

@ -23,7 +23,10 @@ public class SwaggerGenerator extends DefaultCodegen implements CodegenConfig {
public SwaggerGenerator() {
super();
templateDir = "swagger";
outputFolder = "generated-code/swagger";
supportingFiles.add(new SupportingFile("README.md", "", "README.md"));
}
@Override

View File

@ -0,0 +1,44 @@
package com.wordnik.swagger.codegen.languages;
import com.wordnik.swagger.codegen.*;
import com.wordnik.swagger.util.*;
import com.wordnik.swagger.models.Swagger;
import org.apache.commons.io.FileUtils;
import java.io.File;
public class SwaggerYamlGenerator extends DefaultCodegen implements CodegenConfig {
public CodegenType getTag() {
return CodegenType.DOCUMENTATION;
}
public String getName() {
return "swagger-yaml";
}
public String getHelp() {
return "Creates a static swagger.yaml file.";
}
public SwaggerYamlGenerator() {
super();
templateDir = "swagger";
outputFolder = "generated-code/swagger";
supportingFiles.add(new SupportingFile("README.md", "", "README.md"));
}
@Override
public void processSwagger(Swagger swagger) {
try{
String swaggerString = Yaml.mapper().writeValueAsString(swagger);
String outputFile = outputFolder + File.separator + "swagger.yaml";
FileUtils.writeStringToFile(new File(outputFile), swaggerString);
System.out.println("wrote file to " + outputFile);
}
catch(Exception e) {
e.printStackTrace();
}
}
}

View File

@ -58,10 +58,10 @@ public class {{classname}} {
Map<String, String> headerParams = new HashMap<String, String>();
Map<String, String> formParams = new HashMap<String, String>();
{{#queryParams}}if(!"null".equals(String.valueOf({{paramName}})))
queryParams.put("{{baseName}}", String.valueOf({{paramName}}));
{{#queryParams}}if ({{paramName}} != null)
queryParams.put("{{baseName}}", ApiInvoker.parameterToString({{paramName}}));
{{/queryParams}}
{{#headerParams}}headerParams.put("{{baseName}}", {{paramName}});
{{#headerParams}}headerParams.put("{{baseName}}", ApiInvoker.parameterToString({{paramName}}));
{{/headerParams}}
String[] contentTypes = {
{{#consumes}}"{{mediaType}}"{{#hasMore}},{{/hasMore}}{{/consumes}}
@ -74,7 +74,7 @@ public class {{classname}} {
FormDataMultiPart mp = new FormDataMultiPart();
{{#formParams}}{{#notFile}}
hasFields = true;
mp.field("{{baseName}}", {{paramName}}, MediaType.MULTIPART_FORM_DATA_TYPE);
mp.field("{{baseName}}", ApiInvoker.parameterToString({{paramName}}), MediaType.MULTIPART_FORM_DATA_TYPE);
{{/notFile}}{{#isFile}}
hasFields = true;
mp.field("{{baseName}}", {{paramName}}, MediaType.MULTIPART_FORM_DATA_TYPE);
@ -83,7 +83,7 @@ public class {{classname}} {
postBody = mp;
}
else {
{{#formParams}}{{#notFile}}formParams.put("{{baseName}}", {{paramName}});{{/notFile}}
{{#formParams}}{{#notFile}}formParams.put("{{baseName}}", ApiInvoker.parameterToString({{paramName}}));{{/notFile}}
{{/formParams}}
}

View File

@ -19,16 +19,75 @@ import javax.ws.rs.core.MediaType;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.io.IOException;
import java.util.Date;
import java.util.TimeZone;
import java.net.URLEncoder;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class ApiInvoker {
private static ApiInvoker INSTANCE = new ApiInvoker();
private Map<String, Client> hostMap = new HashMap<String, Client>();
private Map<String, String> defaultHeaderMap = new HashMap<String, String>();
private boolean isDebug = false;
/**
* ISO 8601 date time format.
* @see https://en.wikipedia.org/wiki/ISO_8601
*/
public static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
/**
* ISO 8601 date format.
* @see https://en.wikipedia.org/wiki/ISO_8601
*/
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
static {
// Use UTC as the default time zone.
DATE_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public static Date parseDateTime(String str) {
try {
return DATE_TIME_FORMAT.parse(str);
} catch (java.text.ParseException e) {
throw new RuntimeException(e);
}
}
public static Date parseDate(String str) {
try {
return DATE_FORMAT.parse(str);
} catch (java.text.ParseException e) {
throw new RuntimeException(e);
}
}
public static String formatDateTime(Date datetime) {
return DATE_TIME_FORMAT.format(datetime);
}
public static String formatDate(Date date) {
return DATE_FORMAT.format(date);
}
public static String parameterToString(Object param) {
if (param == null) {
return "";
} else if (param instanceof Date) {
return formatDateTime((Date) param);
} else {
return String.valueOf(param);
}
}
public void enableDebug() {
isDebug = true;
}

View File

@ -2,7 +2,8 @@ package {{package}};
import {{modelPackage}}.*;
import com.wordnik.swagger.annotations.*;
import com.wordnik.swagger.annotations.ApiParam;
import com.sun.jersey.multipart.FormDataParam;
{{#imports}}import {{import}};
@ -20,7 +21,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.*;
@Path("/{{baseName}}")
@Api(value = "/{{baseName}}", description = "the {{baseName}} API")
@com.wordnik.swagger.annotations.Api(value = "/{{baseName}}", description = "the {{baseName}} API")
{{#operations}}
public class {{classname}} {
{{#operation}}
@ -28,10 +29,9 @@ public class {{classname}} {
{{#subresourceOperation}}@Path("{{path}}"){{/subresourceOperation}}
{{#hasConsumes}}@Consumes({ {{#consumes}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }){{/hasConsumes}}
{{#hasProduces}}@Produces({ {{#produces}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }){{/hasProduces}}
// {{returnType}}
@ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}})
@ApiResponses(value = { {{#responses}}
@ApiResponse(code = {{{code}}}, message = "{{{message}}}"){{#hasMore}},
@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}},

View File

@ -31,7 +31,7 @@
<version>${jetty-version}</version>
<configuration>
<webAppConfig>
<contextPath>{{^basePath}}/{{/basePath}}{{#basePath}}{{basePath}}{{/basePath}}</contextPath>
<contextPath>{{^contextPath}}/{{/contextPath}}{{#contextPath}}{{contextPath}}{{/contextPath}}</contextPath>
</webAppConfig>
<webAppSourceDirectory>target/${project.artifactId}-${project.version}</webAppSourceDirectory>
<webDefaultXml>${project.basedir}/conf/jetty/webdefault.xml</webDefaultXml>
@ -123,8 +123,17 @@
<version>${servlet-api-version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<swagger-core-version>1.5.1-M1</swagger-core-version>
<swagger-core-version>1.5.3-M1-SNAPSHOT</swagger-core-version>
<jetty-version>8.1.11.v20130520</jetty-version>
<jersey-version>1.13</jersey-version>
<slf4j-version>1.6.3</slf4j-version>

View File

@ -9,6 +9,8 @@ com.wordnik.swagger.codegen.languages.ScalaClientCodegen
com.wordnik.swagger.codegen.languages.StaticDocCodegen
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.PhpClientCodegen
com.wordnik.swagger.codegen.languages.RubyClientCodegen
com.wordnik.swagger.codegen.languages.PythonClientCodegen

View File

@ -0,0 +1,74 @@
# Swagger Codegen for the {{name}} library
## Overview
This is a boiler-plate project to generate your own client library with Swagger. It's goal is
to get you started with the basic plumbing so you can put in your own logic. It won't work without
your changes applied.
## What's Swagger?
The goal of Swagger™ is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via Swagger, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. Similar to what interfaces have done for lower-level programming, Swagger removes the guesswork in calling the service.
Check out [Swagger-Spec](https://github.com/swagger-api/swagger-spec) for additional information about the Swagger project, including additional libraries with support for other languages and more.
## How do I use this?
At this point, you've likely generated a client setup. It will include something along these lines:
```
.
|- README.md // this file
|- pom.xml // build script
|-- src
|--- main
|---- java
|----- {{generatorPackage}}.{{generatorClass}}.java // generator file
|---- resources
|----- {{name}} // template files
|----- META-INF
|------ services
|------- com.wordnik.swagger.codegen.CodegenConfig
```
You _will_ need to make changes in at least the following:
`{{generatorClass}}.java`
Templates in this folder:
`src/main/resources/{{name}}`
Once modified, you can run this:
```
mvn package
```
In your generator project. A single jar file will be produced in `target`. You can now use that with codegen:
```
java -cp /path/to/swagger-codegen-distribution:/path/to/your/jar com.wordnik.swagger.codegen.Codegen -l {{name}} -o ./test
```
Now your templates are available to the client generator and you can write output values
## But how do I modify this?
The `{{generatorClass}}.java` has comments in it--lots of comments. There is no good substitute
for reading the code more, though. See how the `{{generatorClass}}` implements `CodegenConfig`.
That class has the signature of all values that can be overridden.
For the templates themselves, you have a number of values available to you for generation.
You can execute the `java` command from above while passing different debug flags to show
the object you have available during client generation:
```
# The following additional debug options are available for all codegen targets:
# -DdebugSwagger prints the swagger specification as interpreted by the codegen
# -DdebugModels prints models passed to the template engine
# -DdebugOperations prints operations passed to the template engine
# -DdebugSupportingFiles prints additional data passed to the template engine
java -DdebugOperations -cp /path/to/swagger-codegen-distribution:/path/to/your/jar com.wordnik.swagger.codegen.Codegen -l {{name}} -o ./test
```
Will, for example, output the debug info for operations. You can use this info
in the `api.mustache` file.

View File

@ -0,0 +1,28 @@
# This is a sample api mustache template. It is representing a ficticous
# language and won't be usable or compile to anything without lots of changes.
# Use it as an example. You can access the variables in the generator object
# like such:
# use the package from the `apiPackage` variable
package: {{package}}
# operations block
{{#operations}}
classname: {{classname}}
# loop over each operation in the API:
{{#operation}}
# each operation has a `nickname`:
nickname: {{nickname}}
# and parameters:
{{#allParams}}
{{paramName}}: {{dataType}}
{{/allParams}}
{{/operation}}
# end of operations block
{{/operations}}

View File

@ -0,0 +1,191 @@
package {{generatorPackage}};
import com.wordnik.swagger.codegen.*;
import com.wordnik.swagger.models.properties.*;
import java.util.*;
import java.io.File;
public class {{generatorClass}} extends DefaultCodegen implements CodegenConfig {
// source folder where to write the files
protected String sourceFolder = "src";
protected String apiVersion = "1.0.0";
/**
* Configures the type of generator.
*
* @return the CodegenType for this generator
* @see com.wordnik.swagger.codegen.CodegenType
*/
public CodegenType getTag() {
return CodegenType.CLIENT;
}
/**
* Configures a friendly name for the generator. This will be used by the generator
* to select the library with the -l flag.
*
* @return the friendly name for the generator
*/
public String getName() {
return "{{name}}";
}
/**
* Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
*/
public String getHelp() {
return "Generates a {{name}} client library.";
}
public {{generatorClass}}() {
super();
// set the output folder here
outputFolder = "generated-code/{{name}}";
/**
* Models. You can write model files using the modelTemplateFiles map.
* if you want to create one template for file, you can do so here.
* for multiple files for model, just put another entry in the `modelTemplateFiles` with
* a different extension
*/
modelTemplateFiles.put(
"model.mustache", // the template to use
".sample"); // the extension for each file to write
/**
* Api classes. You can write classes for each Api file with the apiTemplateFiles map.
* as with models, add multiple entries with different extensions for multiple files per
* class
*/
apiTemplateFiles.put(
"api.mustache", // the template to use
".sample"); // the extension for each file to write
/**
* Template Location. This is the location which templates will be read from. The generator
* will use the resource stream to attempt to read the templates.
*/
templateDir = "{{name}}";
/**
* Api Package. Optional, if needed, this can be used in templates
*/
apiPackage = "io.swagger.client.api";
/**
* Model Package. Optional, if needed, this can be used in templates
*/
modelPackage = "io.swagger.client.model";
/**
* Reserved words. Override this with reserved words specific to your language
*/
reservedWords = new HashSet<String> (
Arrays.asList(
"sample1", // replace with static values
"sample2")
);
/**
* Additional Properties. These values can be passed to the templates and
* are available in models, apis, and supporting files
*/
additionalProperties.put("apiVersion", apiVersion);
/**
* Supporting Files. You can write single files for the generator with the
* entire object tree available. If the input file has a suffix of `.mustache
* it will be processed by the template engine. Otherwise, it will be copied
*/
supportingFiles.add(new SupportingFile("myFile.mustache", // the input template or file
"", // the destination folder, relative `outputFolder`
"myFile.sample") // the output file
);
/**
* Language Specific Primitives. These types will not trigger imports by
* the client generator
*/
languageSpecificPrimitives = new HashSet<String>(
Arrays.asList(
"Type1", // replace these with your types
"Type2")
);
}
/**
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
* those terms here. This logic is only called if a variable matches the reseved words
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name) {
return "_" + name; // add an underscore to the name
}
/**
* Location to write model files. You can use the modelPackage() as defined when the class is
* instantiated
*/
public String modelFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar);
}
/**
* Location to write api files. You can use the apiPackage() as defined when the class is
* instantiated
*/
@Override
public String apiFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar);
}
/**
* Optional - type declaration. This is a String which is used by the templates to instantiate your
* types. There is typically special handling for different property types
*
* @return a string value used as the `dataType` field for model templates, `returnType` for api templates
*/
@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);
}
/**
* Optional - swagger type conversion. This is used to map swagger types in a `Property` into
* either language specific types via `typeMapping` or into complex models if there is not a mapping.
*
* @return a string value of the type or complex model for this property
* @see com.wordnik.swagger.models.properties.Property
*/
@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if(typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if(languageSpecificPrimitives.contains(type))
return toModelName(type);
}
else
type = swaggerType;
return toModelName(type);
}
}

View File

@ -0,0 +1,102 @@
<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>io.swagger</groupId>
<artifactId>{{name}}-swagger-codegen</artifactId>
<packaging>jar</packaging>
<name>{{name}}-swagger-codegen</name>
<version>1.0.0</version>
<prerequisites>
<maven>2.2.0</maven>
</prerequisites>
<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>
<!-- 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>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-codegen</artifactId>
<version>${swagger-codegen-version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<swagger-codegen-version>2.1.2-M1</swagger-codegen-version>
<maven-plugin-version>1.0.0</maven-plugin-version>
<junit-version>4.8.1</junit-version>
</properties>
</project>

View File

@ -0,0 +1 @@
{{fullyQualifiedGeneratorClass}}

View File

@ -9,6 +9,7 @@
<div class="app-desc">{{{appDescription}}} for {{partner}}</div>
{{#infoUrl}}<div class="app-desc">More information: <a href="{{{infoUrl}}}">{{{infoUrl}}}</a></div>{{/infoUrl}}
{{#infoEmail}}<div class="app-desc">Contact Info: <a href="{{{infoEmail}}}">{{{infoEmail}}}</a></div>{{/infoEmail}}
{{#version}}<div class="app-desc">Version: {{{version}}}</div>{{/version}}
<div class="license-info">{{{licenseInfo}}}</div>
<div class="license-url">{{{licenseUrl}}}</div>
<h2>Access</h2>

View File

@ -6,3 +6,19 @@ This server was generated by the [swagger-codegen](https://github.com/swagger-ap
This example uses the [expressjs](http://expressjs.com/) framework. To see how to make this your own, look here:
[README](https://github.com/wordnik/swagger-codegen/README.md)
### Running the server
To run the server, follow these simple steps:
```
npm install
node .
```
To view the Swagger UI interface:
```
open http://localhost:8080/docs
```
This project leverages the mega-awesome [swagger-tools](https://github.com/apigee-127/swagger-tools) middleware which does most all the work.

View File

@ -1,62 +0,0 @@
var swagger = require("swagger-node-express");
var url = require("url");
var errors = swagger.errors;
var params = swagger.params;
/* add model includes */
function writeResponse (response, data) {
response.header('Access-Control-Allow-Origin', "*");
response.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
response.header("Access-Control-Allow-Headers", "Content-Type");
response.header("Content-Type", "application/json; charset=utf-8");
response.send(JSON.stringify(data));
}
exports.models = models = require("../models.js");
{{#operations}}
{{#operation}}
exports.{{nickname}} = {
'spec': {
"description" : "Operations about pets",
"path" : "{{path}}",
"notes" : "{{{notes}}}",
"summary" : "{{{summary}}}",
"method": "{{httpMethod}}",
"params" : [{{#queryParams}}
params.query("{{paramName}}", "{{description}}", "{{swaggerDataType}}", {{#required}}true{{/required}}{{^required}}false{{/required}}, {{#allowMultiple}}true{{/allowMultiple}}{{^allowMultiple}}false{{/allowMultiple}}, "{{{allowableValues}}}"{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}){{#hasMore}},{{/hasMore}}
{{/queryParams}}].concat([{{#pathParams}}
params.path("{{paramName}}", "{{description}}"){{#hasMore}},{{/hasMore}}
{{/pathParams}}]).concat([{{#headerParams}}
params.header("{{paramName}}", "{{description}}"){{#hasMore}},{{/hasMore}}
{{/headerParams}}]).concat([{{#bodyParams}}
params.body("body", "{{swaggerDataType}}", "{{description}}", {{#required}}{{required}}{{/required}}{{^required}}false{{/required}})
{{/bodyParams}}]),
{{#returnContainer}}
"type": "{{returnType}}",
"items": {
{{#returnTypeIsPrimitive}}"type": "{{returnContainer}}"{{/returnTypeIsPrimitive}}
{{^returnTypeIsPrimitive}}"$ref": "{{returnContainer}}"{{/returnTypeIsPrimitive}}
},
// container
{{/returnContainer}}
{{^returnContainer}}
"type" : "{{returnType}}",
{{/returnContainer}}
"responseMessages" : [errors.invalid('id'), errors.notFound('{{returnType}}')],
"nickname" : "{{nickname}}"
},
'action': function (req,res) {
{{#requiredParamCount}}
{{#requiredParams}}
if (!req.params.{{baseName}}) {
throw errors.invalid('{{baseName}}');
}
{{/requiredParams}}
{{/requiredParamCount}}
writeResponse(res, {message: "how about implementing {{nickname}} as a {{httpMethod}} method?"});
}
};
{{/operation}}
{{/operations}}

View File

@ -0,0 +1,17 @@
'use strict';
var url = require('url');
{{#operations}}
{{#operation}}
module.exports.{{nickname}} = function {{nickname}} (req, res, next) {
{{#allParams}}var {{paramName}} = req.swagger.params['{{baseName}}'].value;
{{/allParams}}
console.log('do some magic!');
res.setHeader('Content-Type', 'application/json');
res.end();
};
{{/operation}}
{{/operations}}

View File

@ -0,0 +1,38 @@
'use strict';
var app = require('connect')();
var http = require('http');
var swaggerTools = require('swagger-tools');
var serverPort = {{serverPort}};
// swaggerRouter configuration
var options = {
swaggerUi: '/swagger.json',
controllers: './controllers',
useStubs: process.env.NODE_ENV === 'development' ? true : false // Conditionally turn on stubs (mock mode)
};
// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
var swaggerDoc = require('./api/swagger.json');
// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
app.use(middleware.swaggerMetadata());
// Validate Swagger requests
app.use(middleware.swaggerValidator());
// Route validated requests to appropriate controller
app.use(middleware.swaggerRouter(options));
// Serve the Swagger documents and Swagger UI
app.use(middleware.swaggerUi());
// Start the server
http.createServer(app).listen({{serverPort}}, function () {
console.log('Your server is listening on port %d (http://localhost:%d)', {{serverPort}}, {{serverPort}});
console.log('Swagger-ui is available on http://localhost:%d/docs', {{serverPort}});
});
});

View File

@ -1,53 +0,0 @@
var express = require("express")
, url = require("url")
, cors = require("cors")
, app = express()
, swagger = require("swagger-node-express")
, db = false
var corsOptions = {
credentials: true,
origin: function(origin,callback) {
if(origin===undefined) {
callback(null,false);
} else {
callback(null,true);
}
}
};
app.use(express.json());
app.use(express.urlencoded());
app.use(cors(corsOptions));
{{#basePath}}
var subpath = express();
app.use("{{{basePath}}}", subpath);
swagger.setAppHandler(subpath);
{{/basePath}}
{{^basePath}}
swagger.setAppHandler(app);
{{/basePath}}
swagger.configureSwaggerPaths("", "api-docs", "")
var models = require("./app/models.js");
{{#apiInfo}}
{{#apis}}
var {{classname}} = require("./{{apiFolder}}/{{classname}}.js");
{{/apis}}
{{/apiInfo}}
swagger.addModels(models)
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}.add{{httpMethod}}({{classname}}.{{nickname}})
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}};
// configures the app
swagger.configure("http://localhost:8002{{basePath}}", "0.1");
// start the server
app.listen(8002);

View File

@ -1,3 +0,0 @@
exports.models = {
{{#models}}{{#model}}"{{classVarName}}": {{{modelJson}}}{{#hasMoreModels}},{{/hasMoreModels}}{{/model}}{{/models}}
}

View File

@ -1,16 +1,15 @@
{
"name": "{{{artifactId}}}",
"description": "Wordnik node.js server generator",
"version": "{{{artifactVersion}}}",
"homepage": "{{{homepage}}}",
"main": "./main.js",
"engines": {
"node": ">= 0.8.x"
},
"name": "{{projectName}}",
"version": "{{appVersion}}",
"description": "{{appDescription}}",
"main": "index.js",
"keywords": [
"swagger"
],
"license": "MIT",
"private": true,
"dependencies": {
"swagger-node-express": ">= 2.0.x",
"connect": ">= 1.8.x",
"cors": "2.1.1",
"express": "3.x"
"connect": "^3.2.0",
"swagger-tools": "0.8.*"
}
}

View File

@ -0,0 +1,42 @@
{
"swagger": "2.0",
"info": {
"title": "{{appName}}",
"description": "{{appDescription}}",
"version": "{{apiVersion}}"
},
{{#apiInfo}}
"produces": ["application/json"],
"host": "{{host}}",
"basePath": "{{contextPath}}",
"paths": {
{{#apis}}
{{#operations}}
{{#operation}}
"{{{path}}}": {
"{{httpMethod}}": {
"x-swagger-router-controller": "{{classname}}",
"tags": ["{{baseName}}"],
"operationId": "{{operationId}}",{{#hasParams}}
"parameters": [
{{#allParams}}
{{{jsonSchema}}}{{#hasMore}},{{/hasMore}}
{{/allParams}}
],{{/hasParams}}
"responses": {
{{#responses}}
"{{code}}": {{{jsonSchema}}}
{{#hasMore}},{{/hasMore}}
{{/responses}}
}
}
} {{#hasMore}},{{/hasMore}}
{{/operation}}
{{#hasMore}},{{/hasMore}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
}, "definitions": {
{{#models}}{{#model}}"{{classVarName}}": {{{modelJson}}}{{#hasMoreModels}},{{/hasMoreModels}}{{/model}}{{/models}}
}
}

View File

@ -48,6 +48,18 @@ class APIClient {
$this->headerValue = $headerValue;
}
/**
* 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.');
}
$this->user_agent= $user_agent;
}
/**
* @param integer $seconds Number of seconds before timing out [set to 0 for no timeout]
*/
@ -58,7 +70,6 @@ class APIClient {
$this->curl_timout = $seconds;
}
/**
* @param string $resourcePath path to method endpoint
* @param string $method method to call
@ -107,6 +118,9 @@ class APIClient {
if ($method == self::$POST) {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
} else if ($method == self::$PATCH) {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
} else if ($method == self::$PUT) {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
@ -118,25 +132,35 @@ class APIClient {
}
curl_setopt($curl, CURLOPT_URL, $url);
// Set user agent
if ($this->user_agent) {
curl_setopt($curl, CURLOPT_USERAGENT, $this->user_agent);
} else { // use PHP-Swagger as the default user agent
curl_setopt($curl, CURLOPT_USERAGENT, 'PHP-Swagger');
}
// Make the request
$response = curl_exec($curl);
$response_info = curl_getinfo($curl);
// Handle the response
if ($response_info['http_code'] == 0) {
throw new Exception("TIMEOUT: api call to " . $url .
" took more than 5s to return" );
} else if ($response_info['http_code'] == 200) {
throw new APIClientException("TIMEOUT: api call to " . $url .
" took more than 5s to return", 0, $response_info, $response);
} else if ($response_info['http_code'] >= 200 && $response_info['http_code'] <= 299 ) {
$data = json_decode($response);
if (json_last_error() > 0) { // if response is a string
$data = $response;
}
} else if ($response_info['http_code'] == 401) {
throw new Exception("Unauthorized API request to " . $url .
": ".json_decode($response)->message );
throw new APIClientException("Unauthorized API request to " . $url .
": " . serialize($response), 0, $response_info, $response);
} else if ($response_info['http_code'] == 404) {
$data = null;
} else {
throw new Exception("Can't connect to the api: " . $url .
throw new APIClientException("Can't connect to the api: " . $url .
" response code: " .
$response_info['http_code']);
$response_info['http_code'], 0, $response_info, $response);
}
return $data;
}
@ -175,7 +199,7 @@ class APIClient {
* @return string the serialized object
*/
public static function toPathValue($value) {
return rawurlencode($value);
return rawurlencode(toString($value));
}
/**
@ -190,19 +214,47 @@ class APIClient {
if (is_array($object)) {
return implode(',', $object);
} else {
return $object;
return toString($object);
}
}
/**
* Just pass through the header value for now. Placeholder in case we
* find out we need to do something with header values.
* Take value and turn it into a string suitable for inclusion in
* the header. If it's a string, pass through unchanged
* If it's a datetime object, format it in ISO8601
* @param string $value a string which will be part of the header
* @return string the header string
*/
public static function toHeaderValue($value) {
return toString($value);
}
/**
* Take value and turn it into a string suitable for inclusion in
* the http body (form parameter). If it's a string, pass through unchanged
* If it's a datetime object, format it in ISO8601
* @param string $value the value of the form parameter
* @return string the form string
*/
public static function toFormValue($value) {
return toString($value);
}
/**
* Take value and turn it into a string suitable for inclusion in
* the parameter. If it's a string, pass through unchanged
* If it's a datetime object, format it in ISO8601
* @param string $value the value of the parameter
* @return string the header string
*/
public static function toString($value) {
if ($value instanceof \DateTime) { // datetime in ISO8601 format
return $value->format(\DateTime::ISO8601);
}
else {
return $value;
}
}
/**
* Deserialize a JSON string into an object
@ -220,13 +272,14 @@ class APIClient {
$inner = substr($class, 4, -1);
$values = array();
if(strrpos($inner, ",") !== false) {
$subClass = explode(',', $inner, 2)[1];
$subClass_array = explode(',', $inner, 2);
$subClass = $subClass_array[1];
foreach ($data as $key => $value) {
$values[] = array($key => self::deserialize($value, $subClass));
}
}
$deserialized = $values;
} elseif (substr($class, 0, 6) == 'array[') {
} elseif (strcasecmp(substr($class, 0, 6),'array[') == 0) {
$subClass = substr($class, 6, -1);
$values = array();
foreach ($data as $key => $value) {
@ -253,3 +306,20 @@ class APIClient {
}
class APIClientException extends Exception {
protected $response, $response_info;
public function __construct($message="", $code=0, $response_info=null, $response=null) {
parent::__construct($message, $code);
$this->response_info = $response_info;
$this->response = $response;
}
public function getResponse() {
return $this->response;
}
public function getResponseInfo() {
return $this->response_info;
}
}

View File

@ -50,20 +50,20 @@ class {{classname}} {
{{#queryParams}}// query params
if(${{paramName}} !== null) {
$queryParams['{{paramName}}'] = $this->apiClient->toQueryValue(${{paramName}});
$queryParams['{{baseName}}'] = $this->apiClient->toQueryValue(${{paramName}});
}{{/queryParams}}
{{#headerParams}}// header params
if(${{paramName}} !== null) {
$headerParams['{{paramName}}'] = $this->apiClient->toHeaderValue(${{paramName}});
$headerParams['{{baseName}}'] = $this->apiClient->toHeaderValue(${{paramName}});
}{{/headerParams}}
{{#pathParams}}// path params
if(${{paramName}} !== null) {
$resourcePath = str_replace("{" . "{{paramName}}" . "}",
$resourcePath = str_replace("{" . "{{baseName}}" . "}",
$this->apiClient->toPathValue(${{paramName}}), $resourcePath);
}{{/pathParams}}
{{#formParams}}
{{#formParams}}// form params
if (${{paramName}} !== null) {
$formParams[{{paramName}}] = {{#isFile}}'@' . {{/isFile}}${{paramName}};
$formParams['{{baseName}}'] = {{#isFile}}'@' . {{/isFile}}$this->apiClient->toFormValue(${{paramName}});
}{{/formParams}}
{{#bodyParams}}// body params
$body = null;
@ -71,6 +71,7 @@ class {{classname}} {
$body = ${{paramName}};
}{{/bodyParams}}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {

View File

@ -24,7 +24,7 @@
{{#models}}
{{#model}}
class {{classname}} {
class {{classname}} implements ArrayAccess {
static $swaggerTypes = array(
{{#vars}}'{{name}}' => '{{{datatype}}}'{{#hasMore}},
{{/hasMore}}{{/vars}}
@ -35,6 +35,27 @@ class {{classname}} {
* {{{description}}}
*/{{/description}}
public ${{name}}; /* {{{datatype}}} */{{/vars}}
public function __construct(array $data) {
{{#vars}}$this->{{name}} = $data["{{name}}"];{{#hasMore}}
{{/hasMore}}{{/vars}}
}
public function offsetExists($offset) {
return isset($this->$offset);
}
public function offsetGet($offset) {
return $this->$offset;
}
public function offsetSet($offset, $value) {
$this->$offset = $value;
}
public function offsetUnset($offset) {
unset($this->$offset);
}
}
{{/model}}
{{/models}}

View File

@ -43,7 +43,6 @@ class ApiClient:
data = None
if queryParams:
# Need to remove None values, these should not be sent
sentQueryParams = {}
@ -57,7 +56,7 @@ class ApiClient:
#Options to add statements later on and for compatibility
pass
elif method in ['POST', 'PUT', 'DELETE']:
elif method in ['PATCH', 'POST', 'PUT', 'DELETE']:
if postData:
headers['Content-type'] = 'application/json'
@ -119,6 +118,39 @@ class ApiClient:
for (key, val) in objDict.items()
if key != 'swaggerTypes'}
def _iso8601Format(self, timesep, microsecond, offset, zulu):
"""Format for parsing a datetime string with given properties.
Args:
timesep -- string separating time from date ('T' or 't')
microsecond -- microsecond portion of time ('.XXX')
offset -- time offset (+/-XX:XX) or None
zulu -- 'Z' or 'z' for UTC, or None for time offset (+/-XX:XX)
Returns:
str - format string for datetime.strptime"""
return '%Y-%m-%d{}%H:%M:%S{}{}'.format(
timesep,
'.%f' if microsecond else '',
zulu or ('%z' if offset else ''))
# http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14
_iso8601Regex = re.compile(
r'^\d\d\d\d-\d\d-\d\d([Tt])\d\d:\d\d:\d\d(\.\d+)?(([Zz])|(\+|-)\d\d:?\d\d)?$')
def _parseDatetime(self, d):
if d is None:
return None
m = ApiClient._iso8601Regex.match(d)
if not m:
raise Exception('datetime regex match failed "%s"' % d)
timesep, microsecond, offset, zulu, plusminus = m.groups()
format = self._iso8601Format(timesep, microsecond, offset, zulu)
if offset and not zulu:
d = d.rsplit(sep=plusminus, maxsplit=1)[0] + offset.replace(':', '')
return datetime.datetime.strptime(d, format)
def deserialize(self, obj, objClass):
"""Derialize a JSON string into an object.
@ -145,11 +177,7 @@ class ApiClient:
if objClass in [int, float, dict, list, str, bool]:
return objClass(obj)
elif objClass == datetime:
# Server will always return a time stamp in UTC, but with
# trailing +0000 indicating no offset from UTC. So don't process
# last 5 characters.
return datetime.datetime.strptime(obj[:-5],
"%Y-%m-%dT%H:%M:%S.%f")
return self._parseDatetime(obj)
instance = objClass()
@ -167,8 +195,7 @@ class ApiClient:
value = value
setattr(instance, attr, value)
elif (attrType == 'datetime'):
setattr(instance, attr, datetime.datetime.strptime(value[:-5],
"%Y-%m-%dT%H:%M:%S.%f"))
setattr(instance, attr, self._parseDatetime(value))
elif 'list[' in attrType:
match = re.match('list\[(.*)\]', attrType)
subClass = match.group(1)
@ -182,7 +209,7 @@ class ApiClient:
setattr(instance, attr, subValues)
else:
setattr(instance, attr, self.deserialize(value,
objClass))
attrType))
return instance

View File

@ -23,9 +23,7 @@ class {{classname}}
# set default values and merge with input
options = {
{{#allParams}}
:{{paramName}} => {{paramName}}{{#hasMore}},
{{/hasMore}}
{{#allParams}}:'{{paramName}}' => {{paramName}}{{#hasMore}},{{/hasMore}}
{{/allParams}}
}.merge(opts)
@ -38,13 +36,12 @@ class {{classname}}
query_param_keys.include? key
end
{{#headerParams}}headers = {
{{{paramName}}}: {{{paramName}}},
}
{{/headerParams}}
{{^headerParams}}headers = nil
{{/headerParams}}
# header parameters, if any
headers = {}
{{#headerParams}}{{#optional}}headers[:'{{{baseName}}}'] = options[:'{{{paramName}}}'] if options[:'{{{paramName}}}']{{/optional}}{{/headerParams}}
{{#headerParams}}{{^optional}}headers[:'{{{baseName}}}'] = {{{paramName}}}{{/optional}}{{/headerParams}}
# http body (model)
post_body = nil
{{#bodyParam}}
if body != nil
@ -69,13 +66,18 @@ class {{classname}}
end
{{/bodyParam}}
# form parameters
form_parameter_hash = {}
{{#formParams}}{{#optional}}form_parameter_hash["{{baseName}}"] = options[:'{{paramName}}'] if options[:'{{paramName}}']{{/optional}}
{{^optional}}form_parameter_hash["{{baseName}}"] = {{paramName}}{{/optional}}{{/formParams}}
{{#returnType}}
response = Swagger::Request.new(:{{httpMethod}}, path, {:params=>queryopts,:headers=>headers, :body=>post_body }).make.body
response = Swagger::Request.new(:{{httpMethod}}, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
{{#returnContainer}}
response.map {|response|{{/returnContainer}} {{returnBaseType}}.new(response){{#returnContainer}} }{{/returnContainer}}
{{/returnType}}
{{^returnType}}
Swagger::Request.new(:{{httpMethod}}, path, {:params=>queryopts,:headers=>headers, :body=>post_body}).make
Swagger::Request.new(:{{httpMethod}}, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
{{/returnType}}
{{newline}}
end

View File

@ -6,10 +6,8 @@ class {{classname}}
# :internal => :external
def self.attribute_map
{
{{#vars}}
:{{{name}}} => :{{{baseName}}}{{#hasMore}},
{{/hasMore}}
{{/vars}}{{newline}}
{{#vars}}:{{{name}}} => :'{{{baseName}}}'{{#hasMore}},{{/hasMore}}
{{/vars}}
}
end
@ -18,15 +16,11 @@ class {{classname}}
# Morph attribute keys into undescored rubyish style
{{#vars}}
if self.class.attribute_map[:"{{{name}}}"]
{{#isContainer}}
if (value = attributes["{{{baseName}}}"]).is_a?(Array)
@{{{name}}} = value{{#complexType}}.map{ |v| {{complexType}}.new(v) }{{/complexType}}{{newline}}
{{#isContainer}}if (value = attributes["{{{baseName}}}"]).is_a?(Array)
@{{{name}}} = value{{#complexType}}.map{ |v| {{complexType}}.new(v) }{{/complexType}}
end{{/isContainer}}{{^isContainer}}@{{{name}}} = attributes["{{{baseName}}}"]{{/isContainer}}
end
{{/isContainer}}{{^isContainer}}
@{{{name}}} = attributes["{{{baseName}}}"]
{{/isContainer}}
end
{{/vars}}{{newline}}
{{/vars}}
end
def to_body

View File

@ -6,7 +6,7 @@ module Swagger
require 'typhoeus'
require "swagger/version"
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers, :form_params
# All requests must have an HTTP method and a path
@ -115,9 +115,18 @@ module Swagger
end
# If body is an object, JSONify it before making the actual request.
#
# For form parameters, remove empty value
def outgoing_body
body.is_a?(String) ? body : body.to_json
# 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
# Construct a query string from the query-string-type params
@ -163,6 +172,13 @@ module Swagger
: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,

View File

@ -17,6 +17,7 @@ import scala.collection.JavaConverters._
import scala.collection.mutable.HashMap
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.datatype.joda.JodaModule
import com.fasterxml.jackson.core.JsonGenerator.Feature
import com.fasterxml.jackson.databind._
import com.fasterxml.jackson.annotation._
@ -26,6 +27,7 @@ object ScalaJsonUtil {
def getJsonMapper = {
val mapper = new ObjectMapper()
mapper.registerModule(new DefaultScalaModule())
mapper.registerModule(new JodaModule());
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT)
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)

View File

@ -0,0 +1,2 @@
# Swagger JSON
This is a swagger JSON built by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project.

View File

@ -0,0 +1,139 @@
{
"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/withTwoHundredAndDefault": {
"get": {
"summary": "Operation with several unordered 2XX results and one default",
"description": "",
"operationId": "withTwoHundredAndDefault",
"produces": [
"application/json"
],
"responses": {
"default": {
"description": "default response",
"schema": {
"type": "integer",
"format": "int32"
}
},
"100": {
"description": "100 response",
"schema": {
"type": "integer",
"format": "int32"
}
},
"202": {
"description": "201 response",
"schema": {
"type": "integer",
"format": "int64"
}
},
"203": {
"description": "202 response",
"schema": {
"type": "integer",
"format": "int32"
}
},
"400": {
"description": "400 response",
"schema": {
"type": "integer",
"format": "int32"
}
},
"201": {
"description": "200 response",
"schema": {
"type": "string"
}
}
}
}
},
"/tests/withoutTwoHundredButDefault": {
"get": {
"summary": "Operation with several unordered 2XX results and one default",
"description": "",
"operationId": "withoutTwoHundredButDefault",
"produces": [
"application/json"
],
"responses": {
"default": {
"description": "default response",
"schema": {
"type": "string"
}
},
"100": {
"description": "100 response",
"schema": {
"type": "integer",
"format": "int32"
}
},
"301": {
"description": "301 response",
"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"
}
}
}
}
}

View File

@ -94,4 +94,31 @@ class CodegenTest extends FlatSpec with Matchers {
statusParam.required should equal (false)
statusParam.hasMore should be (null)
}
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")
val codegen = new DefaultCodegen()
val path = "/tests/withTwoHundredAndDefault"
val p = model.getPaths().get(path).getGet()
val op = codegen.fromOperation(path, "get", p)
op.returnType should be("String")
}
it should "select main response from a 2.0 spec using the default keyword when no 2XX code" in {
val model = new SwaggerParser()
.read("src/test/resources/2_0/responseSelectionTest.json")
val codegen = new DefaultCodegen()
val path = "/tests/withoutTwoHundredButDefault"
val p = model.getPaths().get(path).getGet()
val op = codegen.fromOperation(path, "get", p)
op.returnType should be("String")
}
}

View File

@ -14,7 +14,6 @@ import scala.collection.JavaConverters._
@RunWith(classOf[JUnitRunner])
class JavaModelTest extends FlatSpec with Matchers {
it should "convert a simple java model" in {
val model = new ModelImpl()
.description("a sample model")
@ -124,6 +123,37 @@ class JavaModelTest extends FlatSpec with Matchers {
vars.get(0).isContainer should equal (true)
}
ignore should "convert a model with a map with complex list property" in {
val model = new ModelImpl()
.description("a sample model")
.property("translations", new MapProperty()
.additionalProperties(
new ArrayProperty().items(new RefProperty("Pet")))
)
.required("id")
val codegen = new JavaClientCodegen()
val cm = codegen.fromModel("sample", model)
cm.name should be ("sample")
cm.classname should be ("Sample")
cm.description should be ("a sample model")
cm.vars.size should be (1)
val vars = cm.vars
vars.get(0).baseName should be ("translations")
vars.get(0).getter should be ("getTranslations")
vars.get(0).setter should be ("setTranslations")
vars.get(0).datatype should be ("Map<String, List<Pet>>")
vars.get(0).name should be ("translations")
vars.get(0).defaultValue should be ("new HashMap<String, List<Pet>>() ")
vars.get(0).baseType should be ("Map")
vars.get(0).containerType should be ("map")
vars.get(0).required should equal (false)
vars.get(0).isContainer should equal (true)
}
it should "convert a model with complex properties" in {
val model = new ModelImpl()
.description("a sample model")
@ -265,4 +295,44 @@ class JavaModelTest extends FlatSpec with Matchers {
vars.get(0).required should equal (true)
vars.get(0).isNotContainer should equal (true)
}
it should "convert a model with a 2nd char upper-case property names" in {
val model = new ModelImpl()
.description("a model with a 2nd char upper-case property names")
.property("pId", new StringProperty())
.required("pId")
val codegen = new JavaClientCodegen()
val cm = codegen.fromModel("sample", model)
cm.name should be ("sample")
cm.classname should be ("Sample")
cm.vars.size should be (1)
val vars = cm.vars
vars.get(0).baseName should be ("pId")
vars.get(0).getter should be ("getpId")
vars.get(0).setter should be ("setpId")
vars.get(0).datatype should be ("String")
vars.get(0).name should be ("pId")
vars.get(0).defaultValue should be ("null")
vars.get(0).baseType should be ("String")
vars.get(0).hasMore should equal (null)
vars.get(0).required should equal (true)
vars.get(0).isNotContainer should equal (true)
}
it should "convert hyphens per issue 503" in {
val model = new ModelImpl()
.description("a sample model")
.property("created-at", new DateTimeProperty())
val codegen = new JavaClientCodegen()
val cm = codegen.fromModel("sample", model)
val vars = cm.vars
vars.get(0).baseName should be("created-at")
vars.get(0).getter should be ("getCreated_at")
vars.get(0).setter should be ("setCreated_at")
vars.get(0).name should be ("created_at")
}
}

View File

@ -3,14 +3,14 @@
<parent>
<groupId>com.wordnik</groupId>
<artifactId>swagger-codegen-project</artifactId>
<version>2.1.2-M1</version>
<version>2.1.3-M1-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<groupId>com.wordnik</groupId>
<artifactId>swagger-generator</artifactId>
<packaging>war</packaging>
<name>swagger-generator</name>
<version>1.0.0</version>
<version>2.1.3-M1-SNAPSHOT</version>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
@ -221,20 +221,12 @@
</dependency>
</dependencies>
<properties>
<felix-version>2.3.4</felix-version>
<servlet-api-version>2.5</servlet-api-version>
<logback-version>1.0.1</logback-version>
<junit-version>4.8.1</junit-version>
<maven-plugin-version>1.0.0</maven-plugin-version>
<commons-lang-version>2.4</commons-lang-version>
<slf4j-version>1.6.3</slf4j-version>
<servlet-api-version>2.5</servlet-api-version>
<zip-version>1.3.2</zip-version>
<jetty-version>9.0.7.v20131107</jetty-version>
<jersey2-version>2.4.1</jersey2-version>
<swagger-core-version>1.5.1-M1</swagger-core-version>
<scala-maven-plugin-version>3.1.5</scala-maven-plugin-version>
<scala-version>2.10.0</scala-version>
</properties>
</project>

View File

@ -66,6 +66,7 @@ public class Generator {
List<File> files = new Codegen().opts(clientOptInput).generate();
if(files.size() > 0) {
List<File> filesToAdd = new ArrayList<File>();
System.out.println("adding to " + outputFolder);
filesToAdd.add(new File(outputFolder));
ZipUtil zip = new ZipUtil();
zip.compressFiles(filesToAdd, outputFilename);

View File

@ -34,9 +34,10 @@ public class SwaggerResource {
@GET
@Path("/download/{fileId}")
@Produces({"application/zip"})
@Produces({MediaType.APPLICATION_OCTET_STREAM})
@ApiOperation(value = "Downloads a pre-generated file",
response = String.class)
response = String.class,
tags = {"clients", "servers"})
public Response downloadFile(@PathParam("fileId") String fileId) throws Exception {
Generated g = fileMap.get(fileId);
System.out.println("looking for fileId " + fileId);
@ -57,9 +58,10 @@ public class SwaggerResource {
@POST
@Path("/clients/{language}")
@Produces({"application/zip", "application/json"})
@ApiOperation(
value = "Generates a client library based on the config")
value = "Generates a client library based on the config",
response = ResponseCode.class,
tags = "clients")
public Response generateClient(
@ApiParam(value = "The target language for the client library", allowableValues = "android,java,php,objc,docs", required = true) @PathParam("language") String language,
@ApiParam(value = "Configuration for building the client library", required = true) GeneratorInput opts) throws Exception {
@ -85,7 +87,8 @@ public class SwaggerResource {
@Path("/clients")
@ApiOperation(value = "Gets languages supported by the client generator",
response = String.class,
responseContainer = "List")
responseContainer = "List",
tags = "clients")
public Response clientOptions() {
String[] languages = new String[clients.size()];
languages = clients.toArray(languages);
@ -96,7 +99,8 @@ public class SwaggerResource {
@Path("/servers")
@ApiOperation(value = "Gets languages supported by the server generator",
response = String.class,
responseContainer = "List")
responseContainer = "List",
tags = "servers")
public Response serverOptions() {
String[] languages = new String[servers.size()];
languages = servers.toArray(languages);
@ -106,7 +110,8 @@ public class SwaggerResource {
@POST
@Path("/servers/{framework}")
@ApiOperation(value = "Generates a server library for the supplied server framework",
notes = "The model representing this is not accurate, it needs to contain a consolidated JSON structure")
response = ResponseCode.class,
tags = "servers")
public Response generateServerForLanguage(
@ApiParam(value = "framework", allowableValues = "jaxrs,nodejs", required = true) @PathParam("framework") String framework,
@ApiParam(value = "parameters", required = true) GeneratorInput opts)

View File

@ -9,7 +9,7 @@
<artifactId>swagger-codegen-project</artifactId>
<packaging>pom</packaging>
<name>swagger-codegen-project</name>
<version>2.1.2-M1</version>
<version>2.1.3-M1-SNAPSHOT</version>
<url>https://github.com/swagger-api/swagger-codegen</url>
<scm>
<connection>scm:git:git@github.com:swagger-api/swagger-codegen.git</connection>
@ -347,10 +347,10 @@
</repository>
</repositories>
<properties>
<swagger-parser-version>1.0.1</swagger-parser-version>
<swagger-parser-version>1.0.3</swagger-parser-version>
<scala-version>2.11.1</scala-version>
<felix-version>2.3.4</felix-version>
<swagger-core-version>1.5.2-M1</swagger-core-version>
<swagger-core-version>1.5.3-M1-SNAPSHOT</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>

View File

@ -19,16 +19,75 @@ import javax.ws.rs.core.MediaType;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.io.IOException;
import java.util.Date;
import java.util.TimeZone;
import java.net.URLEncoder;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class ApiInvoker {
private static ApiInvoker INSTANCE = new ApiInvoker();
private Map<String, Client> hostMap = new HashMap<String, Client>();
private Map<String, String> defaultHeaderMap = new HashMap<String, String>();
private boolean isDebug = false;
/**
* ISO 8601 date time format.
* @see https://en.wikipedia.org/wiki/ISO_8601
*/
public static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
/**
* ISO 8601 date format.
* @see https://en.wikipedia.org/wiki/ISO_8601
*/
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
static {
// Use UTC as the default time zone.
DATE_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public static Date parseDateTime(String str) {
try {
return DATE_TIME_FORMAT.parse(str);
} catch (java.text.ParseException e) {
throw new RuntimeException(e);
}
}
public static Date parseDate(String str) {
try {
return DATE_FORMAT.parse(str);
} catch (java.text.ParseException e) {
throw new RuntimeException(e);
}
}
public static String formatDateTime(Date datetime) {
return DATE_TIME_FORMAT.format(datetime);
}
public static String formatDate(Date date) {
return DATE_FORMAT.format(date);
}
public static String parameterToString(Object param) {
if (param == null) {
return "";
} else if (param instanceof Date) {
return formatDateTime((Date) param);
} else {
return String.valueOf(param);
}
}
public void enableDebug() {
isDebug = true;
}

View File

@ -148,8 +148,8 @@ public class PetApi {
Map<String, String> headerParams = new HashMap<String, String>();
Map<String, String> formParams = new HashMap<String, String>();
if(!"null".equals(String.valueOf(status)))
queryParams.put("status", String.valueOf(status));
if (status != null)
queryParams.put("status", ApiInvoker.parameterToString(status));
String[] contentTypes = {
@ -200,8 +200,8 @@ public class PetApi {
Map<String, String> headerParams = new HashMap<String, String>();
Map<String, String> formParams = new HashMap<String, String>();
if(!"null".equals(String.valueOf(tags)))
queryParams.put("tags", String.valueOf(tags));
if (tags != null)
queryParams.put("tags", ApiInvoker.parameterToString(tags));
String[] contentTypes = {
@ -317,17 +317,17 @@ public class PetApi {
FormDataMultiPart mp = new FormDataMultiPart();
hasFields = true;
mp.field("name", name, MediaType.MULTIPART_FORM_DATA_TYPE);
mp.field("name", ApiInvoker.parameterToString(name), MediaType.MULTIPART_FORM_DATA_TYPE);
hasFields = true;
mp.field("status", status, MediaType.MULTIPART_FORM_DATA_TYPE);
mp.field("status", ApiInvoker.parameterToString(status), MediaType.MULTIPART_FORM_DATA_TYPE);
if(hasFields)
postBody = mp;
}
else {
formParams.put("name", name);
formParams.put("status", status);
formParams.put("name", ApiInvoker.parameterToString(name));
formParams.put("status", ApiInvoker.parameterToString(status));
}
@ -364,7 +364,7 @@ public class PetApi {
Map<String, String> formParams = new HashMap<String, String>();
headerParams.put("api_key", api_key);
headerParams.put("api_key", ApiInvoker.parameterToString(api_key));
String[] contentTypes = {
@ -428,7 +428,7 @@ public class PetApi {
FormDataMultiPart mp = new FormDataMultiPart();
hasFields = true;
mp.field("additionalMetadata", additionalMetadata, MediaType.MULTIPART_FORM_DATA_TYPE);
mp.field("additionalMetadata", ApiInvoker.parameterToString(additionalMetadata), MediaType.MULTIPART_FORM_DATA_TYPE);
hasFields = true;
mp.field("file", file, MediaType.MULTIPART_FORM_DATA_TYPE);
@ -437,7 +437,7 @@ public class PetApi {
postBody = mp;
}
else {
formParams.put("additionalMetadata", additionalMetadata);
formParams.put("additionalMetadata", ApiInvoker.parameterToString(additionalMetadata));
}

View File

@ -198,10 +198,10 @@ public class UserApi {
Map<String, String> headerParams = new HashMap<String, String>();
Map<String, String> formParams = new HashMap<String, String>();
if(!"null".equals(String.valueOf(username)))
queryParams.put("username", String.valueOf(username));
if(!"null".equals(String.valueOf(password)))
queryParams.put("password", String.valueOf(password));
if (username != null)
queryParams.put("username", ApiInvoker.parameterToString(username));
if (password != null)
queryParams.put("password", ApiInvoker.parameterToString(password));
String[] contentTypes = {

View File

@ -110,28 +110,6 @@ static NSString * basePath = @"http://petstore.swagger.io/v2";
// primitive response type
// no return base type
return [client stringWithCompletionBlock: requestUrl
method: @"PUT"
queryParams: queryParams
body: bodyDictionary
headerParams: headerParams
requestContentType: requestContentType
responseContentType: responseContentType
completionBlock: ^(NSString *data, NSError *error) {
if (error) {
completionBlock(error);
return;
}
completionBlock(nil);
}];
}
-(NSNumber*) addPetWithCompletionBlock: (SWGPet*) body
@ -193,28 +171,6 @@ static NSString * basePath = @"http://petstore.swagger.io/v2";
// primitive response type
// no return base type
return [client stringWithCompletionBlock: requestUrl
method: @"POST"
queryParams: queryParams
body: bodyDictionary
headerParams: headerParams
requestContentType: requestContentType
responseContentType: responseContentType
completionBlock: ^(NSString *data, NSError *error) {
if (error) {
completionBlock(error);
return;
}
completionBlock(nil);
}];
}
-(NSNumber*) findPetsByStatusWithCompletionBlock: (NSArray*) status
@ -443,28 +399,6 @@ static NSString * basePath = @"http://petstore.swagger.io/v2";
// primitive response type
// no return base type
return [client stringWithCompletionBlock: requestUrl
method: @"POST"
queryParams: queryParams
body: bodyDictionary
headerParams: headerParams
requestContentType: requestContentType
responseContentType: responseContentType
completionBlock: ^(NSString *data, NSError *error) {
if (error) {
completionBlock(error);
return;
}
completionBlock(nil);
}];
}
-(NSNumber*) deletePetWithCompletionBlock: (NSString*) api_key
@ -509,28 +443,6 @@ static NSString * basePath = @"http://petstore.swagger.io/v2";
// primitive response type
// no return base type
return [client stringWithCompletionBlock: requestUrl
method: @"DELETE"
queryParams: queryParams
body: bodyDictionary
headerParams: headerParams
requestContentType: requestContentType
responseContentType: responseContentType
completionBlock: ^(NSString *data, NSError *error) {
if (error) {
completionBlock(error);
return;
}
completionBlock(nil);
}];
}
-(NSNumber*) uploadFileWithCompletionBlock: (NSNumber*) petId

View File

@ -303,28 +303,6 @@ static NSString * basePath = @"http://petstore.swagger.io/v2";
// primitive response type
// no return base type
return [client stringWithCompletionBlock: requestUrl
method: @"DELETE"
queryParams: queryParams
body: bodyDictionary
headerParams: headerParams
requestContentType: requestContentType
responseContentType: responseContentType
completionBlock: ^(NSString *data, NSError *error) {
if (error) {
completionBlock(error);
return;
}
completionBlock(nil);
}];
}

View File

@ -554,28 +554,6 @@ static NSString * basePath = @"http://petstore.swagger.io/v2";
// primitive response type
// no return base type
return [client stringWithCompletionBlock: requestUrl
method: @"PUT"
queryParams: queryParams
body: bodyDictionary
headerParams: headerParams
requestContentType: requestContentType
responseContentType: responseContentType
completionBlock: ^(NSString *data, NSError *error) {
if (error) {
completionBlock(error);
return;
}
completionBlock(nil);
}];
}
-(NSNumber*) deleteUserWithCompletionBlock: (NSString*) username
@ -617,28 +595,6 @@ static NSString * basePath = @"http://petstore.swagger.io/v2";
// primitive response type
// no return base type
return [client stringWithCompletionBlock: requestUrl
method: @"DELETE"
queryParams: queryParams
body: bodyDictionary
headerParams: headerParams
requestContentType: requestContentType
responseContentType: responseContentType
completionBlock: ^(NSString *data, NSError *error) {
if (error) {
completionBlock(error);
return;
}
completionBlock(nil);
}];
}

View File

@ -57,6 +57,7 @@ class PetApi {
$body = $body;
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -102,6 +103,7 @@ class PetApi {
$body = $body;
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -146,6 +148,7 @@ class PetApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -196,6 +199,7 @@ class PetApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -247,6 +251,7 @@ class PetApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -297,15 +302,16 @@ class PetApi {
$resourcePath = str_replace("{" . "petId" . "}",
$this->apiClient->toPathValue($petId), $resourcePath);
}
// form params
if ($name !== null) {
$formParams[name] = $name;
}
$formParams['name'] = $this->apiClient->toFormValue($name);
}// form params
if ($status !== null) {
$formParams[status] = $status;
$formParams['status'] = $this->apiClient->toFormValue($status);
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -355,6 +361,7 @@ class PetApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -399,15 +406,16 @@ class PetApi {
$resourcePath = str_replace("{" . "petId" . "}",
$this->apiClient->toPathValue($petId), $resourcePath);
}
// form params
if ($additionalMetadata !== null) {
$formParams[additionalMetadata] = $additionalMetadata;
}
$formParams['additionalMetadata'] = $this->apiClient->toFormValue($additionalMetadata);
}// form params
if ($file !== null) {
$formParams[file] = '@' . $file;
$formParams['file'] = '@' . $this->apiClient->toFormValue($file);
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {

View File

@ -52,6 +52,7 @@ class StoreApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -103,6 +104,7 @@ class StoreApi {
$body = $body;
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -154,6 +156,7 @@ class StoreApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -205,6 +208,7 @@ class StoreApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {

View File

@ -48,6 +48,18 @@ class APIClient {
$this->headerValue = $headerValue;
}
/**
* 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.');
}
$this->user_agent= $user_agent;
}
/**
* @param integer $seconds Number of seconds before timing out [set to 0 for no timeout]
*/
@ -58,7 +70,6 @@ class APIClient {
$this->curl_timout = $seconds;
}
/**
* @param string $resourcePath path to method endpoint
* @param string $method method to call
@ -107,6 +118,9 @@ class APIClient {
if ($method == self::$POST) {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
} else if ($method == self::$PATCH) {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
} else if ($method == self::$PUT) {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
@ -118,25 +132,35 @@ class APIClient {
}
curl_setopt($curl, CURLOPT_URL, $url);
// Set user agent
if ($this->user_agent) {
curl_setopt($curl, CURLOPT_USERAGENT, $this->user_agent);
} else { // use PHP-Swagger as the default user agent
curl_setopt($curl, CURLOPT_USERAGENT, 'PHP-Swagger');
}
// Make the request
$response = curl_exec($curl);
$response_info = curl_getinfo($curl);
// Handle the response
if ($response_info['http_code'] == 0) {
throw new Exception("TIMEOUT: api call to " . $url .
" took more than 5s to return" );
} else if ($response_info['http_code'] == 200) {
throw new APIClientException("TIMEOUT: api call to " . $url .
" took more than 5s to return", 0, $response_info, $response);
} else if ($response_info['http_code'] >= 200 && $response_info['http_code'] <= 299 ) {
$data = json_decode($response);
if (json_last_error() > 0) { // if response is a string
$data = $response;
}
} else if ($response_info['http_code'] == 401) {
throw new Exception("Unauthorized API request to " . $url .
": ".json_decode($response)->message );
throw new APIClientException("Unauthorized API request to " . $url .
": " . serialize($response), 0, $response_info, $response);
} else if ($response_info['http_code'] == 404) {
$data = null;
} else {
throw new Exception("Can't connect to the api: " . $url .
throw new APIClientException("Can't connect to the api: " . $url .
" response code: " .
$response_info['http_code']);
$response_info['http_code'], 0, $response_info, $response);
}
return $data;
}
@ -175,7 +199,7 @@ class APIClient {
* @return string the serialized object
*/
public static function toPathValue($value) {
return rawurlencode($value);
return rawurlencode(toString($value));
}
/**
@ -190,19 +214,47 @@ class APIClient {
if (is_array($object)) {
return implode(',', $object);
} else {
return $object;
return toString($object);
}
}
/**
* Just pass through the header value for now. Placeholder in case we
* find out we need to do something with header values.
* Take value and turn it into a string suitable for inclusion in
* the header. If it's a string, pass through unchanged
* If it's a datetime object, format it in ISO8601
* @param string $value a string which will be part of the header
* @return string the header string
*/
public static function toHeaderValue($value) {
return toString($value);
}
/**
* Take value and turn it into a string suitable for inclusion in
* the http body (form parameter). If it's a string, pass through unchanged
* If it's a datetime object, format it in ISO8601
* @param string $value the value of the form parameter
* @return string the form string
*/
public static function toFormValue($value) {
return toString($value);
}
/**
* Take value and turn it into a string suitable for inclusion in
* the parameter. If it's a string, pass through unchanged
* If it's a datetime object, format it in ISO8601
* @param string $value the value of the parameter
* @return string the header string
*/
public static function toString($value) {
if ($value instanceof \DateTime) { // datetime in ISO8601 format
return $value->format(\DateTime::ISO8601);
}
else {
return $value;
}
}
/**
* Deserialize a JSON string into an object
@ -220,13 +272,14 @@ class APIClient {
$inner = substr($class, 4, -1);
$values = array();
if(strrpos($inner, ",") !== false) {
$subClass = explode(',', $inner, 2)[1];
$subClass_array = explode(',', $inner, 2);
$subClass = $subClass_array[1];
foreach ($data as $key => $value) {
$values[] = array($key => self::deserialize($value, $subClass));
}
}
$deserialized = $values;
} elseif (substr($class, 0, 6) == 'array[') {
} elseif (strcasecmp(substr($class, 0, 6),'array[') == 0) {
$subClass = substr($class, 6, -1);
$values = array();
foreach ($data as $key => $value) {
@ -253,3 +306,20 @@ class APIClient {
}
class APIClientException extends Exception {
protected $response, $response_info;
public function __construct($message="", $code=0, $response_info=null, $response=null) {
parent::__construct($message, $code);
$this->response_info = $response_info;
$this->response = $response;
}
public function getResponse() {
return $this->response;
}
public function getResponseInfo() {
return $this->response_info;
}
}

View File

@ -57,6 +57,7 @@ class UserApi {
$body = $body;
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -102,6 +103,7 @@ class UserApi {
$body = $body;
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -147,6 +149,7 @@ class UserApi {
$body = $body;
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -195,6 +198,7 @@ class UserApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -241,6 +245,7 @@ class UserApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -286,6 +291,7 @@ class UserApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -342,6 +348,7 @@ class UserApi {
$body = $body;
}
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
@ -387,6 +394,7 @@ class UserApi {
// for HTTP post (form)
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {

View File

@ -22,7 +22,7 @@
*
*/
class Category {
class Category implements ArrayAccess {
static $swaggerTypes = array(
'id' => 'int',
'name' => 'string'
@ -31,4 +31,25 @@ class Category {
public $id; /* int */
public $name; /* string */
public function __construct(array $data) {
$this->id = $data["id"];
$this->name = $data["name"];
}
public function offsetExists($offset) {
return isset($this->$offset);
}
public function offsetGet($offset) {
return $this->$offset;
}
public function offsetSet($offset, $value) {
$this->$offset = $value;
}
public function offsetUnset($offset) {
unset($this->$offset);
}
}

View File

@ -22,7 +22,7 @@
*
*/
class Order {
class Order implements ArrayAccess {
static $swaggerTypes = array(
'id' => 'int',
'petId' => 'int',
@ -42,4 +42,29 @@ class Order {
*/
public $status; /* string */
public $complete; /* boolean */
public function __construct(array $data) {
$this->id = $data["id"];
$this->petId = $data["petId"];
$this->quantity = $data["quantity"];
$this->shipDate = $data["shipDate"];
$this->status = $data["status"];
$this->complete = $data["complete"];
}
public function offsetExists($offset) {
return isset($this->$offset);
}
public function offsetGet($offset) {
return $this->$offset;
}
public function offsetSet($offset, $value) {
$this->$offset = $value;
}
public function offsetUnset($offset) {
unset($this->$offset);
}
}

View File

@ -22,7 +22,7 @@
*
*/
class Pet {
class Pet implements ArrayAccess {
static $swaggerTypes = array(
'id' => 'int',
'category' => 'Category',
@ -42,4 +42,29 @@ class Pet {
* pet status in the store
*/
public $status; /* string */
public function __construct(array $data) {
$this->id = $data["id"];
$this->category = $data["category"];
$this->name = $data["name"];
$this->photoUrls = $data["photoUrls"];
$this->tags = $data["tags"];
$this->status = $data["status"];
}
public function offsetExists($offset) {
return isset($this->$offset);
}
public function offsetGet($offset) {
return $this->$offset;
}
public function offsetSet($offset, $value) {
$this->$offset = $value;
}
public function offsetUnset($offset) {
unset($this->$offset);
}
}

View File

@ -22,7 +22,7 @@
*
*/
class Tag {
class Tag implements ArrayAccess {
static $swaggerTypes = array(
'id' => 'int',
'name' => 'string'
@ -31,4 +31,25 @@ class Tag {
public $id; /* int */
public $name; /* string */
public function __construct(array $data) {
$this->id = $data["id"];
$this->name = $data["name"];
}
public function offsetExists($offset) {
return isset($this->$offset);
}
public function offsetGet($offset) {
return $this->$offset;
}
public function offsetSet($offset, $value) {
$this->$offset = $value;
}
public function offsetUnset($offset) {
unset($this->$offset);
}
}

View File

@ -22,7 +22,7 @@
*
*/
class User {
class User implements ArrayAccess {
static $swaggerTypes = array(
'id' => 'int',
'username' => 'string',
@ -46,4 +46,31 @@ class User {
* User Status
*/
public $userStatus; /* int */
public function __construct(array $data) {
$this->id = $data["id"];
$this->username = $data["username"];
$this->firstName = $data["firstName"];
$this->lastName = $data["lastName"];
$this->email = $data["email"];
$this->password = $data["password"];
$this->phone = $data["phone"];
$this->userStatus = $data["userStatus"];
}
public function offsetExists($offset) {
return isset($this->$offset);
}
public function offsetGet($offset) {
return $this->$offset;
}
public function offsetSet($offset, $value) {
$this->$offset = $value;
}
public function offsetUnset($offset) {
unset($this->$offset);
}
}

View File

@ -0,0 +1,391 @@
require "uri"
class PetApi
basePath = "http://petstore.swagger.io/v2"
# apiInvoker = APIInvoker
def self.escapeString(string)
URI.encode(string.to_s)
end
def self.updatePet (body, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:body => body
}.merge(opts)
#resource path
path = "/pet".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
if body != nil
if body.is_a?(Array)
array = Array.new
body.each do |item|
if item.respond_to?("to_body".to_sym)
array.push item.to_body
else
array.push item
end
end
post_body = array
else
if body.respond_to?("to_body".to_sym)
post_body = body.to_body
else
post_body = body
end
end
end
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:PUT, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.addPet (body, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:body => body
}.merge(opts)
#resource path
path = "/pet".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
if body != nil
if body.is_a?(Array)
array = Array.new
body.each do |item|
if item.respond_to?("to_body".to_sym)
array.push item.to_body
else
array.push item
end
end
post_body = array
else
if body.respond_to?("to_body".to_sym)
post_body = body.to_body
else
post_body = body
end
end
end
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:POST, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.findPetsByStatus (status, opts={})
query_param_keys = [:status]
# set default values and merge with input
options = {
:status => status
}.merge(opts)
#resource path
path = "/pet/findByStatus".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
response.map {|response| Pet.new(response) }
end
def self.findPetsByTags (tags, opts={})
query_param_keys = [:tags]
# set default values and merge with input
options = {
:tags => tags
}.merge(opts)
#resource path
path = "/pet/findByTags".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
response.map {|response| Pet.new(response) }
end
def self.getPetById (petId, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:petId => petId
}.merge(opts)
#resource path
path = "/pet/{petId}".sub('{format}','json').sub('{' + 'petId' + '}', escapeString(petId))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
Pet.new(response)
end
def self.updatePetWithForm (petId,name,status, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:petId => petId,
:name => name,
:status => status
}.merge(opts)
#resource path
path = "/pet/{petId}".sub('{format}','json').sub('{' + 'petId' + '}', escapeString(petId))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
form_parameter_hash["name"] = name
form_parameter_hash["status"] = status
Swagger::Request.new(:POST, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.deletePet (api_key,petId, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:api_key => api_key,
:petId => petId
}.merge(opts)
#resource path
path = "/pet/{petId}".sub('{format}','json').sub('{' + 'petId' + '}', escapeString(petId))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
headers[:'api_key'] = api_key
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:DELETE, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.uploadFile (petId,additionalMetadata,file, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:petId => petId,
:additionalMetadata => additionalMetadata,
:file => file
}.merge(opts)
#resource path
path = "/pet/{petId}/uploadImage".sub('{format}','json').sub('{' + 'petId' + '}', escapeString(petId))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
form_parameter_hash["additionalMetadata"] = additionalMetadata
form_parameter_hash["file"] = file
Swagger::Request.new(:POST, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
end

View File

@ -0,0 +1,197 @@
require "uri"
class StoreApi
basePath = "http://petstore.swagger.io/v2"
# apiInvoker = APIInvoker
def self.escapeString(string)
URI.encode(string.to_s)
end
def self.getInventory ( opts={})
query_param_keys = []
# set default values and merge with input
options = {
}.merge(opts)
#resource path
path = "/store/inventory".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
response.map {|response| map.new(response) }
end
def self.placeOrder (body, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:body => body
}.merge(opts)
#resource path
path = "/store/order".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
if body != nil
if body.is_a?(Array)
array = Array.new
body.each do |item|
if item.respond_to?("to_body".to_sym)
array.push item.to_body
else
array.push item
end
end
post_body = array
else
if body.respond_to?("to_body".to_sym)
post_body = body.to_body
else
post_body = body
end
end
end
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:POST, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
Order.new(response)
end
def self.getOrderById (orderId, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:orderId => orderId
}.merge(opts)
#resource path
path = "/store/order/{orderId}".sub('{format}','json').sub('{' + 'orderId' + '}', escapeString(orderId))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
Order.new(response)
end
def self.deleteOrder (orderId, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:orderId => orderId
}.merge(opts)
#resource path
path = "/store/order/{orderId}".sub('{format}','json').sub('{' + 'orderId' + '}', escapeString(orderId))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:DELETE, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
end

View File

@ -0,0 +1,421 @@
require "uri"
class UserApi
basePath = "http://petstore.swagger.io/v2"
# apiInvoker = APIInvoker
def self.escapeString(string)
URI.encode(string.to_s)
end
def self.createUser (body, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:body => body
}.merge(opts)
#resource path
path = "/user".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
if body != nil
if body.is_a?(Array)
array = Array.new
body.each do |item|
if item.respond_to?("to_body".to_sym)
array.push item.to_body
else
array.push item
end
end
post_body = array
else
if body.respond_to?("to_body".to_sym)
post_body = body.to_body
else
post_body = body
end
end
end
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:POST, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.createUsersWithArrayInput (body, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:body => body
}.merge(opts)
#resource path
path = "/user/createWithArray".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
if body != nil
if body.is_a?(Array)
array = Array.new
body.each do |item|
if item.respond_to?("to_body".to_sym)
array.push item.to_body
else
array.push item
end
end
post_body = array
else
if body.respond_to?("to_body".to_sym)
post_body = body.to_body
else
post_body = body
end
end
end
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:POST, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.createUsersWithListInput (body, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:body => body
}.merge(opts)
#resource path
path = "/user/createWithList".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
if body != nil
if body.is_a?(Array)
array = Array.new
body.each do |item|
if item.respond_to?("to_body".to_sym)
array.push item.to_body
else
array.push item
end
end
post_body = array
else
if body.respond_to?("to_body".to_sym)
post_body = body.to_body
else
post_body = body
end
end
end
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:POST, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.loginUser (username,password, opts={})
query_param_keys = [:username,:password]
# set default values and merge with input
options = {
:username => username,
:password => password
}.merge(opts)
#resource path
path = "/user/login".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
string.new(response)
end
def self.logoutUser ( opts={})
query_param_keys = []
# set default values and merge with input
options = {
}.merge(opts)
#resource path
path = "/user/logout".sub('{format}','json')
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.getUserByName (username, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:username => username
}.merge(opts)
#resource path
path = "/user/{username}".sub('{format}','json').sub('{' + 'username' + '}', escapeString(username))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
response = Swagger::Request.new(:GET, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make.body
User.new(response)
end
def self.updateUser (username,body, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:username => username,
:body => body
}.merge(opts)
#resource path
path = "/user/{username}".sub('{format}','json').sub('{' + 'username' + '}', escapeString(username))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
if body != nil
if body.is_a?(Array)
array = Array.new
body.each do |item|
if item.respond_to?("to_body".to_sym)
array.push item.to_body
else
array.push item
end
end
post_body = array
else
if body.respond_to?("to_body".to_sym)
post_body = body.to_body
else
post_body = body
end
end
end
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:PUT, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
def self.deleteUser (username, opts={})
query_param_keys = []
# set default values and merge with input
options = {
:username => username
}.merge(opts)
#resource path
path = "/user/{username}".sub('{format}','json').sub('{' + 'username' + '}', escapeString(username))
# pull querystring keys from options
queryopts = options.select do |key,value|
query_param_keys.include? key
end
# header parameters, if any
headers = {}
# http body (model)
post_body = nil
# form parameters
form_parameter_hash = {}
Swagger::Request.new(:DELETE, path, {:params=>queryopts,:headers=>headers, :body=>post_body, :form_params => form_parameter_hash }).make
end
end

View File

@ -6,7 +6,7 @@ module Swagger
require 'typhoeus'
require "swagger/version"
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers, :form_params
# All requests must have an HTTP method and a path
@ -115,9 +115,18 @@ module Swagger
end
# If body is an object, JSONify it before making the actual request.
#
# For form parameters, remove empty value
def outgoing_body
body.is_a?(String) ? body : body.to_json
# 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
# Construct a query string from the query-string-type params
@ -163,6 +172,13 @@ module Swagger
: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,

View File

@ -2,4 +2,3 @@ module Swagger
VERSION = "4.06.08"
end

View File

@ -1,11 +1,11 @@
class Category
attr_accessor :id, :name
# :internal => :external
def self.attribute_map
{
:id => :id,
:name => :name
:id => :'id',
:name => :'name'
}
end
@ -13,14 +13,15 @@ class Category
def initialize(attributes = {})
return if attributes.empty?
# Morph attribute keys into undescored rubyish style
if self.class.attribute_map[:"id"]
@id = attributes["id"]
end
if self.class.attribute_map[:"name"]
@name = attributes["name"]
end
end
def to_body
@ -31,4 +32,3 @@ class Category
body
end
end

View File

@ -1,14 +1,15 @@
class Order
attr_accessor :id, :pet_id, :quantity, :status, :ship_date
class Order
attr_accessor :id, :petId, :quantity, :shipDate, :status, :complete
# :internal => :external
def self.attribute_map
{
:id => :id,
:pet_id => :petId,
:quantity => :quantity,
:status => :status,
:ship_date => :shipDate
:id => :'id',
:petId => :'petId',
:quantity => :'quantity',
:shipDate => :'shipDate',
:status => :'status',
:complete => :'complete'
}
end
@ -16,22 +17,30 @@ class Order
def initialize(attributes = {})
return if attributes.empty?
# Morph attribute keys into undescored rubyish style
if self.class.attribute_map[:"id"]
@id = attributes["id"]
end
if self.class.attribute_map[:"pet_id"]
@pet_id = attributes["petId"]
if self.class.attribute_map[:"petId"]
@petId = attributes["petId"]
end
if self.class.attribute_map[:"quantity"]
@quantity = attributes["quantity"]
end
if self.class.attribute_map[:"shipDate"]
@shipDate = attributes["shipDate"]
end
if self.class.attribute_map[:"status"]
@status = attributes["status"]
end
if self.class.attribute_map[:"ship_date"]
@ship_date = attributes["shipDate"]
end
if self.class.attribute_map[:"complete"]
@complete = attributes["complete"]
end
end
@ -43,4 +52,3 @@ class Order
body
end
end

View File

@ -1,15 +1,15 @@
class Pet
attr_accessor :id, :category, :name, :photo_urls, :tags, :status
class Pet
attr_accessor :id, :category, :name, :photoUrls, :tags, :status
# :internal => :external
def self.attribute_map
{
:id => :id,
:category => :category,
:name => :name,
:photo_urls => :photoUrls,
:tags => :tags,
:status => :status
:id => :'id',
:category => :'category',
:name => :'name',
:photoUrls => :'photoUrls',
:tags => :'tags',
:status => :'status'
}
end
@ -17,28 +17,35 @@ class Pet
def initialize(attributes = {})
return if attributes.empty?
# Morph attribute keys into undescored rubyish style
if self.class.attribute_map[:"id"]
@id = attributes["id"]
end
if self.class.attribute_map[:"category"]
@category = attributes["category"]
end
if self.class.attribute_map[:"name"]
@name = attributes["name"]
end
if self.class.attribute_map[:"photo_urls"]
if self.class.attribute_map[:"photoUrls"]
if (value = attributes["photoUrls"]).is_a?(Array)
@photo_urls = valueend
@photoUrls = value
end
end
if self.class.attribute_map[:"tags"]
if (value = attributes["tags"]).is_a?(Array)
@tags = value.map{ |v| Tag.new(v) }end
@tags = value.map{ |v| Tag.new(v) }
end
end
if self.class.attribute_map[:"status"]
@status = attributes["status"]
end
end
def to_body
@ -49,4 +56,3 @@ class Pet
body
end
end

View File

@ -1,11 +1,11 @@
class Tag
attr_accessor :id, :name
# :internal => :external
def self.attribute_map
{
:id => :id,
:name => :name
:id => :'id',
:name => :'name'
}
end
@ -13,14 +13,15 @@ class Tag
def initialize(attributes = {})
return if attributes.empty?
# Morph attribute keys into undescored rubyish style
if self.class.attribute_map[:"id"]
@id = attributes["id"]
end
if self.class.attribute_map[:"name"]
@name = attributes["name"]
end
end
def to_body
@ -31,4 +32,3 @@ class Tag
body
end
end

View File

@ -1,17 +1,17 @@
class User
attr_accessor :id, :first_name, :username, :last_name, :email, :password, :phone, :user_status
class User
attr_accessor :id, :username, :firstName, :lastName, :email, :password, :phone, :userStatus
# :internal => :external
def self.attribute_map
{
:id => :id,
:first_name => :firstName,
:username => :username,
:last_name => :lastName,
:email => :email,
:password => :password,
:phone => :phone,
:user_status => :userStatus
:id => :'id',
:username => :'username',
:firstName => :'firstName',
:lastName => :'lastName',
:email => :'email',
:password => :'password',
:phone => :'phone',
:userStatus => :'userStatus'
}
end
@ -19,31 +19,38 @@ class User
def initialize(attributes = {})
return if attributes.empty?
# Morph attribute keys into undescored rubyish style
if self.class.attribute_map[:"id"]
@id = attributes["id"]
end
if self.class.attribute_map[:"first_name"]
@first_name = attributes["firstName"]
end
if self.class.attribute_map[:"username"]
@username = attributes["username"]
end
if self.class.attribute_map[:"last_name"]
@last_name = attributes["lastName"]
if self.class.attribute_map[:"firstName"]
@firstName = attributes["firstName"]
end
if self.class.attribute_map[:"lastName"]
@lastName = attributes["lastName"]
end
if self.class.attribute_map[:"email"]
@email = attributes["email"]
end
if self.class.attribute_map[:"password"]
@password = attributes["password"]
end
if self.class.attribute_map[:"phone"]
@phone = attributes["phone"]
end
if self.class.attribute_map[:"user_status"]
@user_status = attributes["userStatus"]
end
if self.class.attribute_map[:"userStatus"]
@userStatus = attributes["userStatus"]
end
end
@ -55,4 +62,3 @@ class User
body
end
end

View File

@ -0,0 +1,22 @@
module Swagger
class Configuration
require 'swagger/version'
attr_accessor :format, :api_key, :username, :password, :auth_token, :scheme, :host, :base_path, :user_agent, :logger, :inject_format, :force_ending_format, :camelize_params
# Defaults go in here..
def initialize
@format = 'json'
@scheme = 'http'
@host = 'api.wordnik.com'
@base_path = '/v4'
@user_agent = "ruby-#{Swagger::VERSION}"
@inject_format = true
@force_ending_format = false
@camelize_params = true
end
end
end

View File

@ -0,0 +1,199 @@
module Swagger
class Request
require 'uri'
require 'addressable/uri'
require 'typhoeus'
require "swagger/version"
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers
# 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
}
# 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
# 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
# Fill in the path params
self.params.each_pair do |key, value|
p = p.gsub("{#{key}}", value.to_s)
end
# 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.
#
def outgoing_body
body.is_a?(String) ? body : body.to_json
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
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
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 :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
end
end

View File

@ -0,0 +1,70 @@
module Swagger
class Response
require 'json'
attr_accessor :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
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
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

View File

@ -0,0 +1,4 @@
module Swagger
VERSION = "4.06.08"
end

View File

@ -1,5 +1,6 @@
import com.wordnik.petstore.api._
import com.wordnik.petstore.model._
import io.swagger.client._
import io.swagger.client.api._
import io.swagger.client.model._
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
@ -30,7 +31,7 @@ class PetApiTest extends FlatSpec with Matchers {
Category(1, "sold"),
"dragon",
(for (i <- (1 to 10)) yield "http://foo.com/photo/" + i).toList,
(for (i <- (1 to 5)) yield com.wordnik.petstore.model.Tag(i, "tag-" + i)).toList,
(for (i <- (1 to 5)) yield io.swagger.client.model.Tag(i, "tag-" + i)).toList,
"lost"
)
@ -55,7 +56,7 @@ class PetApiTest extends FlatSpec with Matchers {
Category(1, "sold"),
"programmer",
(for (i <- (1 to 10)) yield "http://foo.com/photo/" + i).toList,
(for (i <- (1 to 5)) yield com.wordnik.petstore.model.Tag(i, "tag-" + i)).toList,
(for (i <- (1 to 5)) yield io.swagger.client.model.Tag(i, "tag-" + i)).toList,
"confused"
)
@ -80,7 +81,7 @@ class PetApiTest extends FlatSpec with Matchers {
}
it should "find pets by status" in {
api.findPetsByStatus("available") match {
api.findPetsByStatus(List("available")) match {
case Some(pets) => {
pets.foreach(pet => pet.status should be("available"))
}
@ -90,7 +91,7 @@ class PetApiTest extends FlatSpec with Matchers {
it should "find pets by tag" in {
println("finding by tags")
api.findPetsByTags("tag1,tag2") match {
api.findPetsByTags(List("tag1", "tag2")) match {
case Some(pets) => {
pets.foreach(pet => {
val tags = (for (tag <- pet.tags) yield tag.name).toSet

View File

@ -1,6 +1,6 @@
import com.wordnik.client._
import com.wordnik.petstore.api._
import com.wordnik.petstore.model._
import io.swagger.client._
import io.swagger.client.api._
import io.swagger.client.model._
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
@ -30,13 +30,14 @@ class StoreApiTest extends FlatSpec with Matchers {
}
it should "place an order" in {
val now = new java.util.Date
val now = new org.joda.time.DateTime
val order = Order (
10,
1000,
101,
"pending",
now)
petId = 10,
id = 1000,
quantity = 101,
status = "pending",
shipDate = now,
complete = true)
api.placeOrder(order)
@ -45,20 +46,21 @@ class StoreApiTest extends FlatSpec with Matchers {
order.id should be(1000)
order.petId should be(10)
order.quantity should be(101)
order.shipDate should be (now)
order.shipDate.equals(now) should be (true)
}
case None =>
}
}
it should "delete an order" in {
val now = new java.util.Date
val now = new org.joda.time.DateTime
val order = Order(
1001,
10,
101,
"pending",
now)
id = 1001,
petId = 10,
quantity = 101,
status = "pending",
shipDate = now,
complete = true)
api.placeOrder(order)
@ -67,7 +69,7 @@ class StoreApiTest extends FlatSpec with Matchers {
order.id should be(1001)
order.petId should be(10)
order.quantity should be(101)
order.shipDate should be (now)
order.shipDate.equals(now) should be (true)
}
case None =>
}

View File

@ -1,5 +1,6 @@
import com.wordnik.petstore.api._
import com.wordnik.petstore.model._
import io.swagger.client._
import io.swagger.client.api._
import io.swagger.client.model._
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner

Some files were not shown because too many files have changed in this diff Show More