diff --git a/.gitignore b/.gitignore index b4d421e3c55..cd7e1d286fa 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,9 @@ target .lib atlassian-ide-plugin.xml .DS_Store +packages/ +.pub +.packages samples/client/petstore/php/SwaggerClient-php/composer.lock samples/client/petstore/php/SwaggerClient-php/vendor/ diff --git a/bin/dart-petstore.sh b/bin/dart-petstore.sh new file mode 100644 index 00000000000..387d005132b --- /dev/null +++ b/bin/dart-petstore.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l dart -o samples/client/petstore/dart" + +java $JAVA_OPTS -jar $executable $ags diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/DartClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/DartClientCodegen.java new file mode 100644 index 00000000000..c22e7969e28 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/DartClientCodegen.java @@ -0,0 +1,282 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.CliOption; +import io.swagger.codegen.CodegenConfig; +import io.swagger.codegen.CodegenType; +import io.swagger.codegen.DefaultCodegen; +import io.swagger.codegen.SupportingFile; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.Property; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.HashMap; + +public class DartClientCodegen extends DefaultCodegen implements CodegenConfig { + protected boolean browserClient = true; + protected String pubName = "swagger"; + protected String pubVersion = "1.0.0"; + protected String pubDescription = "Swagger API client"; + protected String sourceFolder = ""; + + public DartClientCodegen() { + super(); + outputFolder = "generated-code/dart"; + modelTemplateFiles.put("model.mustache", ".dart"); + apiTemplateFiles.put("api.mustache", ".dart"); + templateDir = "dart"; + apiPackage = "lib.api"; + modelPackage = "lib.model"; + + reservedWords = new HashSet( + Arrays.asList( + "abstract", "as", "assert", "async", "async*", "await", + "break", "case", "catch", "class", "const", "continue", + "default", "deferred", "do", "dynamic", "else", "enum", + "export", "external", "extends", "factory", "false", "final", + "finally", "for", "get", "if", "implements", "import", "in", + "is", "library", "new", "null", "operator", "part", "rethrow", + "return", "set", "static", "super", "switch", "sync*", "this", + "throw", "true", "try", "typedef", "var", "void", "while", + "with", "yield", "yield*" ) + ); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "bool", + "num", + "int", + "float") + ); + instantiationTypes.put("array", "List"); + instantiationTypes.put("map", "Map"); + + typeMapping = new HashMap(); + typeMapping.put("Array", "List"); + typeMapping.put("array", "List"); + typeMapping.put("List", "List"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "String"); + typeMapping.put("int", "int"); + typeMapping.put("float", "num"); + typeMapping.put("long", "int"); + typeMapping.put("short", "int"); + typeMapping.put("char", "String"); + typeMapping.put("double", "num"); + typeMapping.put("object", "Object"); + typeMapping.put("integer", "int"); + typeMapping.put("Date", "DateTime"); + typeMapping.put("date", "DateTime"); + typeMapping.put("File", "MultipartFile"); + + cliOptions.add(new CliOption("browserClient", "Is the client browser based")); + cliOptions.add(new CliOption("pubName", "Name in generated pubspec")); + cliOptions.add(new CliOption("pubVersion", "Version in generated pubspec")); + cliOptions.add(new CliOption("sourceFolder", "source folder for generated code")); + } + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "dart"; + } + + public String getHelp() { + return "Generates a Dart client library."; + } + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey("browserClient")) { + this.setBrowserClient(Boolean.parseBoolean((String) additionalProperties.get("browserClient"))); + additionalProperties.put("browserClient", browserClient); + } else { + //not set, use to be passed to template + additionalProperties.put("browserClient", browserClient); + } + + if (additionalProperties.containsKey("pubName")) { + this.setPubName((String) additionalProperties.get("pubName")); + } else { + //not set, use to be passed to template + additionalProperties.put("pubName", pubName); + } + + if (additionalProperties.containsKey("pubVersion")) { + this.setPubVersion((String) additionalProperties.get("pubVersion")); + } else { + //not set, use to be passed to template + additionalProperties.put("pubVersion", pubVersion); + } + + if (additionalProperties.containsKey("pubDescription")) { + this.setPubDescription((String) additionalProperties.get("pubDescription")); + } else { + //not set, use to be passed to template + additionalProperties.put("pubDescription", pubDescription); + } + + if (additionalProperties.containsKey("sourceFolder")) { + this.setSourceFolder((String) additionalProperties.get("sourceFolder")); + } + + final String libFolder = sourceFolder + File.separator + "lib"; + supportingFiles.add(new SupportingFile("pubspec.mustache", "", "pubspec.yaml")); + supportingFiles.add(new SupportingFile("api_client.mustache", libFolder, "api_client.dart")); + supportingFiles.add(new SupportingFile("apiException.mustache", libFolder, "api_exception.dart")); + supportingFiles.add(new SupportingFile("apilib.mustache", libFolder, "api.dart")); + + final String authFolder = sourceFolder + File.separator + "auth"; + supportingFiles.add(new SupportingFile("auth/authentication.mustache", authFolder, "authentication.dart")); + supportingFiles.add(new SupportingFile("auth/http_basic_auth.mustache", authFolder, "http_basic_auth.dart")); + supportingFiles.add(new SupportingFile("auth/api_key_auth.mustache", authFolder, "api_key_auth.dart")); + supportingFiles.add(new SupportingFile("auth/oauth.mustache", authFolder, "oauth.dart")); + } + + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar); + } + + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar); + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } + + // camelize (lower first character) the variable name + // pet_id => petId + name = camelize(name, true); + + // for reserved word or word starting with number, append _ + if (reservedWords.contains(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } + + return name; + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toModelName(String name) { + // model name cannot use reserved keyword, e.g. return + if (reservedWords.contains(name)) { + throw new RuntimeException(name + " (reserved word) cannot be used as a model name"); + } + + // camelize the model name + // phone_number => PhoneNumber + return camelize(name); + } + + @Override + public String toModelFilename(String name) { + return underscore(toModelName(name)); + } + + @Override + public String toApiFilename(String name) { + return underscore(toApiName(name)); + } + + @Override + public String toDefaultValue(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "{}"; + } else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "[]"; + } + + return super.toDefaultValue(p); + } + + @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) + ""; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if (typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if (languageSpecificPrimitives.contains(type)) { + return type; + } + } else { + type = swaggerType; + } + return toModelName(type); + } + + @Override + public String toOperationId(String operationId) { + // method name cannot use reserved keyword, e.g. return + if (reservedWords.contains(operationId)) { + throw new RuntimeException(operationId + " (reserved word) cannot be used as method name"); + } + + return camelize(operationId, true); + } + + public void setBrowserClient(boolean browserClient) { + this.browserClient = browserClient; + } + + public void setPubName(String pubName) { + this.pubName = pubName; + } + + public void setPubVersion(String pubVersion) { + this.pubVersion = pubVersion; + } + + public void setPubDescription(String pubDescription) { + this.pubDescription = pubDescription; + } + + public void setSourceFolder(String sourceFolder) { + this.sourceFolder = sourceFolder; + } +} diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig index e98ac462230..a73fe5f4388 100644 --- a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -1,6 +1,7 @@ io.swagger.codegen.languages.AndroidClientCodegen io.swagger.codegen.languages.AsyncScalaClientCodegen io.swagger.codegen.languages.CSharpClientCodegen +io.swagger.codegen.languages.DartClientCodegen io.swagger.codegen.languages.FlashClientCodegen io.swagger.codegen.languages.JavaClientCodegen io.swagger.codegen.languages.JaxRSServerCodegen diff --git a/modules/swagger-codegen/src/main/resources/dart/api.mustache b/modules/swagger-codegen/src/main/resources/dart/api.mustache new file mode 100644 index 00000000000..51216a11c95 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/api.mustache @@ -0,0 +1,83 @@ +part of api; + +{{#operations}} + +class {{classname}} { + String basePath = "{{basePath}}"; + ApiClient apiClient = ApiClient.defaultApiClient; + + {{classname}}([ApiClient apiClient]) { + if (apiClient != null) { + this.apiClient = apiClient; + } + } + + {{#operation}} + /// {{summary}} + /// + /// {{notes}} + {{#returnType}}Future<{{{returnType}}}> {{/returnType}}{{^returnType}}Future {{/returnType}}{{nickname}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) { + Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + {{#requiredParamCount}} + // verify required params are set + if({{/requiredParamCount}}{{#requiredParams}} {{paramName}} == null {{#hasMore}}|| {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) { + throw new ApiException(400, "missing required params"); + }{{/requiredParamCount}} + + // create path and map variables + String path = "{{path}}".replaceAll("{format}","json"){{#pathParams}}.replaceAll("{" + "{{paramName}}" + "}", {{{paramName}}}.toString()){{/pathParams}}; + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + {{#queryParams}}if("null" != {{paramName}}) + queryParams["{{baseName}}"] = {{paramName}} is List ? {{paramName}}.join(',') : {{paramName}}; + {{/queryParams}} + {{#headerParams}}headerParams["{{baseName}}"] = {{paramName}}; + {{/headerParams}} + + List contentTypes = [{{#consumes}}"{{mediaType}}"{{#hasMore}},{{/hasMore}}{{/consumes}}]; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = [{{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}}]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + {{#formParams}}{{#notFile}} + if ({{paramName}} != null) { + hasFields = true; + mp.fields['{{baseName}}'] = apiClient.parameterToString({{paramName}}); + } + {{/notFile}}{{#isFile}} + if ({{paramName}} != null) { + hasFields = true; + mp.fields['{{baseName}}'] = {{paramName}}.field; + mp.files.add({{paramName}}); + } + {{/isFile}}{{/formParams}} + if(hasFields) + postBody = mp; + } + else { + {{#formParams}}{{#notFile}}if ({{paramName}} != null) + formParams['{{baseName}}'] = apiClient.parameterToString({{paramName}});{{/notFile}} + {{/formParams}} + } + + return apiClient.invokeAPI(basePath, path, '{{httpMethod}}', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return {{#returnType}}ApiClient.deserialize(response.body, {{returnBaseType}}){{/returnType}}; + } + else { + return {{#returnType}}null{{/returnType}}; + } + }); + } + {{/operation}} +} +{{/operations}} diff --git a/modules/swagger-codegen/src/main/resources/dart/apiException.mustache b/modules/swagger-codegen/src/main/resources/dart/apiException.mustache new file mode 100644 index 00000000000..c168fb512da --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/apiException.mustache @@ -0,0 +1,9 @@ +part of api; + +class ApiException implements Exception { + int code = 0; + String message = null; + + ApiException(this.code, this.message); + +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/dart/api_client.mustache b/modules/swagger-codegen/src/main/resources/dart/api_client.mustache new file mode 100644 index 00000000000..92fa90d6261 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/api_client.mustache @@ -0,0 +1,160 @@ +part of api; + +class ApiClient { + static ApiClient defaultApiClient = new ApiClient(); + + Map _defaultHeaderMap = {}; + Map _authentications = {}; + static final dson = new Dartson.JSON(); + final DateFormat _dateFormatter = new DateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + ApiClient() { + // Setup authentications (key: authentication name, value: authentication).{{#authMethods}}{{#isBasic}} + _authentications['{{name}}'] = new HttpBasicAuth();{{/isBasic}}{{#isApiKey}} + _authentications['{{name}}'] = new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}");{{/isApiKey}}{{#isOAuth}} + _authentications['{{name}}'] = new OAuth();{{/isOAuth}}{{/authMethods}} + } + + void addDefaultHeader(String key, String value) { + _defaultHeaderMap[key] = value; + } + + /// Format the given Date object into string. + String formatDate(DateTime date) { + return _dateFormatter.format(date); + } + + /// Format the given parameter object into string. + String parameterToString(Object param) { + if (param == null) { + return ''; + } else if (param is DateTime) { + return formatDate(param); + } else if (param is List) { + return (param).join(','); + } else { + return param.toString(); + } + } + + static dynamic deserialize(String json, dynamic clazz) { + var result = json; + + try { + var decodedJson = JSON.decode(json); + + if(decodedJson is List) { + result = []; + for(var obj in decodedJson) { + result.add(_createEntity(obj, clazz)); + } + } else { + result = _createEntity(json, clazz); + } + } on FormatException { + // Just return the passed in value + } + + return result; + } + + static dynamic _createEntity(dynamic json, dynamic clazz) { + bool isMap = json is Map; + + switch(clazz) { + {{#models}} + {{#model}} + case {{classname}}: + return isMap ? dson.map(json, new {{classname}}()) : dson.decode(json, new {{classname}}()); + {{/model}} + {{/models}} + default: + throw new ApiException(500, 'Could not find a suitable class for deserialization'); + } + } + + static String serialize(Object obj) { + String serialized = ''; + if (obj == null) { + serialized = ''; + } else if (obj is String) { + serialized = obj; + } else { + serialized = dson.encode(obj); + } + return serialized; + } + + Future invokeAPI( String host, + String path, + String method, + Map queryParams, + Object body, + Map headerParams, + Map formParams, + String contentType, + List authNames) { + + updateParamsForAuth(authNames, queryParams, headerParams); + + var client = new {{#browserClient}}Browser{{/browserClient}}Client(); + + StringBuffer sb = new StringBuffer(); + + for(String key in queryParams.keys) { + String value = queryParams[key]; + if (value != null){ + if(sb.toString().length == 0) { + sb.write("?"); + } else { + sb.write("&"); + } + sb.write(key); + sb.write("="); + sb.write(value); + } + } + String querystring = sb.toString(); + + String url = host + path + querystring; + + headerParams.addAll(_defaultHeaderMap); + headerParams['Content-Type'] = contentType; + + var completer = new Completer(); + + if(body is MultipartRequest) { + var request = new MultipartRequest(method, Uri.parse(url)); + request.fields.addAll(body.fields); + request.files.addAll(body.files); + request.headers.addAll(body.headers); + request.headers.addAll(headerParams); + client.send(request).then((response) => completer.complete(Response.fromStream(response))); + } else { + var msgBody = contentType == "application/x-www-form-urlencoded" ? formParams : serialize(body); + switch(method) { + case "GET": + return client.get(url, headers: headerParams); + case "POST": + return client.post(url, headers: headerParams, body: msgBody); + case "PUT": + return client.put(url, headers: headerParams, body: msgBody); + case "DELETE": + return client.delete(url, headers: headerParams); + } + } + + return completer.future; + } + + /// Update query and header parameters based on authentication settings. + /// @param authNames The authentications to apply + void updateParamsForAuth(List authNames, Map queryParams, Map headerParams) { + authNames.forEach((authName) { + Authentication auth = _authentications[authName]; + if (auth == null) throw new ArgumentError("Authentication undefined: " + authName); + auth.applyToParams(queryParams, headerParams); + }); + } + +} diff --git a/modules/swagger-codegen/src/main/resources/dart/apilib.mustache b/modules/swagger-codegen/src/main/resources/dart/apilib.mustache new file mode 100644 index 00000000000..f9699315566 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/apilib.mustache @@ -0,0 +1,22 @@ +library api; + +import 'dart:async'; +import 'dart:convert';{{#browserClient}} +import 'dart:html'; +import 'package:http/browser_client.dart';{{/browserClient}} +import 'package:http/http.dart'; +import 'package:dartson/dartson.dart'; +import 'package:crypto/crypto.dart'; +import 'package:intl/intl.dart'; + +part 'api_client.dart'; +part 'api_exception.dart'; +part 'auth/authentication.dart'; +part 'auth/api_key_auth.dart'; +part 'auth/oauth.dart'; +part 'auth/http_basic_auth.dart'; + +{{#apiInfo}}{{#apis}}part 'api/{{classVarName}}_api.dart'; +{{/apis}}{{/apiInfo}} +{{#models}}{{#model}}part 'model/{{classVarName}}.dart'; +{{/model}}{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/dart/auth/api_key_auth.mustache b/modules/swagger-codegen/src/main/resources/dart/auth/api_key_auth.mustache new file mode 100644 index 00000000000..6e728ae916b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/auth/api_key_auth.mustache @@ -0,0 +1,28 @@ +part of api; + +class ApiKeyAuth implements Authentication { + + final String location; + final String paramName; + String apiKey; + String apiKeyPrefix; + + ApiKeyAuth(this.location, this.paramName); + + @override + void applyToParams(Map queryParams, Map headerParams) { + String value; + if (apiKeyPrefix != null) { + value = '$apiKeyPrefix $apiKey'; + } else { + value = apiKey; + } + + if (location == 'query' && value != null) { + queryParams[paramName] = value; + } else if (location == 'header' && value != null) { + headerParams[paramName] = value; + } + } + +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/dart/auth/authentication.mustache b/modules/swagger-codegen/src/main/resources/dart/auth/authentication.mustache new file mode 100644 index 00000000000..4833af90ec0 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/auth/authentication.mustache @@ -0,0 +1,7 @@ +part of api; + +abstract class Authentication { + + /// Apply authentication settings to header and query params. + void applyToParams(Map queryParams, Map headerParams); +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/dart/auth/http_basic_auth.mustache b/modules/swagger-codegen/src/main/resources/dart/auth/http_basic_auth.mustache new file mode 100644 index 00000000000..e681c25653d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/auth/http_basic_auth.mustache @@ -0,0 +1,14 @@ +part of api; + +class HttpBasicAuth implements Authentication { + + String username; + String password; + + @override + void applyToParams(Map queryParams, Map headerParams) { + String str = (username == null ? "" : username) + ":" + (password == null ? "" : password); + headerParams["Authorization"] = "Basic " + CryptoUtils.bytesToBase64(UTF8.encode(str)); + } + +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/dart/auth/oauth.mustache b/modules/swagger-codegen/src/main/resources/dart/auth/oauth.mustache new file mode 100644 index 00000000000..5e3e2c8b260 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/auth/oauth.mustache @@ -0,0 +1,9 @@ +part of api; + +class OAuth implements Authentication { + + @override + void applyToParams(Map queryParams, Map headerParams) { + // TODO: support oauth + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/dart/model.mustache b/modules/swagger-codegen/src/main/resources/dart/model.mustache new file mode 100644 index 00000000000..c0c4789c00b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/model.mustache @@ -0,0 +1,18 @@ +part of api; + +{{#models}}{{#model}} +@Entity() +class {{classname}} { + {{#vars}}{{#description}}/* {{{description}}} */{{/description}} + {{{datatype}}} {{name}} = {{{defaultValue}}}; + {{#allowableValues}}{{#min}} // range from {{min}} to {{max}}{{/min}}//{{^min}}enum {{name}}Enum { {{#values}} {{.}}, {{/values}} };{{/min}}{{/allowableValues}} + {{/vars}} + {{classname}}(); + + @override + String toString() { + return '{{classname}}[{{#vars}}{{name}}=${{name}}, {{/vars}}]'; + } + +} +{{/model}}{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/dart/pubspec.mustache b/modules/swagger-codegen/src/main/resources/dart/pubspec.mustache new file mode 100644 index 00000000000..97bf9c1defd --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/dart/pubspec.mustache @@ -0,0 +1,15 @@ +name: {{pubName}} +version: {{pubVersion}} +description: {{pubDescription}} +dependencies: + http: '>=0.11.1 <0.12.0' + dartson: "^0.2.4" + crypto: "^0.9.0" + intl: "^0.12.4+2" + +dev_dependencies: + guinness: '^0.1.17' + browser: any + +transformers: + - dartson diff --git a/samples/client/petstore/dart/auth/api_key_auth.dart b/samples/client/petstore/dart/auth/api_key_auth.dart new file mode 100644 index 00000000000..6e728ae916b --- /dev/null +++ b/samples/client/petstore/dart/auth/api_key_auth.dart @@ -0,0 +1,28 @@ +part of api; + +class ApiKeyAuth implements Authentication { + + final String location; + final String paramName; + String apiKey; + String apiKeyPrefix; + + ApiKeyAuth(this.location, this.paramName); + + @override + void applyToParams(Map queryParams, Map headerParams) { + String value; + if (apiKeyPrefix != null) { + value = '$apiKeyPrefix $apiKey'; + } else { + value = apiKey; + } + + if (location == 'query' && value != null) { + queryParams[paramName] = value; + } else if (location == 'header' && value != null) { + headerParams[paramName] = value; + } + } + +} \ No newline at end of file diff --git a/samples/client/petstore/dart/auth/authentication.dart b/samples/client/petstore/dart/auth/authentication.dart new file mode 100644 index 00000000000..4833af90ec0 --- /dev/null +++ b/samples/client/petstore/dart/auth/authentication.dart @@ -0,0 +1,7 @@ +part of api; + +abstract class Authentication { + + /// Apply authentication settings to header and query params. + void applyToParams(Map queryParams, Map headerParams); +} \ No newline at end of file diff --git a/samples/client/petstore/dart/auth/http_basic_auth.dart b/samples/client/petstore/dart/auth/http_basic_auth.dart new file mode 100644 index 00000000000..e681c25653d --- /dev/null +++ b/samples/client/petstore/dart/auth/http_basic_auth.dart @@ -0,0 +1,14 @@ +part of api; + +class HttpBasicAuth implements Authentication { + + String username; + String password; + + @override + void applyToParams(Map queryParams, Map headerParams) { + String str = (username == null ? "" : username) + ":" + (password == null ? "" : password); + headerParams["Authorization"] = "Basic " + CryptoUtils.bytesToBase64(UTF8.encode(str)); + } + +} \ No newline at end of file diff --git a/samples/client/petstore/dart/auth/oauth.dart b/samples/client/petstore/dart/auth/oauth.dart new file mode 100644 index 00000000000..5e3e2c8b260 --- /dev/null +++ b/samples/client/petstore/dart/auth/oauth.dart @@ -0,0 +1,9 @@ +part of api; + +class OAuth implements Authentication { + + @override + void applyToParams(Map queryParams, Map headerParams) { + // TODO: support oauth + } +} \ No newline at end of file diff --git a/samples/client/petstore/dart/lib/api.dart b/samples/client/petstore/dart/lib/api.dart new file mode 100644 index 00000000000..3dba4e66eef --- /dev/null +++ b/samples/client/petstore/dart/lib/api.dart @@ -0,0 +1,27 @@ +library api; + +import 'dart:async'; +import 'dart:convert'; +import 'dart:html'; +import 'package:http/browser_client.dart'; +import 'package:http/http.dart'; +import 'package:dartson/dartson.dart'; +import 'package:crypto/crypto.dart'; +import 'package:intl/intl.dart'; + +part 'api_client.dart'; +part 'api_exception.dart'; +part 'auth/authentication.dart'; +part 'auth/api_key_auth.dart'; +part 'auth/oauth.dart'; +part 'auth/http_basic_auth.dart'; + +part 'api/user_api.dart'; +part 'api/store_api.dart'; +part 'api/pet_api.dart'; + +part 'model/user.dart'; +part 'model/category.dart'; +part 'model/pet.dart'; +part 'model/tag.dart'; +part 'model/order.dart'; diff --git a/samples/client/petstore/dart/lib/api/pet_api.dart b/samples/client/petstore/dart/lib/api/pet_api.dart new file mode 100644 index 00000000000..b800b535d84 --- /dev/null +++ b/samples/client/petstore/dart/lib/api/pet_api.dart @@ -0,0 +1,418 @@ +part of api; + + + +class PetApi { + String basePath = "http://petstore.swagger.io/v2"; + ApiClient apiClient = ApiClient.defaultApiClient; + + PetApi([ApiClient apiClient]) { + if (apiClient != null) { + this.apiClient = apiClient; + } + } + + + /// Update an existing pet + /// + /// + Future updatePet(Pet body) { + Object postBody = body; + + + // create path and map variables + String path = "/pet".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = ["application/json","application/xml"]; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'PUT', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Add a new pet to the store + /// + /// + Future addPet(Pet body) { + Object postBody = body; + + + // create path and map variables + String path = "/pet".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = ["application/json","application/xml"]; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'POST', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Finds Pets by status + /// + /// Multiple status values can be provided with comma seperated strings + Future> findPetsByStatus(List status) { + Object postBody = null; + + + // create path and map variables + String path = "/pet/findByStatus".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + if("null" != status) + queryParams["status"] = status is List ? status.join(',') : status; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, Pet); + } + else { + return null; + } + }); + } + + /// Finds Pets by tags + /// + /// Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing. + Future> findPetsByTags(List tags) { + Object postBody = null; + + + // create path and map variables + String path = "/pet/findByTags".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + if("null" != tags) + queryParams["tags"] = tags is List ? tags.join(',') : tags; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, Pet); + } + else { + return null; + } + }); + } + + /// Find pet by ID + /// + /// Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions + Future getPetById(int petId) { + Object postBody = null; + + + // create path and map variables + String path = "/pet/{petId}".replaceAll("{format}","json").replaceAll("{" + "petId" + "}", petId.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth", "api_key"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, Pet); + } + else { + return null; + } + }); + } + + /// Updates a pet in the store with form data + /// + /// + Future updatePetWithForm(String petId, String name, String status) { + Object postBody = null; + + + // create path and map variables + String path = "/pet/{petId}".replaceAll("{format}","json").replaceAll("{" + "petId" + "}", petId.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = ["application/x-www-form-urlencoded"]; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if (name != null) { + hasFields = true; + mp.fields['name'] = apiClient.parameterToString(name); + } + + if (status != null) { + hasFields = true; + mp.fields['status'] = apiClient.parameterToString(status); + } + + if(hasFields) + postBody = mp; + } + else { + if (name != null) + formParams['name'] = apiClient.parameterToString(name); + if (status != null) + formParams['status'] = apiClient.parameterToString(status); + + } + + return apiClient.invokeAPI(basePath, path, 'POST', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Deletes a pet + /// + /// + Future deletePet(int petId, String apiKey) { + Object postBody = null; + + + // create path and map variables + String path = "/pet/{petId}".replaceAll("{format}","json").replaceAll("{" + "petId" + "}", petId.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + headerParams["api_key"] = apiKey; + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'DELETE', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// uploads an image + /// + /// + Future uploadFile(int petId, String additionalMetadata, MultipartFile file) { + Object postBody = null; + + + // create path and map variables + String path = "/pet/{petId}/uploadImage".replaceAll("{format}","json").replaceAll("{" + "petId" + "}", petId.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = ["multipart/form-data"]; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["petstore_auth"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if (additionalMetadata != null) { + hasFields = true; + mp.fields['additionalMetadata'] = apiClient.parameterToString(additionalMetadata); + } + + if (file != null) { + hasFields = true; + mp.fields['file'] = file.field; + mp.files.add(file); + } + + if(hasFields) + postBody = mp; + } + else { + if (additionalMetadata != null) + formParams['additionalMetadata'] = apiClient.parameterToString(additionalMetadata); + + + } + + return apiClient.invokeAPI(basePath, path, 'POST', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + +} + diff --git a/samples/client/petstore/dart/lib/api/store_api.dart b/samples/client/petstore/dart/lib/api/store_api.dart new file mode 100644 index 00000000000..fb346e317ee --- /dev/null +++ b/samples/client/petstore/dart/lib/api/store_api.dart @@ -0,0 +1,201 @@ +part of api; + + + +class StoreApi { + String basePath = "http://petstore.swagger.io/v2"; + ApiClient apiClient = ApiClient.defaultApiClient; + + StoreApi([ApiClient apiClient]) { + if (apiClient != null) { + this.apiClient = apiClient; + } + } + + + /// Returns pet inventories by status + /// + /// Returns a map of status codes to quantities + Future> getInventory() { + Object postBody = null; + + + // create path and map variables + String path = "/store/inventory".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = ["api_key"]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, Map); + } + else { + return null; + } + }); + } + + /// Place an order for a pet + /// + /// + Future placeOrder(Order body) { + Object postBody = body; + + + // create path and map variables + String path = "/store/order".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'POST', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, Order); + } + else { + return null; + } + }); + } + + /// Find purchase order by ID + /// + /// For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions + Future getOrderById(String orderId) { + Object postBody = null; + + + // create path and map variables + String path = "/store/order/{orderId}".replaceAll("{format}","json").replaceAll("{" + "orderId" + "}", orderId.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, Order); + } + else { + return null; + } + }); + } + + /// Delete purchase order by ID + /// + /// For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + Future deleteOrder(String orderId) { + Object postBody = null; + + + // create path and map variables + String path = "/store/order/{orderId}".replaceAll("{format}","json").replaceAll("{" + "orderId" + "}", orderId.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'DELETE', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + +} + diff --git a/samples/client/petstore/dart/lib/api/user_api.dart b/samples/client/petstore/dart/lib/api/user_api.dart new file mode 100644 index 00000000000..b8e7bc0f149 --- /dev/null +++ b/samples/client/petstore/dart/lib/api/user_api.dart @@ -0,0 +1,389 @@ +part of api; + + + +class UserApi { + String basePath = "http://petstore.swagger.io/v2"; + ApiClient apiClient = ApiClient.defaultApiClient; + + UserApi([ApiClient apiClient]) { + if (apiClient != null) { + this.apiClient = apiClient; + } + } + + + /// Create user + /// + /// This can only be done by the logged in user. + Future createUser(User body) { + Object postBody = body; + + + // create path and map variables + String path = "/user".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'POST', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Creates list of users with given input array + /// + /// + Future createUsersWithArrayInput(List body) { + Object postBody = body; + + + // create path and map variables + String path = "/user/createWithArray".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'POST', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Creates list of users with given input array + /// + /// + Future createUsersWithListInput(List body) { + Object postBody = body; + + + // create path and map variables + String path = "/user/createWithList".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'POST', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Logs user into the system + /// + /// + Future loginUser(String username, String password) { + Object postBody = null; + + + // create path and map variables + String path = "/user/login".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + if("null" != username) + queryParams["username"] = username is List ? username.join(',') : username; + if("null" != password) + queryParams["password"] = password is List ? password.join(',') : password; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, String); + } + else { + return null; + } + }); + } + + /// Logs out current logged in user session + /// + /// + Future logoutUser() { + Object postBody = null; + + + // create path and map variables + String path = "/user/logout".replaceAll("{format}","json"); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Get user by user name + /// + /// + Future getUserByName(String username) { + Object postBody = null; + + + // create path and map variables + String path = "/user/{username}".replaceAll("{format}","json").replaceAll("{" + "username" + "}", username.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'GET', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ApiClient.deserialize(response.body, User); + } + else { + return null; + } + }); + } + + /// Updated user + /// + /// This can only be done by the logged in user. + Future updateUser(String username, User body) { + Object postBody = body; + + + // create path and map variables + String path = "/user/{username}".replaceAll("{format}","json").replaceAll("{" + "username" + "}", username.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'PUT', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + + /// Delete user + /// + /// This can only be done by the logged in user. + Future deleteUser(String username) { + Object postBody = null; + + + // create path and map variables + String path = "/user/{username}".replaceAll("{format}","json").replaceAll("{" + "username" + "}", username.toString()); + + // query params + Map queryParams = {}; + Map headerParams = {}; + Map formParams = {}; + + + + List contentTypes = []; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = []; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + + if(hasFields) + postBody = mp; + } + else { + + } + + return apiClient.invokeAPI(basePath, path, 'DELETE', queryParams, postBody, headerParams, formParams, contentType, authNames).then((response) { + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } + else if(response.body != null){ + return ; + } + else { + return ; + } + }); + } + +} + diff --git a/samples/client/petstore/dart/lib/api_client.dart b/samples/client/petstore/dart/lib/api_client.dart new file mode 100644 index 00000000000..82cecd7db49 --- /dev/null +++ b/samples/client/petstore/dart/lib/api_client.dart @@ -0,0 +1,179 @@ +part of api; + +class ApiClient { + static ApiClient defaultApiClient = new ApiClient(); + + Map _defaultHeaderMap = {}; + Map _authentications = {}; + static final dson = new Dartson.JSON(); + final DateFormat _dateFormatter = new DateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + ApiClient() { + // Setup authentications (key: authentication name, value: authentication). + _authentications['api_key'] = new ApiKeyAuth("header", "api_key"); + _authentications['petstore_auth'] = new OAuth(); + } + + void addDefaultHeader(String key, String value) { + _defaultHeaderMap[key] = value; + } + + /// Format the given Date object into string. + String formatDate(DateTime date) { + return _dateFormatter.format(date); + } + + /// Format the given parameter object into string. + String parameterToString(Object param) { + if (param == null) { + return ''; + } else if (param is DateTime) { + return formatDate(param); + } else if (param is List) { + return (param).join(','); + } else { + return param.toString(); + } + } + + static dynamic deserialize(String json, dynamic clazz) { + var result = json; + + try { + var decodedJson = JSON.decode(json); + + if(decodedJson is List) { + result = []; + for(var obj in decodedJson) { + result.add(_createEntity(obj, clazz)); + } + } else { + result = _createEntity(json, clazz); + } + } on FormatException { + // Just return the passed in value + } + + return result; + } + + static dynamic _createEntity(dynamic json, dynamic clazz) { + bool isMap = json is Map; + + switch(clazz) { + + + case User: + return isMap ? dson.map(json, new User()) : dson.decode(json, new User()); + + + + case Category: + return isMap ? dson.map(json, new Category()) : dson.decode(json, new Category()); + + + + case Pet: + return isMap ? dson.map(json, new Pet()) : dson.decode(json, new Pet()); + + + + case Tag: + return isMap ? dson.map(json, new Tag()) : dson.decode(json, new Tag()); + + + + case Order: + return isMap ? dson.map(json, new Order()) : dson.decode(json, new Order()); + + + default: + throw new ApiException(500, 'Could not find a suitable class for deserialization'); + } + } + + static String serialize(Object obj) { + String serialized = ''; + if (obj == null) { + serialized = ''; + } else if (obj is String) { + serialized = obj; + } else { + serialized = dson.encode(obj); + } + return serialized; + } + + Future invokeAPI( String host, + String path, + String method, + Map queryParams, + Object body, + Map headerParams, + Map formParams, + String contentType, + List authNames) { + + updateParamsForAuth(authNames, queryParams, headerParams); + + var client = new BrowserClient(); + + StringBuffer sb = new StringBuffer(); + + for(String key in queryParams.keys) { + String value = queryParams[key]; + if (value != null){ + if(sb.toString().length == 0) { + sb.write("?"); + } else { + sb.write("&"); + } + sb.write(key); + sb.write("="); + sb.write(value); + } + } + String querystring = sb.toString(); + + String url = host + path + querystring; + + headerParams.addAll(_defaultHeaderMap); + headerParams['Content-Type'] = contentType; + + var completer = new Completer(); + + if(body is MultipartRequest) { + var request = new MultipartRequest(method, Uri.parse(url)); + request.fields.addAll(body.fields); + request.files.addAll(body.files); + request.headers.addAll(body.headers); + request.headers.addAll(headerParams); + client.send(request).then((response) => completer.complete(Response.fromStream(response))); + } else { + var msgBody = contentType == "application/x-www-form-urlencoded" ? formParams : serialize(body); + switch(method) { + case "GET": + return client.get(url, headers: headerParams); + case "POST": + return client.post(url, headers: headerParams, body: msgBody); + case "PUT": + return client.put(url, headers: headerParams, body: msgBody); + case "DELETE": + return client.delete(url, headers: headerParams); + } + } + + return completer.future; + } + + /// Update query and header parameters based on authentication settings. + /// @param authNames The authentications to apply + void updateParamsForAuth(List authNames, Map queryParams, Map headerParams) { + authNames.forEach((authName) { + Authentication auth = _authentications[authName]; + if (auth == null) throw new ArgumentError("Authentication undefined: " + authName); + auth.applyToParams(queryParams, headerParams); + }); + } + +} diff --git a/samples/client/petstore/dart/lib/api_exception.dart b/samples/client/petstore/dart/lib/api_exception.dart new file mode 100644 index 00000000000..c168fb512da --- /dev/null +++ b/samples/client/petstore/dart/lib/api_exception.dart @@ -0,0 +1,9 @@ +part of api; + +class ApiException implements Exception { + int code = 0; + String message = null; + + ApiException(this.code, this.message); + +} \ No newline at end of file diff --git a/samples/client/petstore/dart/lib/auth/api_key_auth.dart b/samples/client/petstore/dart/lib/auth/api_key_auth.dart new file mode 100644 index 00000000000..6e728ae916b --- /dev/null +++ b/samples/client/petstore/dart/lib/auth/api_key_auth.dart @@ -0,0 +1,28 @@ +part of api; + +class ApiKeyAuth implements Authentication { + + final String location; + final String paramName; + String apiKey; + String apiKeyPrefix; + + ApiKeyAuth(this.location, this.paramName); + + @override + void applyToParams(Map queryParams, Map headerParams) { + String value; + if (apiKeyPrefix != null) { + value = '$apiKeyPrefix $apiKey'; + } else { + value = apiKey; + } + + if (location == 'query' && value != null) { + queryParams[paramName] = value; + } else if (location == 'header' && value != null) { + headerParams[paramName] = value; + } + } + +} \ No newline at end of file diff --git a/samples/client/petstore/dart/lib/auth/authentication.dart b/samples/client/petstore/dart/lib/auth/authentication.dart new file mode 100644 index 00000000000..b4aa90651f6 --- /dev/null +++ b/samples/client/petstore/dart/lib/auth/authentication.dart @@ -0,0 +1,6 @@ +part of api; + +abstract class Authentication { + + void applyToParams(Map queryParams, Map headerParams); +} \ No newline at end of file diff --git a/samples/client/petstore/dart/lib/auth/http_basic_auth.dart b/samples/client/petstore/dart/lib/auth/http_basic_auth.dart new file mode 100644 index 00000000000..e681c25653d --- /dev/null +++ b/samples/client/petstore/dart/lib/auth/http_basic_auth.dart @@ -0,0 +1,14 @@ +part of api; + +class HttpBasicAuth implements Authentication { + + String username; + String password; + + @override + void applyToParams(Map queryParams, Map headerParams) { + String str = (username == null ? "" : username) + ":" + (password == null ? "" : password); + headerParams["Authorization"] = "Basic " + CryptoUtils.bytesToBase64(UTF8.encode(str)); + } + +} \ No newline at end of file diff --git a/samples/client/petstore/dart/lib/auth/oauth.dart b/samples/client/petstore/dart/lib/auth/oauth.dart new file mode 100644 index 00000000000..5e3e2c8b260 --- /dev/null +++ b/samples/client/petstore/dart/lib/auth/oauth.dart @@ -0,0 +1,9 @@ +part of api; + +class OAuth implements Authentication { + + @override + void applyToParams(Map queryParams, Map headerParams) { + // TODO: support oauth + } +} \ No newline at end of file diff --git a/samples/client/petstore/dart/lib/model/category.dart b/samples/client/petstore/dart/lib/model/category.dart new file mode 100644 index 00000000000..d036a2b186a --- /dev/null +++ b/samples/client/petstore/dart/lib/model/category.dart @@ -0,0 +1,21 @@ +part of api; + + +@Entity() +class Category { + + int id = null; + + + String name = null; + + + Category(); + + @override + String toString() { + return 'Category[id=$id, name=$name, ]'; + } + +} + diff --git a/samples/client/petstore/dart/lib/model/order.dart b/samples/client/petstore/dart/lib/model/order.dart new file mode 100644 index 00000000000..487f5fad644 --- /dev/null +++ b/samples/client/petstore/dart/lib/model/order.dart @@ -0,0 +1,33 @@ +part of api; + + +@Entity() +class Order { + + int id = null; + + + int petId = null; + + + int quantity = null; + + + DateTime shipDate = null; + + /* Order Status */ + String status = null; + //enum statusEnum { placed, approved, delivered, }; + + bool complete = null; + + + Order(); + + @override + String toString() { + return 'Order[id=$id, petId=$petId, quantity=$quantity, shipDate=$shipDate, status=$status, complete=$complete, ]'; + } + +} + diff --git a/samples/client/petstore/dart/lib/model/pet.dart b/samples/client/petstore/dart/lib/model/pet.dart new file mode 100644 index 00000000000..133cc2eb4ad --- /dev/null +++ b/samples/client/petstore/dart/lib/model/pet.dart @@ -0,0 +1,33 @@ +part of api; + + +@Entity() +class Pet { + + int id = null; + + + Category category = null; + + + String name = null; + + + List photoUrls = []; + + + List tags = []; + + /* pet status in the store */ + String status = null; + //enum statusEnum { available, pending, sold, }; + + Pet(); + + @override + String toString() { + return 'Pet[id=$id, category=$category, name=$name, photoUrls=$photoUrls, tags=$tags, status=$status, ]'; + } + +} + diff --git a/samples/client/petstore/dart/lib/model/tag.dart b/samples/client/petstore/dart/lib/model/tag.dart new file mode 100644 index 00000000000..36cbb19a796 --- /dev/null +++ b/samples/client/petstore/dart/lib/model/tag.dart @@ -0,0 +1,21 @@ +part of api; + + +@Entity() +class Tag { + + int id = null; + + + String name = null; + + + Tag(); + + @override + String toString() { + return 'Tag[id=$id, name=$name, ]'; + } + +} + diff --git a/samples/client/petstore/dart/lib/model/user.dart b/samples/client/petstore/dart/lib/model/user.dart new file mode 100644 index 00000000000..4e09c455941 --- /dev/null +++ b/samples/client/petstore/dart/lib/model/user.dart @@ -0,0 +1,39 @@ +part of api; + + +@Entity() +class User { + + int id = null; + + + String username = null; + + + String firstName = null; + + + String lastName = null; + + + String email = null; + + + String password = null; + + + String phone = null; + + /* User Status */ + int userStatus = null; + + + User(); + + @override + String toString() { + return 'User[id=$id, username=$username, firstName=$firstName, lastName=$lastName, email=$email, password=$password, phone=$phone, userStatus=$userStatus, ]'; + } + +} + diff --git a/samples/client/petstore/dart/pubspec.lock b/samples/client/petstore/dart/pubspec.lock new file mode 100644 index 00000000000..1e4ba01779c --- /dev/null +++ b/samples/client/petstore/dart/pubspec.lock @@ -0,0 +1,87 @@ +# Generated by pub +# See http://pub.dartlang.org/doc/glossary.html#lockfile +packages: + analyzer: + description: analyzer + source: hosted + version: "0.25.0+1" + args: + description: args + source: hosted + version: "0.13.2" + barback: + description: barback + source: hosted + version: "0.15.2+4" + browser: + description: browser + source: hosted + version: "0.10.0+2" + collection: + description: collection + source: hosted + version: "1.1.1" + crypto: + description: crypto + source: hosted + version: "0.9.0" + dartson: + description: dartson + source: hosted + version: "0.2.4" + guinness: + description: guinness + source: hosted + version: "0.1.17" + http: + description: http + source: hosted + version: "0.11.2" + http_parser: + description: http_parser + source: hosted + version: "0.0.2+7" + intl: + description: intl + source: hosted + version: "0.12.4+2" + logging: + description: logging + source: hosted + version: "0.9.3" + path: + description: path + source: hosted + version: "1.3.6" + petitparser: + description: petitparser + source: hosted + version: "1.4.3" + pool: + description: pool + source: hosted + version: "1.1.0" + source_maps: + description: source_maps + source: hosted + version: "0.10.1" + source_span: + description: source_span + source: hosted + version: "1.1.2" + stack_trace: + description: stack_trace + source: hosted + version: "1.3.4" + string_scanner: + description: string_scanner + source: hosted + version: "0.1.3+1" + unittest: + description: unittest + source: hosted + version: "0.11.6+1" + watcher: + description: watcher + source: hosted + version: "0.9.6" diff --git a/samples/client/petstore/dart/pubspec.yaml b/samples/client/petstore/dart/pubspec.yaml new file mode 100644 index 00000000000..cbc62b63ca1 --- /dev/null +++ b/samples/client/petstore/dart/pubspec.yaml @@ -0,0 +1,15 @@ +name: swagger +version: 1.0.0 +description: Swagger API client +dependencies: + http: '>=0.11.1 <0.12.0' + dartson: "^0.2.4" + crypto: "^0.9.0" + intl: "^0.12.4+2" + +dev_dependencies: + guinness: '^0.1.17' + browser: any + +transformers: + - dartson diff --git a/samples/client/petstore/dart/test/pet_test.dart b/samples/client/petstore/dart/test/pet_test.dart new file mode 100644 index 00000000000..f93c3ea3e37 --- /dev/null +++ b/samples/client/petstore/dart/test/pet_test.dart @@ -0,0 +1,85 @@ +part of tests; + +testPetApi() { + var petApi = new PetApi(); + + describe('Pet API ', () { + it('adds a new pet and gets it by id', () async { + var id = 137; + + await petApi.addPet(new Pet()..id = id); + var pet = await petApi.getPetById(id); + expect(pet.id).toEqual(id); + }); + + it('doesn\'t get non-existing pet by id', () { + expect(petApi.getPetById(6789099)).toThrowWith(anInstanceOf: ApiException); + }); + + it('deletes existing pet by id', () async { + var id = 7689; + await petApi.addPet(new Pet()..id = id); + await petApi.deletePet(id, 'special-key'); + expect(petApi.getPetById(id)).toThrowWith(anInstanceOf: ApiException); + }); + + it('updates pet with form', () async { + var id = 52341; + await petApi.addPet(new Pet()..id = id..name='Snowy'); + await petApi.updatePetWithForm('$id', 'Doge', ''); + var pet = await petApi.getPetById(id); + expect(pet.name).toEqual('Doge'); + }); + + it('updates existing pet', () async { + var id = 900001; + var name = 'Snowy'; + + await petApi.addPet(new Pet()..id = id); + await petApi.updatePet(new Pet()..id = id..name = name); + var pet = await petApi.getPetById(id); + expect(pet.name).toEqual(name); + }); + + it('finds pets by status', () async { + var id1 = 754111; + var id2 = 1231341; + var id3 = 6776251; + var status = 'available'; + + return Future.wait([petApi.addPet(new Pet()..id = id1..status = status), + petApi.addPet(new Pet()..id = id2..status = status), + petApi.addPet(new Pet()..id = id3..status = 'sold')]) + .then((_) async { + + var pets = await petApi.findPetsByStatus([status]); + var petIds = pets.map((pet) => pet.id).toList(); + expect(petIds).toContain(id1); + expect(petIds).toContain(id2); + expect(petIds).not.toContain(id3); + }); + }); + + it('finds pets by tag', () async { + var snowyId = 253156; + var grumpyId = 734215; + var snowyTags = [new Tag()..id=12211..name='terrier']; + var grumpyTags = [new Tag()..id=455803..name='grumpy']; + await petApi.addPet(new Pet()..id = snowyId..name = 'Snowy'..tags = snowyTags); + await petApi.addPet(new Pet()..id = grumpyId..name = 'Grumpy Cat'..tags = grumpyTags); + + var pets = await petApi.findPetsByTags(['grumpy']); + var petIds = pets.map((pet) => pet.id).toList(); + expect(petIds).toContain(grumpyId); + expect(petIds).not.toContain(snowyId); + }); + + it('uploads a pet image', () async { + var id = 672322; + await petApi.addPet(new Pet()..id = id); + var file = new MultipartFile.fromBytes('file', [104, 101, 108, 108, 111]); + await petApi.uploadFile(id, '', file); + }); + + }); +} \ No newline at end of file diff --git a/samples/client/petstore/dart/test/store_test.dart b/samples/client/petstore/dart/test/store_test.dart new file mode 100644 index 00000000000..692760f1be1 --- /dev/null +++ b/samples/client/petstore/dart/test/store_test.dart @@ -0,0 +1,30 @@ +part of tests; + +testStoreApi() { + var storeApi = new StoreApi(); + + describe('Store API ', () async { + + it('places an order and gets it by id', () async { + var id = 4356; + + await storeApi.placeOrder(new Order()..id = id); + var order = await storeApi.getOrderById(id.toString()); + expect(order.id).toEqual(id); + }); + + it('deletes an order', () async { + var id = 637211; + + await storeApi.placeOrder(new Order()..id = id); + await storeApi.deleteOrder(id.toString()); + expect(storeApi.getOrderById(id.toString())).toThrowWith(anInstanceOf: ApiException); + }); + + it('gets the store inventory', () async { + Map inventory = await storeApi.getInventory(); + expect(inventory.length).not.toBe(0); + }); + + }); +} \ No newline at end of file diff --git a/samples/client/petstore/dart/test/tests.dart b/samples/client/petstore/dart/test/tests.dart new file mode 100644 index 00000000000..173a5587a4d --- /dev/null +++ b/samples/client/petstore/dart/test/tests.dart @@ -0,0 +1,16 @@ +library tests; + +import 'dart:async'; +import 'package:http/http.dart'; +import 'package:guinness/guinness.dart'; +import 'package:swagger/api.dart'; + +part 'pet_test.dart'; +part 'store_test.dart'; +part 'user_test.dart'; + +main() { + testPetApi(); + testStoreApi(); + testUserApi(); +} \ No newline at end of file diff --git a/samples/client/petstore/dart/test/tests.html b/samples/client/petstore/dart/test/tests.html new file mode 100644 index 00000000000..e3796c5fcfe --- /dev/null +++ b/samples/client/petstore/dart/test/tests.html @@ -0,0 +1,14 @@ + + + + + + + Unit Test Results + + + + + + + \ No newline at end of file diff --git a/samples/client/petstore/dart/test/user_test.dart b/samples/client/petstore/dart/test/user_test.dart new file mode 100644 index 00000000000..886a6bc3c5d --- /dev/null +++ b/samples/client/petstore/dart/test/user_test.dart @@ -0,0 +1,63 @@ +part of tests; + +testUserApi() { + var userApi = new UserApi(); + + describe('User API ', () { + + it('creates a user', () async { + var id = 67567; + var username = 'Mally45'; + await userApi.createUser(new User()..id = id..username = username); + var user = await userApi.getUserByName(username); + expect(user.id).toEqual(id); + }); + + it('creates users with list input', () async { + var firstId = 46226; + var joe ='Joe'; + + var sally = 'Sally'; + var secondId = 95239; + + var users = [ new User()..id = firstId..username = joe, + new User()..id = secondId..username = sally]; + + await userApi.createUsersWithListInput(users); + var firstUser = await userApi.getUserByName(joe); + var secondUser = await userApi.getUserByName(sally); + expect(firstUser.id).toEqual(firstId); + expect(secondUser.id).toEqual(secondId); + }); + + it('updates a user', () async { + var username ='Arkjam89'; + var email = 'test@example.com'; + var user = new User()..id = 733356..username = username; + + await userApi.createUser(user); + user.email = email; + await userApi.updateUser(username,user); + var foundUser = await userApi.getUserByName(username); + expect(foundUser.email).toEqual(email); + }); + + it('deletes a user', () async { + var username ='Riddlem325'; + await userApi.createUser(new User()..id = 1231114..username = username); + await userApi.deleteUser(username); + expect(userApi.getUserByName(username)).toThrowWith(anInstanceOf: ApiException); + }); + + it('logs a user in', () async { + var username ='sgarad625'; + var password = 'lokimoki1'; + var user = new User()..id = 733356..username = username..password = password; + + await userApi.createUser(user); + var result = await userApi.loginUser(username, password); + expect(result).toContain('logged in user session:'); + }); + + }); +} \ No newline at end of file