diff --git a/README.md b/README.md index acae949c8192..cb1f35d87c8a 100644 --- a/README.md +++ b/README.md @@ -461,6 +461,7 @@ JavaJerseyServerCodegen.java JavaResteasyServerCodegen.java JavascriptClientCodegen.java NodeJSServerCodegen.java +NancyFXServerCodegen ObjcClientCodegen.java PerlClientCodegen.java PhpClientCodegen.java @@ -698,6 +699,7 @@ Here are some companies/projects using Swagger Codegen in production. To add you - [eureka](http://eure.jp/) - [everystory.us](http://everystory.us) - [Expected Behavior](http://www.expectedbehavior.com/) +- [Finder](http://en.finder.pl/) - [FH Münster - University of Applied Sciences](http://www.fh-muenster.de) - [GraphHopper](https://graphhopper.com/) - [Gravitate Solutions](http://gravitatesolutions.com/) @@ -767,6 +769,7 @@ Swaagger Codegen core team members are contributors who have been making signfic | Java Spring Boot | | | Java SpringMVC | @kolyjjj (2016/05/01) | | Java JAX-RS | | +| NancyFX | | | NodeJS | @kolyjjj (2016/05/01) | | PHP Lumen | @abcsum (2016/05/01) | | PHP Silex | | diff --git a/bin/windows/nancyfx-petstore-server.bat b/bin/windows/nancyfx-petstore-server.bat new file mode 100644 index 000000000000..72af10287ce8 --- /dev/null +++ b/bin/windows/nancyfx-petstore-server.bat @@ -0,0 +1,10 @@ +set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties +set ags=generate -t modules\swagger-codegen\src\main\resources\nancyfx -i modules\swagger-codegen\src\test\resources\2_0\petstore.json -l nancyfx -o samples\server\petstore\nancyfx\ + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java index 0f4608a133ad..6d32d54f3f99 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.Objects; import io.swagger.models.ExternalDocs; @@ -29,6 +30,7 @@ public class CodegenModel { public List readOnlyVars = new ArrayList(); // a list of read-only properties public List readWriteVars = new ArrayList(); // a list of properties for read, write public List allVars; + public List parentVars = new ArrayList<>(); public Map allowableValues; // Sorted sets of required parameters. @@ -36,7 +38,7 @@ public class CodegenModel { public Set allMandatory; public Set imports = new TreeSet(); - public Boolean hasVars, emptyVars, hasMoreModels, hasEnums, isEnum, hasRequired, isArrayModel; + public Boolean hasVars, emptyVars, hasMoreModels, hasEnums, isEnum, hasRequired, isArrayModel, hasChildren; public Boolean hasOnlyReadOnly = true; // true if all properties are read-only public ExternalDocs externalDocs; @@ -122,6 +124,12 @@ public class CodegenModel { return false; if (externalDocs != null ? !externalDocs.equals(that.externalDocs) : that.externalDocs != null) return false; + if (!Objects.equals(hasOnlyReadOnly, that.hasOnlyReadOnly)) + return false; + if (!Objects.equals(hasChildren, that.hasChildren)) + return false; + if (!Objects.equals(parentVars, that.parentVars)) + return false; return vendorExtensions != null ? vendorExtensions.equals(that.vendorExtensions) : that.vendorExtensions == null; } @@ -158,6 +166,9 @@ public class CodegenModel { result = 31 * result + (isEnum != null ? isEnum.hashCode() : 0); result = 31 * result + (externalDocs != null ? externalDocs.hashCode() : 0); result = 31 * result + (vendorExtensions != null ? vendorExtensions.hashCode() : 0); + result = 31 * result + Objects.hash(hasOnlyReadOnly); + result = 31 * result + Objects.hash(hasChildren); + result = 31 * result + Objects.hash(parentVars); return result; } } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java index d58a1a81b1d3..eeef7777df2d 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java @@ -2,8 +2,9 @@ package io.swagger.codegen; import java.util.List; import java.util.Map; +import java.util.Objects; -public class CodegenProperty { +public class CodegenProperty implements Cloneable { public String baseName, complexType, getter, setter, description, datatype, datatypeWithEnum, name, min, max, defaultValue, defaultValueWithParam, baseType, containerType; @@ -43,6 +44,7 @@ public class CodegenProperty { public CodegenProperty items; public Map vendorExtensions; public Boolean hasValidation; // true if pattern, maximum, etc are set (only used in the mustache template) + public Boolean isInherited; @Override public String toString() { @@ -105,6 +107,7 @@ public class CodegenProperty { result = prime * result + ((isDateTime == null) ? 0 : isDateTime.hashCode()); result = prime * result + ((isMapContainer == null) ? 0 : isMapContainer.hashCode()); result = prime * result + ((isListContainer == null) ? 0 : isListContainer.hashCode()); + result = prime * result + Objects.hashCode(isInherited); return result; } @@ -256,6 +259,18 @@ public class CodegenProperty { if (this.isMapContainer != other.isMapContainer && (this.isMapContainer == null || !this.isMapContainer.equals(other.isMapContainer))) { return false; } + if (!Objects.equals(this.isInherited, other.isInherited)) { + return false; + } return true; } + + @Override + public CodegenProperty clone() { + try { + return (CodegenProperty) super.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalStateException(e); + } + } } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java new file mode 100644 index 000000000000..3eec3751364b --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java @@ -0,0 +1,404 @@ +package io.swagger.codegen.languages; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static io.swagger.codegen.CodegenConstants.OPTIONAL_PROJECT_FILE; +import static io.swagger.codegen.CodegenConstants.OPTIONAL_PROJECT_FILE_DESC; +import static io.swagger.codegen.CodegenConstants.PACKAGE_NAME; +import static io.swagger.codegen.CodegenConstants.PACKAGE_VERSION; +import static io.swagger.codegen.CodegenConstants.RETURN_ICOLLECTION; +import static io.swagger.codegen.CodegenConstants.RETURN_ICOLLECTION_DESC; +import static io.swagger.codegen.CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG; +import static io.swagger.codegen.CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC; +import static io.swagger.codegen.CodegenConstants.SOURCE_FOLDER; +import static io.swagger.codegen.CodegenConstants.SOURCE_FOLDER_DESC; +import static io.swagger.codegen.CodegenConstants.USE_COLLECTION; +import static io.swagger.codegen.CodegenConstants.USE_COLLECTION_DESC; +import static io.swagger.codegen.CodegenConstants.USE_DATETIME_OFFSET; +import static io.swagger.codegen.CodegenConstants.USE_DATETIME_OFFSET_DESC; +import static io.swagger.codegen.CodegenType.SERVER; +import static java.util.Arrays.asList; +import static java.util.UUID.randomUUID; +import static org.apache.commons.lang3.StringUtils.capitalize; +import io.swagger.codegen.CodegenModel; +import io.swagger.codegen.CodegenOperation; +import io.swagger.codegen.CodegenProperty; +import io.swagger.codegen.CodegenType; +import io.swagger.codegen.SupportingFile; +import io.swagger.models.Swagger; +import io.swagger.models.properties.Property; +import io.swagger.models.properties.StringProperty; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Predicate; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; + +public class NancyFXServerCodegen extends AbstractCSharpCodegen { + private static final Logger log = LoggerFactory.getLogger(NancyFXServerCodegen.class); + + private static final String API_NAMESPACE = "Modules"; + private static final String MODEL_NAMESPACE = "Models"; + private static final String IMMUTABLE_OPTION = "immutable"; + + private static final Map> propertyToSwaggerTypeMapping = + createPropertyToSwaggerTypeMapping(); + + private final String packageGuid = "{" + randomUUID().toString().toUpperCase() + "}"; + + private final Map dependencies = new HashMap<>(); + private final Set parentModels = new HashSet<>(); + private final Multimap childrenByParent = ArrayListMultimap.create(); + private final BiMap modelNameMapping = HashBiMap.create(); + + public NancyFXServerCodegen() { + outputFolder = "generated-code" + File.separator + getName(); + apiTemplateFiles.put("api.mustache", ".cs"); + + // contextually reserved words + setReservedWordsLowerCase( + asList("var", "async", "await", "dynamic", "yield") + ); + + cliOptions.clear(); + + // CLI options + addOption(PACKAGE_NAME, "C# package name (convention: Title.Case).", packageName); + addOption(PACKAGE_VERSION, "C# package version.", packageVersion); + addOption(SOURCE_FOLDER, SOURCE_FOLDER_DESC, sourceFolder); + + // CLI Switches + addSwitch(SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_BY_REQUIRED_FLAG_DESC, sortParamsByRequiredFlag); + addSwitch(OPTIONAL_PROJECT_FILE, OPTIONAL_PROJECT_FILE_DESC, optionalProjectFileFlag); + addSwitch(USE_DATETIME_OFFSET, USE_DATETIME_OFFSET_DESC, useDateTimeOffsetFlag); + addSwitch(USE_COLLECTION, USE_COLLECTION_DESC, useCollection); + addSwitch(RETURN_ICOLLECTION, RETURN_ICOLLECTION_DESC, returnICollection); + addSwitch(IMMUTABLE_OPTION, "Enabled by default. If disabled generates model classes with setters", true); + typeMapping.putAll(nodaTimeTypesMappings()); + languageSpecificPrimitives.addAll(nodaTimePrimitiveTypes()); + + importMapping.clear(); + } + + @Override + public CodegenType getTag() { + return SERVER; + } + + @Override + public String getName() { + return "nancyfx"; + } + + @Override + public String getHelp() { + return "Generates a NancyFX Web API server."; + } + + @Override + public void processOpts() { + super.processOpts(); + + apiPackage = isNullOrEmpty(packageName) ? API_NAMESPACE : packageName + "." + API_NAMESPACE; + modelPackage = isNullOrEmpty(packageName) ? MODEL_NAMESPACE : packageName + "." + MODEL_NAMESPACE; + + supportingFiles.add(new SupportingFile("parameters.mustache", sourceFile("Utils"), "Parameters.cs")); + supportingFiles.add(new SupportingFile("packages.config.mustache", sourceFolder(), "packages.config")); + supportingFiles.add(new SupportingFile("nuspec.mustache", sourceFolder(), packageName + ".nuspec")); + + if (optionalProjectFileFlag) { + supportingFiles.add(new SupportingFile("Solution.mustache", "", packageName + ".sln")); + supportingFiles.add(new SupportingFile("Project.mustache", sourceFolder(), packageName + ".csproj")); + } + additionalProperties.put("packageGuid", packageGuid); + + setupModelTemplate(); + processImportedMappings(); + appendDependencies(); + } + + private void setupModelTemplate() { + final Object immutableOption = additionalProperties.get(IMMUTABLE_OPTION); + if (immutableOption != null && "false".equalsIgnoreCase(immutableOption.toString())) { + log.info("Using mutable model template"); + modelTemplateFiles.put("modelMutable.mustache", ".cs"); + } else { + log.info("Using immutable model template"); + modelTemplateFiles.put("model.mustache", ".cs"); + } + } + + private void processImportedMappings() { + for (final Entry entry : ImmutableSet.copyOf(importMapping.entrySet())) { + final String model = entry.getKey(); + final String[] namespaceInfo = entry.getValue().split("\\s"); + final String[] namespace = (namespaceInfo.length > 0 ? namespaceInfo[0].trim() : "").split(":"); + final String namespaceName = namespace.length > 0 ? namespace[0].trim() : null; + final String modelClass = namespace.length > 1 ? namespace[1].trim() : null; + final String assembly = namespaceInfo.length > 1 ? namespaceInfo[1].trim() : null; + final String assemblyVersion = namespaceInfo.length > 2 ? namespaceInfo[2].trim() : null; + final String assemblyFramework = namespaceInfo.length > 3 ? namespaceInfo[3].trim() : "net45"; + + if (isNullOrEmpty(model) || isNullOrEmpty(namespaceName)) { + log.warn(String.format("Could not import: '%s' - invalid namespace: '%s'", model, entry.getValue())); + importMapping.remove(model); + } else { + log.info(String.format("Importing: '%s' from '%s' namespace.", model, namespaceName)); + importMapping.put(model, namespaceName); + } + if (!isNullOrEmpty(modelClass)) { + log.info(String.format("Mapping: '%s' class to '%s'", model, modelClass)); + modelNameMapping.put(model, modelClass); + } + if (assembly != null && assemblyVersion != null) { + log.info(String.format("Adding dependency: '%s', version: '%s', framework: '%s'", + assembly, assemblyVersion, assemblyVersion)); + dependencies.put(assembly, new DependencyInfo(assemblyVersion, assemblyFramework)); + } + } + } + + private void appendDependencies() { + final List> listOfDependencies = new ArrayList<>(); + for (final Entry dependency : dependencies.entrySet()) { + final Map dependencyInfo = new HashMap<>(); + dependencyInfo.put("dependency", dependency.getKey()); + dependencyInfo.put("dependencyVersion", dependency.getValue().version); + dependencyInfo.put("dependencyFramework", dependency.getValue().framework); + listOfDependencies.add(dependencyInfo); + } + additionalProperties.put("dependencies", listOfDependencies); + } + + private String sourceFolder() { + return "src" + File.separator + packageName; + } + + private String sourceFile(final String fileName) { + return sourceFolder() + File.separator + fileName; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder() + File.separator + API_NAMESPACE; + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder() + File.separator + MODEL_NAMESPACE; + } + + @Override + protected void processOperation(final CodegenOperation operation) { + super.processOperation(operation); + if (!isNullOrEmpty(operation.path) && operation.path.contains("?")) { + operation.path = operation.path.replace("?", "/"); + } + if (!isNullOrEmpty(operation.httpMethod)) { + operation.httpMethod = capitalize(operation.httpMethod.toLowerCase()); + } + } + + @Override + public Map postProcessAllModels(final Map models) { + final Map processed = super.postProcessAllModels(models); + postProcessParentModels(models); + return processed; + } + + private void postProcessParentModels(final Map models) { + log.info("Processing parents: " + parentModels); + for (final String parent : parentModels) { + final CodegenModel parentModel = modelByName(parent, models); + parentModel.hasChildren = true; + final Collection childrenModels = childrenByParent.get(parent); + for (final CodegenModel child : childrenModels) { + processParentPropertiesInChildModel(parentModel, child); + } + } + } + + private CodegenModel modelByName(final String name, final Map models) { + final Object data = models.get(name); + if (data instanceof Map) { + final Map dataMap = (Map) data; + final Object dataModels = dataMap.get("models"); + if (dataModels instanceof List) { + final List dataModelsList = (List) dataModels; + for (final Object entry : dataModelsList) { + if (entry instanceof Map) { + final Map entryMap = (Map) entry; + final Object model = entryMap.get("model"); + if (model instanceof CodegenModel) { + return (CodegenModel) model; + } + } + } + } + } + return null; + } + + private void processParentPropertiesInChildModel(final CodegenModel parent, final CodegenModel child) { + final Map childPropertiesByName = new HashMap<>(child.vars.size()); + for (final CodegenProperty property : child.vars) { + childPropertiesByName.put(property.name, property); + } + CodegenProperty previousParentVar = null; + for (final CodegenProperty property : parent.vars) { + final CodegenProperty duplicatedByParent = childPropertiesByName.get(property.name); + if (duplicatedByParent != null) { + log.info(String.format("Property: '%s' in '%s' model is inherited from '%s'" , + property.name, child.classname, parent.classname)); + duplicatedByParent.isInherited = true; + final CodegenProperty parentVar = duplicatedByParent.clone(); + parentVar.hasMore = false; + child.parentVars.add(parentVar); + if (previousParentVar != null) { + previousParentVar.hasMore = true; + } + previousParentVar = parentVar; + } + } + } + + @Override + public void postProcessModelProperty(final CodegenModel model, final CodegenProperty property) { + super.postProcessModelProperty(model, property); + if (!isNullOrEmpty(model.parent)) { + parentModels.add(model.parent); + if (!childrenByParent.containsEntry(model.parent, model)) { + childrenByParent.put(model.parent, model); + } + } + } + + @Override + public String toEnumVarName(final String name, final String datatype) { + final String enumName = camelize( + sanitizeName(name) + .replaceFirst("^_", "") + .replaceFirst("_$", "") + .replaceAll("-", "_")); + final String result; + if (enumName.matches("\\d.*")) { + result = "_" + enumName; + } else { + result = enumName; + } + log.info(String.format("toEnumVarName('%s', %s) = '%s'", name, datatype, enumName)); + return result; + } + + @Override + public String toApiName(final String name) { + final String apiName; + if (isNullOrEmpty(name)) { + apiName = "Default"; + } else { + apiName = capitalize(name); + } + log.info(String.format("toApiName('%s') = '%s'", name, apiName)); + return apiName; + } + + @Override + public String toApiFilename(final String name) { + return super.toApiFilename(name) + "Module"; + } + + @Override + public String toModelImport(final String name) { + final String result; + if (modelNameMapping.containsValue(name)) { + final String modelName = modelNameMapping.inverse().get(name); + result = importMapping.containsKey(modelName) ? + importMapping.get(modelName) : super.toModelImport(name); + } else if (importMapping.containsKey(name)) { + result = importMapping.get(name); + } else { + result = null; + } + log.info(String.format("toModelImport('%s') = '%s'", name, result)); + return result; + } + + @Override + public String toModelName(final String name) { + final String modelName = super.toModelName(name); + final String mappedModelName = modelNameMapping.get(modelName); + return isNullOrEmpty(mappedModelName) ? modelName: mappedModelName; + } + + @Override + public void preprocessSwagger(final Swagger swagger) { + additionalProperties.put("packageContext", sanitizeName(swagger.getBasePath())); + additionalProperties.put("baseContext", swagger.getBasePath()); + } + + @Override + public String toEnumName(final CodegenProperty property) { + return sanitizeName(camelize(property.name)) + "Enum"; + } + + @Override + public String getSwaggerType(final Property property) { + for (Entry> entry : propertyToSwaggerTypeMapping.entrySet()) { + if (entry.getValue().apply(property)) { + return entry.getKey(); + } + } + return super.getSwaggerType(property); + } + + private static Map> createPropertyToSwaggerTypeMapping() { + final ImmutableMap.Builder> mapping = ImmutableMap.builder(); + mapping.put("time", timeProperty()); + return mapping.build(); + } + + private static Predicate timeProperty() { + return new Predicate() { + @Override + public boolean apply(Property property) { + return property instanceof StringProperty && "time".equalsIgnoreCase(property.getFormat()); + } + }; + } + + private static Map nodaTimeTypesMappings() { + return ImmutableMap.of( + "time", "LocalTime?", + "date", "ZonedDateTime?", + "datetime", "ZonedDateTime?"); + } + + private static Set nodaTimePrimitiveTypes() { + return ImmutableSet.of("LocalTime?", "ZonedDateTime?"); + } + + private class DependencyInfo { + private final String version; + private final String framework; + + private DependencyInfo(final String version, final String framework) { + this.version = version; + this.framework = framework; + } + } +} 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 e5d4f5f1355e..12425c3ce99d 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 @@ -17,6 +17,7 @@ io.swagger.codegen.languages.JavascriptClientCodegen io.swagger.codegen.languages.JavascriptClosureAngularClientCodegen io.swagger.codegen.languages.JavaJerseyServerCodegen io.swagger.codegen.languages.JMeterCodegen +io.swagger.codegen.languages.NancyFXServerCodegen io.swagger.codegen.languages.NodeJSServerCodegen io.swagger.codegen.languages.ObjcClientCodegen io.swagger.codegen.languages.PerlClientCodegen @@ -46,4 +47,4 @@ io.swagger.codegen.languages.CsharpDotNet2ClientCodegen io.swagger.codegen.languages.ClojureClientCodegen io.swagger.codegen.languages.HaskellServantCodegen io.swagger.codegen.languages.LumenServerCodegen -io.swagger.codegen.languages.GoServerCodegen \ No newline at end of file +io.swagger.codegen.languages.GoServerCodegen diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache new file mode 100644 index 000000000000..5b63a52feb2b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache @@ -0,0 +1,80 @@ + + + + Debug + AnyCPU + {{packageGuid}} + Library + Properties + {{packageName}}.{{packageContext}} + {{packageTitle}} + {{^supportsUWP}} + v4.5 + {{/supportsUWP}} + {{#supportsUWP}} + UAP + 10.0.10240.0 + 10.0.10240.0 + 14 + {{/supportsUWP}} + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\{{packageName}}.XML + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\{{packageName}}.XML + + + + ..\..\packages\Nancy.1.4.1\lib\net40\Nancy.dll + True + + + ..\..\packages\NodaTime.1.3.1\lib\net35-Client\NodaTime.dll + True + + + ..\..\packages\Sharpility.1.2.2\lib\net45\Sharpility.dll + True + + + ..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + {{#dependencies}} + + ..\..\packages\{{dependency}}.{{dependencyVersion}}\lib\{{dependencyFramework}}\{{dependency}}.dll + True + + {{/dependencies}} + + + + + + + + + + + + + + + + + + diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/Solution.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/Solution.mustache new file mode 100644 index 000000000000..7f2d34e366ea --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/Solution.mustache @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +VisualStudioVersion = 12.0.0.0 +MinimumVisualStudioVersion = 10.0.0.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{packageName}}", "src\{{packageName}}\{{packageName}}.csproj", "{{packageGuid}}" +EndProject +Global +GlobalSection(SolutionConfigurationPlatforms) = preSolution +Debug|Any CPU = Debug|Any CPU +Release|Any CPU = Release|Any CPU +EndGlobalSection +GlobalSection(ProjectConfigurationPlatforms) = postSolution +{{packageGuid}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU +{{packageGuid}}.Debug|Any CPU.Build.0 = Debug|Any CPU +{{packageGuid}}.Release|Any CPU.ActiveCfg = Release|Any CPU +{{packageGuid}}.Release|Any CPU.Build.0 = Release|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Debug|Any CPU.Build.0 = Debug|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Release|Any CPU.ActiveCfg = Release|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Release|Any CPU.Build.0 = Release|Any CPU +EndGlobalSection +GlobalSection(SolutionProperties) = preSolution +HideSolutionNode = FALSE +EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache new file mode 100644 index 000000000000..1e66c83c7693 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache @@ -0,0 +1,74 @@ +using System; +using Nancy; +using Nancy.ModelBinding; +using System.Collections.Generic; +using Sharpility.Base; +using {{packageName}}.{{packageContext}}.Models; +using {{packageName}}.{{packageContext}}.Utils; +using NodaTime; +{{#imports}}using {{import}}; +{{/imports}} + +namespace {{packageName}}.{{packageContext}}.Modules +{ {{#operations}}{{#operation}}{{#allParams}}{{#isEnum}} + {{>innerApiEnum}}{{/isEnum}}{{/allParams}}{{/operation}} + + /// + /// Module processing requests of {{classname}} domain. + /// + public sealed class {{classname}}Module : NancyModule + { + /// + /// Sets up HTTP methods mappings. + /// + /// Service handling requests + public {{classname}}Module({{classname}}Service service) : base("{{baseContext}}") + { {{#operation}} + {{httpMethod}}["{{path}}"] = parameters => + { + {{#allParams}}{{#isBodyParam}}var {{paramName}} = this.Bind<{{&dataType}}>();{{/isBodyParam}}{{^isBodyParam}}{{#isEnum}}var {{paramName}} = Parameters.ValueOf<{{>innerApiEnumName}}?>({{>innerParameterValueOfArgs}});{{/isEnum}}{{^isEnum}}var {{paramName}} = Parameters.ValueOf<{{&dataType}}>({{>innerParameterValueOfArgs}});{{/isEnum}}{{#hasMore}} + {{/hasMore}}{{/isBodyParam}}{{/allParams}}{{#allParams}}{{#required}} + Preconditions.IsNotNull({{paramName}}, "Required parameter: '{{paramName}}' is missing at '{{operationId}}'"); + {{/required}}{{/allParams}} + {{#returnType}}return {{/returnType}}service.{{operationId}}(Context{{#allParams.0}}, {{/allParams.0}}{{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{^returnType}} + return new Response { ContentType = "{{produces.0.mediaType}}"};{{/returnType}} + }; +{{/operation}} + } + } + + /// + /// Service handling {{classname}} requests. + /// + public interface {{classname}}Service + { + {{#operation}}/// + /// {{notes}} + /// + /// Context of request + {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} + {{/allParams}}/// {{#returnType}}{{returnType}}{{/returnType}} + {{#returnType}}{{&returnType}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}}(NancyContext context{{#allParams.0}}, {{/allParams.0}}{{>paramsList}});{{#hasMore}} + + {{/hasMore}}{{/operation}} + } + + /// + /// Abstraction of {{classname}}Service. + /// + public abstract class Abstract{{classname}}Service: {{classname}}Service + { + {{#operation}}public virtual {{#returnType}}{{&returnType}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}}(NancyContext context{{#allParams.0}}, {{/allParams.0}}{{>paramsList}}) + { + {{#returnType}}return {{/returnType}}{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); + }{{#hasMore}} + + {{/hasMore}}{{/operation}} + + {{#operation}}protected abstract {{#returnType}}{{&returnType}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}}({{>paramsList}});{{#hasMore}} + + {{/hasMore}}{{/operation}} + } + +{{/operations}} +} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/innerApiEnum.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/innerApiEnum.mustache new file mode 100644 index 000000000000..5a7a89aa5286 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/innerApiEnum.mustache @@ -0,0 +1,4 @@ +/// + /// {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} + /// + public enum {{>innerApiEnumName}} { {{#allowableValues}}{{#values}}{{&.}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}} }; \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/innerApiEnumName.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/innerApiEnumName.mustache new file mode 100644 index 000000000000..f54069fb50c3 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/innerApiEnumName.mustache @@ -0,0 +1 @@ +{{#datatypeWithEnum}}{{operationId}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/innerModelEnum.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/innerModelEnum.mustache new file mode 100644 index 000000000000..19e4731f2cf4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/innerModelEnum.mustache @@ -0,0 +1 @@ +public enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { {{#allowableValues}}{{#enumVars}}{{{name}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}} }; \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/innerParameterType.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/innerParameterType.mustache new file mode 100644 index 000000000000..c9a8cb664495 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/innerParameterType.mustache @@ -0,0 +1 @@ +{{#isQueryParam}}ParameterType.Query{{/isQueryParam}}{{#isPathParam}}ParameterType.Path{{/isPathParam}}{{#isHeaderParam}}ParameterType.Header{{/isHeaderParam}}{{^isQueryParam}}{{^isPathParam}}{{^isHeaderParam}}ParameterType.Undefined{{/isHeaderParam}}{{/isPathParam}}{{/isQueryParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/innerParameterValueOfArgs.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/innerParameterValueOfArgs.mustache new file mode 100644 index 000000000000..2aca302eecf5 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/innerParameterValueOfArgs.mustache @@ -0,0 +1 @@ +parameters, Context.Request, "{{paramName}}", {{>innerParameterType}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache new file mode 100644 index 000000000000..2313ae976f1e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Sharpility.Extensions; +using NodaTime; +{{#imports}}using {{import}}; +{{/imports}} + +{{#models}} +{{#model}} +namespace {{packageName}}.{{packageContext}}.Models +{ + /// + /// {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} + /// + public {{^hasChildren}}sealed {{/hasChildren}}class {{classname}}: {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}> + { {{#vars}}{{^isInherited}} + /// + /// {{^description}}{{{name}}}{{/description}}{{#description}}{{description}}{{/description}} + /// + public {{>nullableDataType}} {{name}} { get; private set; } +{{/isInherited}}{{/vars}} + + /// + /// Empty constructor required by some serializers. + /// Use {{classname}}.Builder() for instance creation instead. + /// + [Obsolete] + public {{classname}}(){{#parent}} : base({{/parent}}{{#parentVars}}null{{#hasMore}}, {{/hasMore}}{{/parentVars}}{{#parent}}){{/parent}} + { + } + + {{#hasChildren}}protected{{/hasChildren}}{{^hasChildren}}private{{/hasChildren}} {{classname}}({{#vars}}{{>nullableDataType}} {{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}){{#parent}} : base({{#parentVars}}{{name}}{{#hasMore}}, {{/hasMore}}{{/parentVars}}){{/parent}} + { + {{#vars}}{{^isInherited}} + this.{{name}} = {{name}}; + {{/isInherited}}{{/vars}} + } + + /// + /// Returns builder of {{classname}}. + /// + /// {{classname}}Builder + public static {{#parent}}new {{/parent}}{{classname}}Builder Builder() + { + return new {{classname}}Builder(); + } + + /// + /// Returns {{classname}}Builder with properties set. + /// Use it to change properties. + /// + /// {{classname}}Builder + public {{#parent}}new {{/parent}}{{classname}}Builder With() + { + return Builder() + {{#vars}} + .{{name}}({{name}}){{#hasMore}} +{{/hasMore}}{{/vars}}; + } + + public override string ToString() + { + return this.PropertiesToString(); + } + + public override bool Equals(object obj) + { + return this.EqualsByProperties(obj); + } + + public bool Equals({{classname}} other) + { + return Equals((object) other); + } + + public override int GetHashCode() + { + return this.PropertiesHash(); + } + + /// + /// Implementation of == operator for ({{classname}}. + /// + /// Compared ({{classname}} + /// Compared ({{classname}} + /// true if compared items are equals, false otherwise + public static bool operator == ({{classname}} left, {{classname}} right) + { + return Equals(left, right); + } + + /// + /// Implementation of != operator for ({{classname}}. + /// + /// Compared ({{classname}} + /// Compared ({{classname}} + /// true if compared items are not equals, false otherwise + public static bool operator != ({{classname}} left, {{classname}} right) + { + return !Equals(left, right); + } + + /// + /// Builder of {{classname}}. + /// + public sealed class {{classname}}Builder + { + {{#vars}} + private {{>nullableDataType}} _{{name}}; + {{/vars}} + + internal {{classname}}Builder() + { + SetupDefaults(); + } + + private void SetupDefaults() + { + {{#vars}} + {{^required}} + {{#defaultValue}} + _{{name}} = {{{defaultValue}}}; + {{/defaultValue}} + {{/required}} + {{/vars}} + } + + {{#vars}} + /// + /// Sets value for {{classname}}.{{{name}}} property. + /// + /// {{^description}}{{{name}}}{{/description}}{{#description}}{{description}}{{/description}} + public {{classname}}Builder {{name}}({{>nullableDataType}} value) + { + _{{name}} = value; + return this; + } + + {{/vars}} + + /// + /// Builds instance of {{classname}}. + /// + /// {{classname}} + public {{classname}} Build() + { + Validate(); + return new {{classname}}( + {{#vars}} + {{name}}: _{{name}}{{#hasMore}},{{/hasMore}} + {{/vars}} + ); + } + + private void Validate() + { {{#vars}}{{#required}} + if (_{{name}} == null) + { + throw new ArgumentException("{{name}} is a required property for {{classname}} and cannot be null"); + } {{/required}}{{/vars}} + } + } + + {{#vars}}{{#isEnum}}{{^parent}} + {{>innerModelEnum}}{{/parent}}{{/isEnum}}{{#items.isEnum}} + {{#items}}{{>innerModelEnum}}{{/items}}{{/items.isEnum}}{{/vars}} + } +{{/model}} +{{/models}} +} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/modelMutable.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/modelMutable.mustache new file mode 100644 index 000000000000..a9ef6c90bd33 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/modelMutable.mustache @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Sharpility.Extensions; +using NodaTime; +{{#imports}}using {{import}}; +{{/imports}} + +{{#models}} +{{#model}} +namespace {{packageName}}.{{packageContext}}.Models +{ {{#vars}}{{#isEnum}}{{^parent}} + {{>innerModelEnum}}{{/parent}}{{/isEnum}}{{#items.isEnum}} + {{#items}}{{>innerModelEnum}}{{/items}}{{/items.isEnum}}{{/vars}} + +/// + /// {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} + /// + public {{^hasChildren}}sealed {{/hasChildren}}class {{classname}}: {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}> + { {{#vars}}{{^isInherited}} + /// + /// {{^description}}{{{name}}}{{/description}}{{#description}}{{description}}{{/description}} + /// + public {{>nullableDataType}} {{name}} { get; set; } +{{/isInherited}}{{/vars}} + + public override string ToString() + { + return this.PropertiesToString(); + } + + public override bool Equals(object obj) + { + return this.EqualsByProperties(obj); + } + + public bool Equals({{classname}} other) + { + return Equals((object) other); + } + + public override int GetHashCode() + { + return this.PropertiesHash(); + } + + /// + /// Implementation of == operator for ({{classname}}. + /// + /// Compared ({{classname}} + /// Compared ({{classname}} + /// true if compared items are equals, false otherwise + public static bool operator == ({{classname}} left, {{classname}} right) + { + return Equals(left, right); + } + + /// + /// Implementation of != operator for ({{classname}}. + /// + /// Compared ({{classname}} + /// Compared ({{classname}} + /// true if compared items are not equals, false otherwise + public static bool operator != ({{classname}} left, {{classname}} right) + { + return !Equals(left, right); + } + } +{{/model}} +{{/models}} +} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/nullableDataType.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/nullableDataType.mustache new file mode 100644 index 000000000000..c999b870119e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/nullableDataType.mustache @@ -0,0 +1 @@ +{{&datatypeWithEnum}}{{#isEnum}}?{{/isEnum}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/nuspec.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/nuspec.mustache new file mode 100644 index 000000000000..bc7e4d8e8e78 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/nuspec.mustache @@ -0,0 +1,14 @@ + + + + {{packageName}} + {{packageName}} + {{{version}}} + swagger-codegen + swagger-codegen + false + NancyFx {{packageName}} API{{#termsOfService}} + {{termsOfService}}{{/termsOfService}}{{#licenseUrl}} + {{licenseUrl}}{{/licenseUrl}} + + \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/packages.config.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/packages.config.mustache new file mode 100644 index 000000000000..58198276a425 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/packages.config.mustache @@ -0,0 +1,10 @@ + + + + + + + {{#dependencies}} + + {{/dependencies}} + \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/parameters.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/parameters.mustache new file mode 100644 index 000000000000..f9a55ba2b772 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/parameters.mustache @@ -0,0 +1,414 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Nancy; +using NodaTime; +using NodaTime.Text; +using Sharpility.Base; +using Sharpility.Extensions; +using Sharpility.Util; + +namespace {{packageName}}.{{packageContext}}.Utils +{ + internal static class Parameters + { + private static readonly IDictionary> Parsers = CreateParsers(); + + internal static TValue ValueOf(dynamic parameters, Request request, string name, ParameterType parameterType) + { + var valueType = typeof(TValue); + var valueUnderlyingType = Nullable.GetUnderlyingType(valueType); + var isNullable = default(TValue) == null; + string value = RawValueOf(parameters, request, name, parameterType); + Preconditions.Evaluate(!string.IsNullOrEmpty(value) || isNullable, string.Format("Required parameter: '{0}' is missing", name)); + if (value == null && isNullable) + { + return default(TValue); + } + if (valueType.IsEnum || (valueUnderlyingType != null && valueUnderlyingType.IsEnum)) + { + return EnumValueOf(name, value); + } + return ValueOf(parameters, name, value, valueType, request, parameterType); + } + + private static string RawValueOf(dynamic parameters, Request request, string name, ParameterType parameterType) + { + try + { + switch (parameterType) + { + case ParameterType.Query: + string querValue = request.Query[name]; + return querValue; + case ParameterType.Path: + string pathValue = parameters[name]; + return pathValue; + case ParameterType.Header: + var headerValue = request.Headers[name]; + return headerValue != null ? string.Join(",", headerValue) : null; + } + } + catch (Exception e) + { + throw new InvalidOperationException(string.Format("Could not obtain value of '{0}' parameter", name), e); + } + throw new InvalidOperationException(string.Format("Parameter with type: {0} is not supported", parameterType)); + } + + private static TValue EnumValueOf(string name, string value) + { + var valueType = typeof(TValue); + var enumType = valueType.IsEnum ? valueType : Nullable.GetUnderlyingType(valueType); + Preconditions.IsNotNull(enumType, () => new InvalidOperationException( + string.Format("Could not parse parameter: '{0}' to enum. Type {1} is not enum", name, valueType))); + var values = Enum.GetValues(enumType); + foreach (var entry in values) + { + if (entry.ToString().EqualsIgnoreCases(value) + || ((int)entry).ToString().EqualsIgnoreCases(value)) + { + return (TValue)entry; + } + } + throw new ArgumentException(string.Format("Parameter: '{0}' value: '{1}' is not supported. Expected one of: {2}", + name, value, Strings.ToString(values))); + } + + private static TValue ValueOf(dynamic parameters, string name, string value, Type valueType, Request request, ParameterType parameterType) + { + var parser = Parsers.GetIfPresent(valueType); + if (parser != null) + { + return ParseValueUsing(name, value, valueType, parser); + } + if (parameterType == ParameterType.Path) + { + return DynamicValueOf(parameters, name); + } + if (parameterType == ParameterType.Query) + { + return DynamicValueOf(request.Query, name); + } + throw new InvalidOperationException(string.Format("Could not get value for {0} with type {1}", name, valueType)); + } + + private static TValue ParseValueUsing(string name, string value, Type valueType, Func parser) + { + var result = parser(Parameter.Of(name, value)); + try + { + return (TValue)result; + } + catch (InvalidCastException) + { + throw new InvalidOperationException( + string.Format("Could not parse parameter: '{0}' with value: '{1}'. " + + "Received: '{2}', expected: '{3}'.", + name, value, result.GetType(), valueType)); + } + } + + private static TValue DynamicValueOf(dynamic parameters, string name) + { + string value = parameters[name]; + try + { + TValue result = parameters[name]; + return result; + } + catch (InvalidCastException) + { + throw new InvalidOperationException(Strings.Format("Parameter: '{0}' value: '{1}' could not be parsed. " + + "Expected type: '{2}' is not supported", + name, value, typeof(TValue))); + } + catch (Exception e) + { + throw new InvalidOperationException(string.Format("Could not get '{0}' value of '{1}' type dynamicly", + name, typeof(TValue)), e); + } + } + + private static IDictionary> CreateParsers() + { + var parsers = ImmutableDictionary.CreateBuilder>(); + parsers.Put(typeof(string), value => value); + parsers.Put(typeof(bool), SafeParse(bool.Parse)); + parsers.Put(typeof(bool?), SafeParse(bool.Parse)); + parsers.Put(typeof(byte), SafeParse(byte.Parse)); + parsers.Put(typeof(sbyte?), SafeParse(sbyte.Parse)); + parsers.Put(typeof(short), SafeParse(short.Parse)); + parsers.Put(typeof(short?), SafeParse(short.Parse)); + parsers.Put(typeof(ushort), SafeParse(ushort.Parse)); + parsers.Put(typeof(ushort?), SafeParse(ushort.Parse)); + parsers.Put(typeof(int), SafeParse(int.Parse)); + parsers.Put(typeof(int?), SafeParse(int.Parse)); + parsers.Put(typeof(uint), SafeParse(uint.Parse)); + parsers.Put(typeof(uint?), SafeParse(uint.Parse)); + parsers.Put(typeof(long), SafeParse(long.Parse)); + parsers.Put(typeof(long?), SafeParse(long.Parse)); + parsers.Put(typeof(ulong), SafeParse(ulong.Parse)); + parsers.Put(typeof(ulong?), SafeParse(ulong.Parse)); + parsers.Put(typeof(float), SafeParse(float.Parse)); + parsers.Put(typeof(float?), SafeParse(float.Parse)); + parsers.Put(typeof(double), SafeParse(double.Parse)); + parsers.Put(typeof(double?), SafeParse(double.Parse)); + parsers.Put(typeof(decimal), SafeParse(decimal.Parse)); + parsers.Put(typeof(decimal?), SafeParse(decimal.Parse)); + parsers.Put(typeof(DateTime), SafeParse(DateTime.Parse)); + parsers.Put(typeof(DateTime?), SafeParse(DateTime.Parse)); + parsers.Put(typeof(TimeSpan), SafeParse(TimeSpan.Parse)); + parsers.Put(typeof(TimeSpan?), SafeParse(TimeSpan.Parse)); + parsers.Put(typeof(ZonedDateTime), SafeParse(ParseZonedDateTime)); + parsers.Put(typeof(ZonedDateTime?), SafeParse(ParseZonedDateTime)); + parsers.Put(typeof(LocalTime), SafeParse(ParseLocalTime)); + parsers.Put(typeof(LocalTime?), SafeParse(ParseLocalTime)); + + parsers.Put(typeof(IEnumerable), value => value); + parsers.Put(typeof(ICollection), value => value); + parsers.Put(typeof(IList), value => value); + parsers.Put(typeof(List), value => value); + parsers.Put(typeof(ISet), value => value); + parsers.Put(typeof(HashSet), value => value); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(bool.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(bool.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(bool.Parse)); + parsers.Put(typeof(List), ListParse(bool.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(bool.Parse)); + parsers.Put(typeof(HashSet), SetParse(bool.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(byte.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(byte.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(byte.Parse)); + parsers.Put(typeof(List), ListParse(byte.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(byte.Parse)); + parsers.Put(typeof(HashSet), SetParse(byte.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(sbyte.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(sbyte.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(sbyte.Parse)); + parsers.Put(typeof(List), ListParse(sbyte.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(sbyte.Parse)); + parsers.Put(typeof(HashSet), SetParse(sbyte.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(short.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(short.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(short.Parse)); + parsers.Put(typeof(List), ListParse(short.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(short.Parse)); + parsers.Put(typeof(HashSet), SetParse(short.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(ushort.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(ushort.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(ushort.Parse)); + parsers.Put(typeof(List), ListParse(ushort.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(ushort.Parse)); + parsers.Put(typeof(HashSet), SetParse(ushort.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(int.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(int.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(int.Parse)); + parsers.Put(typeof(List), ListParse(int.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(int.Parse)); + parsers.Put(typeof(HashSet), SetParse(int.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(uint.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(uint.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(uint.Parse)); + parsers.Put(typeof(List), ListParse(uint.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(uint.Parse)); + parsers.Put(typeof(HashSet), SetParse(uint.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(long.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(long.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(long.Parse)); + parsers.Put(typeof(List), ListParse(long.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(long.Parse)); + parsers.Put(typeof(HashSet), SetParse(long.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(ulong.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(ulong.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(ulong.Parse)); + parsers.Put(typeof(List), ListParse(ulong.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(ulong.Parse)); + parsers.Put(typeof(HashSet), SetParse(ulong.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(float.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(float.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(float.Parse)); + parsers.Put(typeof(List), ListParse(float.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(float.Parse)); + parsers.Put(typeof(HashSet), SetParse(float.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(double.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(double.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(double.Parse)); + parsers.Put(typeof(List), ListParse(double.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(double.Parse)); + parsers.Put(typeof(HashSet), SetParse(double.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(decimal.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(decimal.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(decimal.Parse)); + parsers.Put(typeof(List), ListParse(decimal.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(decimal.Parse)); + parsers.Put(typeof(HashSet), SetParse(decimal.Parse)); + + + parsers.Put(typeof(IEnumerable), ImmutableListParse(DateTime.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(DateTime.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(DateTime.Parse)); + parsers.Put(typeof(List), ListParse(DateTime.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(DateTime.Parse)); + parsers.Put(typeof(HashSet), SetParse(DateTime.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(TimeSpan.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(TimeSpan.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(TimeSpan.Parse)); + parsers.Put(typeof(List), ListParse(TimeSpan.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(TimeSpan.Parse)); + parsers.Put(typeof(HashSet), SetParse(TimeSpan.Parse)); + + return parsers.ToImmutableDictionary(); + } + + private static Func SafeParse(Func parse) + { + return parameter => + { + try + { + return parse(parameter.Value); + } + catch (OverflowException) + { + throw ParameterOutOfRange(parameter, typeof(T)); + } + catch (FormatException) + { + throw InvalidParameterFormat(parameter, typeof(T)); + } + catch (Exception e) + { + throw new InvalidOperationException(Strings.Format("Unable to parse parameter: '{0}' with value: '{1}' to {2}", + parameter.Name, parameter.Value, typeof(T)), e); + } + }; + } + + private static Func ListParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return new List(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToList(); + return results; + }; + } + + private static Func ImmutableListParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return Lists.EmptyList(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToImmutableList(); + return results; + }; + } + + private static Func SetParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return new HashSet(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToSet(); + return results; + }; + } + + private static Func ImmutableSetParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return Sets.EmptySet(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToImmutableHashSet(); + return results; + }; + } + + private static ZonedDateTime ParseZonedDateTime(string value) + { + var dateTime = DateTime.Parse(value); + return new ZonedDateTime(Instant.FromDateTimeUtc(dateTime.ToUniversalTime()), DateTimeZone.Utc); + } + + private static LocalTime ParseLocalTime(string value) + { + return LocalTimePattern.ExtendedIsoPattern.Parse(value).Value; + } + + private static ArgumentException ParameterOutOfRange(Parameter parameter, Type type) + { + return new ArgumentException(Strings.Format("Query: '{0}' value: '{1}' is out of range for: '{2}'", + parameter.Name, parameter.Value, type)); + } + + private static ArgumentException InvalidParameterFormat(Parameter parameter, Type type) + { + return new ArgumentException(Strings.Format("Query '{0}' value: '{1}' format is invalid for: '{2}'", + parameter.Name, parameter.Value, type)); + } + + private class Parameter + { + internal string Name { get; private set; } + internal string Value { get; private set; } + + private Parameter(string name, string value) + { + Name = name; + Value = value; + } + + internal static Parameter Of(string name, string value) + { + return new Parameter(name, value); + } + } + } + + internal enum ParameterType + { + Undefined, + Query, + Path, + Header + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/paramsList.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/paramsList.mustache new file mode 100644 index 000000000000..a1c1d8fbaa10 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/paramsList.mustache @@ -0,0 +1 @@ +{{#allParams}}{{#isEnum}}{{>innerApiEnumName}}?{{/isEnum}}{{^isEnum}}{{&dataType}}{{/isEnum}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NancyFXServerOptionsProvider.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NancyFXServerOptionsProvider.java new file mode 100644 index 000000000000..77a374f648ee --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NancyFXServerOptionsProvider.java @@ -0,0 +1,42 @@ +package io.swagger.codegen.options; + +import static io.swagger.codegen.CodegenConstants.PACKAGE_NAME; +import static io.swagger.codegen.CodegenConstants.PACKAGE_VERSION; +import static io.swagger.codegen.CodegenConstants.RETURN_ICOLLECTION; +import static io.swagger.codegen.CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG; +import static io.swagger.codegen.CodegenConstants.SOURCE_FOLDER; +import static io.swagger.codegen.CodegenConstants.USE_COLLECTION; +import static io.swagger.codegen.CodegenConstants.USE_DATETIME_OFFSET; + +import java.util.Map; + +import com.google.common.collect.ImmutableMap; + +public class NancyFXServerOptionsProvider implements OptionsProvider { + public static final String PACKAGE_NAME_VALUE = "swagger_server_nancyfx"; + public static final String PACKAGE_VERSION_VALUE = "1.0.0-SNAPSHOT"; + public static final String SOURCE_FOLDER_VALUE = "src_nancyfx"; + + @Override + public String getLanguage() { + return "nancyfx"; + } + + @Override + public Map createOptions() { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + return builder.put(PACKAGE_NAME, PACKAGE_NAME_VALUE) + .put(PACKAGE_VERSION, PACKAGE_VERSION_VALUE) + .put(SOURCE_FOLDER, SOURCE_FOLDER_VALUE) + .put(SORT_PARAMS_BY_REQUIRED_FLAG, "true") + .put(USE_DATETIME_OFFSET, "true") + .put(USE_COLLECTION, "false") + .put(RETURN_ICOLLECTION, "false") + .build(); + } + + @Override + public boolean isServer() { + return true; + } +} diff --git a/samples/server/petstore/nancyfx/IO.Swagger.sln b/samples/server/petstore/nancyfx/IO.Swagger.sln new file mode 100644 index 000000000000..896f0bd86f63 --- /dev/null +++ b/samples/server/petstore/nancyfx/IO.Swagger.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +VisualStudioVersion = 12.0.0.0 +MinimumVisualStudioVersion = 10.0.0.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IO.Swagger", "src\IO.Swagger\IO.Swagger.csproj", "{1DE2DD8D-1AFB-4BC2-9FB5-04DE7DCA1353}" +EndProject +Global +GlobalSection(SolutionConfigurationPlatforms) = preSolution +Debug|Any CPU = Debug|Any CPU +Release|Any CPU = Release|Any CPU +EndGlobalSection +GlobalSection(ProjectConfigurationPlatforms) = postSolution +{1DE2DD8D-1AFB-4BC2-9FB5-04DE7DCA1353}.Debug|Any CPU.ActiveCfg = Debug|Any CPU +{1DE2DD8D-1AFB-4BC2-9FB5-04DE7DCA1353}.Debug|Any CPU.Build.0 = Debug|Any CPU +{1DE2DD8D-1AFB-4BC2-9FB5-04DE7DCA1353}.Release|Any CPU.ActiveCfg = Release|Any CPU +{1DE2DD8D-1AFB-4BC2-9FB5-04DE7DCA1353}.Release|Any CPU.Build.0 = Release|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Debug|Any CPU.Build.0 = Debug|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Release|Any CPU.ActiveCfg = Release|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Release|Any CPU.Build.0 = Release|Any CPU +EndGlobalSection +GlobalSection(SolutionProperties) = preSolution +HideSolutionNode = FALSE +EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/IO.Swagger.csproj b/samples/server/petstore/nancyfx/src/IO.Swagger/IO.Swagger.csproj new file mode 100644 index 000000000000..46fb435d4192 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/IO.Swagger.csproj @@ -0,0 +1,66 @@ + + + + Debug + AnyCPU + {1DE2DD8D-1AFB-4BC2-9FB5-04DE7DCA1353} + Library + Properties + IO.Swagger.v2 + + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\IO.Swagger.XML + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\IO.Swagger.XML + + + + ..\..\packages\Nancy.1.4.1\lib\net40\Nancy.dll + True + + + ..\..\packages\NodaTime.1.3.1\lib\net35-Client\NodaTime.dll + True + + + ..\..\packages\Sharpility.1.2.1\lib\net45\Sharpility.dll + True + + + ..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + + + + + + + + + + + + + + + + + + diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/IO.Swagger.nuspec b/samples/server/petstore/nancyfx/src/IO.Swagger/IO.Swagger.nuspec new file mode 100644 index 000000000000..f6ab1af8e9b9 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/IO.Swagger.nuspec @@ -0,0 +1,14 @@ + + + + IO.Swagger + IO.Swagger + 1.0.0 + swagger-codegen + swagger-codegen + false + NancyFx IO.Swagger API + http://helloreverb.com/terms/ + http://www.apache.org/licenses/LICENSE-2.0.html + + \ No newline at end of file diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Category.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Category.cs new file mode 100644 index 000000000000..759bedd74a99 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Category.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Sharpility.Extensions; +using NodaTime; + +namespace IO.Swagger.v2.Models +{ + /// + /// Category + /// + public sealed class Category: IEquatable + { + /// + /// Id + /// + public long? Id { get; private set; } + + /// + /// Name + /// + public string Name { get; private set; } + + + /// + /// Empty constructor required by some serializers. + /// Use Category.Builder() for instance creation instead. + /// + [Obsolete] + public Category() + { + } + + private Category(long? Id, string Name) + { + + this.Id = Id; + + this.Name = Name; + + } + + /// + /// Returns builder of Category. + /// + /// CategoryBuilder + public static CategoryBuilder Builder() + { + return new CategoryBuilder(); + } + + /// + /// Returns CategoryBuilder with properties set. + /// Use it to change properties. + /// + /// CategoryBuilder + public CategoryBuilder With() + { + return Builder() + .Id(Id) + .Name(Name); + } + + public override string ToString() + { + return this.PropertiesToString(); + } + + public override bool Equals(object obj) + { + return this.EqualsByProperties(obj); + } + + public bool Equals(Category other) + { + return Equals((object) other); + } + + public override int GetHashCode() + { + return this.PropertiesHash(); + } + + /// + /// Implementation of == operator for (Category. + /// + /// Compared (Category + /// Compared (Category + /// true if compared items are equals, false otherwise + public static bool operator == (Category left, Category right) + { + return Equals(left, right); + } + + /// + /// Implementation of != operator for (Category. + /// + /// Compared (Category + /// Compared (Category + /// true if compared items are not equals, false otherwise + public static bool operator != (Category left, Category right) + { + return !Equals(left, right); + } + + /// + /// Builder of Category. + /// + public sealed class CategoryBuilder + { + private long? _Id; + private string _Name; + + internal CategoryBuilder() + { + SetupDefaults(); + } + + private void SetupDefaults() + { + } + + /// + /// Sets value for Category.Id property. + /// + /// Id + public CategoryBuilder Id(long? value) + { + _Id = value; + return this; + } + + /// + /// Sets value for Category.Name property. + /// + /// Name + public CategoryBuilder Name(string value) + { + _Name = value; + return this; + } + + + /// + /// Builds instance of Category. + /// + /// Category + public Category Build() + { + Validate(); + return new Category( + Id: _Id, + Name: _Name + ); + } + + private void Validate() + { + } + } + + + } +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Order.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Order.cs new file mode 100644 index 000000000000..22245ee5bfeb --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Order.cs @@ -0,0 +1,246 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Sharpility.Extensions; +using NodaTime; + +namespace IO.Swagger.v2.Models +{ + /// + /// Order + /// + public sealed class Order: IEquatable + { + /// + /// Id + /// + public long? Id { get; private set; } + + /// + /// PetId + /// + public long? PetId { get; private set; } + + /// + /// Quantity + /// + public int? Quantity { get; private set; } + + /// + /// ShipDate + /// + public ZonedDateTime? ShipDate { get; private set; } + + /// + /// Order Status + /// + public StatusEnum? Status { get; private set; } + + /// + /// Complete + /// + public bool? Complete { get; private set; } + + + /// + /// Empty constructor required by some serializers. + /// Use Order.Builder() for instance creation instead. + /// + [Obsolete] + public Order() + { + } + + private Order(long? Id, long? PetId, int? Quantity, ZonedDateTime? ShipDate, StatusEnum? Status, bool? Complete) + { + + this.Id = Id; + + this.PetId = PetId; + + this.Quantity = Quantity; + + this.ShipDate = ShipDate; + + this.Status = Status; + + this.Complete = Complete; + + } + + /// + /// Returns builder of Order. + /// + /// OrderBuilder + public static OrderBuilder Builder() + { + return new OrderBuilder(); + } + + /// + /// Returns OrderBuilder with properties set. + /// Use it to change properties. + /// + /// OrderBuilder + public OrderBuilder With() + { + return Builder() + .Id(Id) + .PetId(PetId) + .Quantity(Quantity) + .ShipDate(ShipDate) + .Status(Status) + .Complete(Complete); + } + + public override string ToString() + { + return this.PropertiesToString(); + } + + public override bool Equals(object obj) + { + return this.EqualsByProperties(obj); + } + + public bool Equals(Order other) + { + return Equals((object) other); + } + + public override int GetHashCode() + { + return this.PropertiesHash(); + } + + /// + /// Implementation of == operator for (Order. + /// + /// Compared (Order + /// Compared (Order + /// true if compared items are equals, false otherwise + public static bool operator == (Order left, Order right) + { + return Equals(left, right); + } + + /// + /// Implementation of != operator for (Order. + /// + /// Compared (Order + /// Compared (Order + /// true if compared items are not equals, false otherwise + public static bool operator != (Order left, Order right) + { + return !Equals(left, right); + } + + /// + /// Builder of Order. + /// + public sealed class OrderBuilder + { + private long? _Id; + private long? _PetId; + private int? _Quantity; + private ZonedDateTime? _ShipDate; + private StatusEnum? _Status; + private bool? _Complete; + + internal OrderBuilder() + { + SetupDefaults(); + } + + private void SetupDefaults() + { + } + + /// + /// Sets value for Order.Id property. + /// + /// Id + public OrderBuilder Id(long? value) + { + _Id = value; + return this; + } + + /// + /// Sets value for Order.PetId property. + /// + /// PetId + public OrderBuilder PetId(long? value) + { + _PetId = value; + return this; + } + + /// + /// Sets value for Order.Quantity property. + /// + /// Quantity + public OrderBuilder Quantity(int? value) + { + _Quantity = value; + return this; + } + + /// + /// Sets value for Order.ShipDate property. + /// + /// ShipDate + public OrderBuilder ShipDate(ZonedDateTime? value) + { + _ShipDate = value; + return this; + } + + /// + /// Sets value for Order.Status property. + /// + /// Order Status + public OrderBuilder Status(StatusEnum? value) + { + _Status = value; + return this; + } + + /// + /// Sets value for Order.Complete property. + /// + /// Complete + public OrderBuilder Complete(bool? value) + { + _Complete = value; + return this; + } + + + /// + /// Builds instance of Order. + /// + /// Order + public Order Build() + { + Validate(); + return new Order( + Id: _Id, + PetId: _PetId, + Quantity: _Quantity, + ShipDate: _ShipDate, + Status: _Status, + Complete: _Complete + ); + } + + private void Validate() + { + } + } + + + public enum StatusEnum { Placed, Approved, Delivered }; + } +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Pet.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Pet.cs new file mode 100644 index 000000000000..aef03f6ba970 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Pet.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Sharpility.Extensions; +using NodaTime; + +namespace IO.Swagger.v2.Models +{ + /// + /// Pet + /// + public sealed class Pet: IEquatable + { + /// + /// Id + /// + public long? Id { get; private set; } + + /// + /// Category + /// + public Category Category { get; private set; } + + /// + /// Name + /// + public string Name { get; private set; } + + /// + /// PhotoUrls + /// + public List PhotoUrls { get; private set; } + + /// + /// Tags + /// + public List Tags { get; private set; } + + /// + /// pet status in the store + /// + public StatusEnum? Status { get; private set; } + + + /// + /// Empty constructor required by some serializers. + /// Use Pet.Builder() for instance creation instead. + /// + [Obsolete] + public Pet() + { + } + + private Pet(long? Id, Category Category, string Name, List PhotoUrls, List Tags, StatusEnum? Status) + { + + this.Id = Id; + + this.Category = Category; + + this.Name = Name; + + this.PhotoUrls = PhotoUrls; + + this.Tags = Tags; + + this.Status = Status; + + } + + /// + /// Returns builder of Pet. + /// + /// PetBuilder + public static PetBuilder Builder() + { + return new PetBuilder(); + } + + /// + /// Returns PetBuilder with properties set. + /// Use it to change properties. + /// + /// PetBuilder + public PetBuilder With() + { + return Builder() + .Id(Id) + .Category(Category) + .Name(Name) + .PhotoUrls(PhotoUrls) + .Tags(Tags) + .Status(Status); + } + + public override string ToString() + { + return this.PropertiesToString(); + } + + public override bool Equals(object obj) + { + return this.EqualsByProperties(obj); + } + + public bool Equals(Pet other) + { + return Equals((object) other); + } + + public override int GetHashCode() + { + return this.PropertiesHash(); + } + + /// + /// Implementation of == operator for (Pet. + /// + /// Compared (Pet + /// Compared (Pet + /// true if compared items are equals, false otherwise + public static bool operator == (Pet left, Pet right) + { + return Equals(left, right); + } + + /// + /// Implementation of != operator for (Pet. + /// + /// Compared (Pet + /// Compared (Pet + /// true if compared items are not equals, false otherwise + public static bool operator != (Pet left, Pet right) + { + return !Equals(left, right); + } + + /// + /// Builder of Pet. + /// + public sealed class PetBuilder + { + private long? _Id; + private Category _Category; + private string _Name; + private List _PhotoUrls; + private List _Tags; + private StatusEnum? _Status; + + internal PetBuilder() + { + SetupDefaults(); + } + + private void SetupDefaults() + { + } + + /// + /// Sets value for Pet.Id property. + /// + /// Id + public PetBuilder Id(long? value) + { + _Id = value; + return this; + } + + /// + /// Sets value for Pet.Category property. + /// + /// Category + public PetBuilder Category(Category value) + { + _Category = value; + return this; + } + + /// + /// Sets value for Pet.Name property. + /// + /// Name + public PetBuilder Name(string value) + { + _Name = value; + return this; + } + + /// + /// Sets value for Pet.PhotoUrls property. + /// + /// PhotoUrls + public PetBuilder PhotoUrls(List value) + { + _PhotoUrls = value; + return this; + } + + /// + /// Sets value for Pet.Tags property. + /// + /// Tags + public PetBuilder Tags(List value) + { + _Tags = value; + return this; + } + + /// + /// Sets value for Pet.Status property. + /// + /// pet status in the store + public PetBuilder Status(StatusEnum? value) + { + _Status = value; + return this; + } + + + /// + /// Builds instance of Pet. + /// + /// Pet + public Pet Build() + { + Validate(); + return new Pet( + Id: _Id, + Category: _Category, + Name: _Name, + PhotoUrls: _PhotoUrls, + Tags: _Tags, + Status: _Status + ); + } + + private void Validate() + { + if (_Name == null) + { + throw new ArgumentException("Name is a required property for Pet and cannot be null"); + } + if (_PhotoUrls == null) + { + throw new ArgumentException("PhotoUrls is a required property for Pet and cannot be null"); + } + } + } + + + public enum StatusEnum { Available, Pending, Sold }; + } +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Tag.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Tag.cs new file mode 100644 index 000000000000..36fd8204a8a8 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/Tag.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Sharpility.Extensions; +using NodaTime; + +namespace IO.Swagger.v2.Models +{ + /// + /// Tag + /// + public sealed class Tag: IEquatable + { + /// + /// Id + /// + public long? Id { get; private set; } + + /// + /// Name + /// + public string Name { get; private set; } + + + /// + /// Empty constructor required by some serializers. + /// Use Tag.Builder() for instance creation instead. + /// + [Obsolete] + public Tag() + { + } + + private Tag(long? Id, string Name) + { + + this.Id = Id; + + this.Name = Name; + + } + + /// + /// Returns builder of Tag. + /// + /// TagBuilder + public static TagBuilder Builder() + { + return new TagBuilder(); + } + + /// + /// Returns TagBuilder with properties set. + /// Use it to change properties. + /// + /// TagBuilder + public TagBuilder With() + { + return Builder() + .Id(Id) + .Name(Name); + } + + public override string ToString() + { + return this.PropertiesToString(); + } + + public override bool Equals(object obj) + { + return this.EqualsByProperties(obj); + } + + public bool Equals(Tag other) + { + return Equals((object) other); + } + + public override int GetHashCode() + { + return this.PropertiesHash(); + } + + /// + /// Implementation of == operator for (Tag. + /// + /// Compared (Tag + /// Compared (Tag + /// true if compared items are equals, false otherwise + public static bool operator == (Tag left, Tag right) + { + return Equals(left, right); + } + + /// + /// Implementation of != operator for (Tag. + /// + /// Compared (Tag + /// Compared (Tag + /// true if compared items are not equals, false otherwise + public static bool operator != (Tag left, Tag right) + { + return !Equals(left, right); + } + + /// + /// Builder of Tag. + /// + public sealed class TagBuilder + { + private long? _Id; + private string _Name; + + internal TagBuilder() + { + SetupDefaults(); + } + + private void SetupDefaults() + { + } + + /// + /// Sets value for Tag.Id property. + /// + /// Id + public TagBuilder Id(long? value) + { + _Id = value; + return this; + } + + /// + /// Sets value for Tag.Name property. + /// + /// Name + public TagBuilder Name(string value) + { + _Name = value; + return this; + } + + + /// + /// Builds instance of Tag. + /// + /// Tag + public Tag Build() + { + Validate(); + return new Tag( + Id: _Id, + Name: _Name + ); + } + + private void Validate() + { + } + } + + + } +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Models/User.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/User.cs new file mode 100644 index 000000000000..69d079ff42d2 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Models/User.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Sharpility.Extensions; +using NodaTime; + +namespace IO.Swagger.v2.Models +{ + /// + /// User + /// + public sealed class User: IEquatable + { + /// + /// Id + /// + public long? Id { get; private set; } + + /// + /// Username + /// + public string Username { get; private set; } + + /// + /// FirstName + /// + public string FirstName { get; private set; } + + /// + /// LastName + /// + public string LastName { get; private set; } + + /// + /// Email + /// + public string Email { get; private set; } + + /// + /// Password + /// + public string Password { get; private set; } + + /// + /// Phone + /// + public string Phone { get; private set; } + + /// + /// User Status + /// + public int? UserStatus { get; private set; } + + + /// + /// Empty constructor required by some serializers. + /// Use User.Builder() for instance creation instead. + /// + [Obsolete] + public User() + { + } + + private User(long? Id, string Username, string FirstName, string LastName, string Email, string Password, string Phone, int? UserStatus) + { + + this.Id = Id; + + this.Username = Username; + + this.FirstName = FirstName; + + this.LastName = LastName; + + this.Email = Email; + + this.Password = Password; + + this.Phone = Phone; + + this.UserStatus = UserStatus; + + } + + /// + /// Returns builder of User. + /// + /// UserBuilder + public static UserBuilder Builder() + { + return new UserBuilder(); + } + + /// + /// Returns UserBuilder with properties set. + /// Use it to change properties. + /// + /// UserBuilder + public UserBuilder With() + { + return Builder() + .Id(Id) + .Username(Username) + .FirstName(FirstName) + .LastName(LastName) + .Email(Email) + .Password(Password) + .Phone(Phone) + .UserStatus(UserStatus); + } + + public override string ToString() + { + return this.PropertiesToString(); + } + + public override bool Equals(object obj) + { + return this.EqualsByProperties(obj); + } + + public bool Equals(User other) + { + return Equals((object) other); + } + + public override int GetHashCode() + { + return this.PropertiesHash(); + } + + /// + /// Implementation of == operator for (User. + /// + /// Compared (User + /// Compared (User + /// true if compared items are equals, false otherwise + public static bool operator == (User left, User right) + { + return Equals(left, right); + } + + /// + /// Implementation of != operator for (User. + /// + /// Compared (User + /// Compared (User + /// true if compared items are not equals, false otherwise + public static bool operator != (User left, User right) + { + return !Equals(left, right); + } + + /// + /// Builder of User. + /// + public sealed class UserBuilder + { + private long? _Id; + private string _Username; + private string _FirstName; + private string _LastName; + private string _Email; + private string _Password; + private string _Phone; + private int? _UserStatus; + + internal UserBuilder() + { + SetupDefaults(); + } + + private void SetupDefaults() + { + } + + /// + /// Sets value for User.Id property. + /// + /// Id + public UserBuilder Id(long? value) + { + _Id = value; + return this; + } + + /// + /// Sets value for User.Username property. + /// + /// Username + public UserBuilder Username(string value) + { + _Username = value; + return this; + } + + /// + /// Sets value for User.FirstName property. + /// + /// FirstName + public UserBuilder FirstName(string value) + { + _FirstName = value; + return this; + } + + /// + /// Sets value for User.LastName property. + /// + /// LastName + public UserBuilder LastName(string value) + { + _LastName = value; + return this; + } + + /// + /// Sets value for User.Email property. + /// + /// Email + public UserBuilder Email(string value) + { + _Email = value; + return this; + } + + /// + /// Sets value for User.Password property. + /// + /// Password + public UserBuilder Password(string value) + { + _Password = value; + return this; + } + + /// + /// Sets value for User.Phone property. + /// + /// Phone + public UserBuilder Phone(string value) + { + _Phone = value; + return this; + } + + /// + /// Sets value for User.UserStatus property. + /// + /// User Status + public UserBuilder UserStatus(int? value) + { + _UserStatus = value; + return this; + } + + + /// + /// Builds instance of User. + /// + /// User + public User Build() + { + Validate(); + return new User( + Id: _Id, + Username: _Username, + FirstName: _FirstName, + LastName: _LastName, + Email: _Email, + Password: _Password, + Phone: _Phone, + UserStatus: _UserStatus + ); + } + + private void Validate() + { + } + } + + + } +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/PetModule.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/PetModule.cs new file mode 100644 index 000000000000..f3ab9ee2892c --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/PetModule.cs @@ -0,0 +1,229 @@ +using System; +using Nancy; +using Nancy.ModelBinding; +using System.Collections.Generic; +using Sharpility.Base; +using IO.Swagger.v2.Models; +using IO.Swagger.v2.Utils; +using NodaTime; + +namespace IO.Swagger.v2.Modules +{ + + /// + /// Module processing requests of Pet domain. + /// + public sealed class PetModule : NancyModule + { + /// + /// Sets up HTTP methods mappings. + /// + /// Service handling requests + public PetModule(PetService service) : base("/v2") + { + Post["/pet"] = parameters => + { + var body = this.Bind(); + service.AddPet(Context, body); + return new Response { ContentType = "application/json"}; + }; + + Delete["/pet/{petId}"] = parameters => + { + var petId = Parameters.ValueOf(parameters, Context.Request, "petId", ParameterType.Path); + var apiKey = Parameters.ValueOf(parameters, Context.Request, "apiKey", ParameterType.Header); + Preconditions.IsNotNull(petId, "Required parameter: 'petId' is missing at 'DeletePet'"); + + service.DeletePet(Context, petId, apiKey); + return new Response { ContentType = "application/json"}; + }; + + Get["/pet/findByStatus"] = parameters => + { + var status = Parameters.ValueOf>(parameters, Context.Request, "status", ParameterType.Query); + return service.FindPetsByStatus(Context, status); + }; + + Get["/pet/findByTags"] = parameters => + { + var tags = Parameters.ValueOf>(parameters, Context.Request, "tags", ParameterType.Query); + return service.FindPetsByTags(Context, tags); + }; + + Get["/pet/{petId}"] = parameters => + { + var petId = Parameters.ValueOf(parameters, Context.Request, "petId", ParameterType.Path); + Preconditions.IsNotNull(petId, "Required parameter: 'petId' is missing at 'GetPetById'"); + + return service.GetPetById(Context, petId); + }; + + Put["/pet"] = parameters => + { + var body = this.Bind(); + service.UpdatePet(Context, body); + return new Response { ContentType = "application/json"}; + }; + + Post["/pet/{petId}"] = parameters => + { + var petId = Parameters.ValueOf(parameters, Context.Request, "petId", ParameterType.Path); + var name = Parameters.ValueOf(parameters, Context.Request, "name", ParameterType.Undefined); + var status = Parameters.ValueOf(parameters, Context.Request, "status", ParameterType.Undefined); + Preconditions.IsNotNull(petId, "Required parameter: 'petId' is missing at 'UpdatePetWithForm'"); + + service.UpdatePetWithForm(Context, petId, name, status); + return new Response { ContentType = "application/json"}; + }; + + Post["/pet/{petId}/uploadImage"] = parameters => + { + var petId = Parameters.ValueOf(parameters, Context.Request, "petId", ParameterType.Path); + var additionalMetadata = Parameters.ValueOf(parameters, Context.Request, "additionalMetadata", ParameterType.Undefined); + var file = Parameters.ValueOf(parameters, Context.Request, "file", ParameterType.Undefined); + Preconditions.IsNotNull(petId, "Required parameter: 'petId' is missing at 'UploadFile'"); + + service.UploadFile(Context, petId, additionalMetadata, file); + return new Response { ContentType = "application/json"}; + }; + } + } + + /// + /// Service handling Pet requests. + /// + public interface PetService + { + /// + /// + /// + /// Context of request + /// Pet object that needs to be added to the store (optional) + /// + void AddPet(NancyContext context, Pet body); + + /// + /// + /// + /// Context of request + /// Pet id to delete + /// (optional) + /// + void DeletePet(NancyContext context, long? petId, string apiKey); + + /// + /// Multiple status values can be provided with comma seperated strings + /// + /// Context of request + /// Status values that need to be considered for filter (optional, default to available) + /// List<Pet> + List FindPetsByStatus(NancyContext context, List status); + + /// + /// Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing. + /// + /// Context of request + /// Tags to filter by (optional) + /// List<Pet> + List FindPetsByTags(NancyContext context, List tags); + + /// + /// Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions + /// + /// Context of request + /// ID of pet that needs to be fetched + /// Pet + Pet GetPetById(NancyContext context, long? petId); + + /// + /// + /// + /// Context of request + /// Pet object that needs to be added to the store (optional) + /// + void UpdatePet(NancyContext context, Pet body); + + /// + /// + /// + /// Context of request + /// ID of pet that needs to be updated + /// Updated name of the pet (optional) + /// Updated status of the pet (optional) + /// + void UpdatePetWithForm(NancyContext context, string petId, string name, string status); + + /// + /// + /// + /// Context of request + /// ID of pet to update + /// Additional data to pass to server (optional) + /// file to upload (optional) + /// + void UploadFile(NancyContext context, long? petId, string additionalMetadata, System.IO.Stream file); + } + + /// + /// Abstraction of PetService. + /// + public abstract class AbstractPetService: PetService + { + public virtual void AddPet(NancyContext context, Pet body) + { + AddPet(body); + } + + public virtual void DeletePet(NancyContext context, long? petId, string apiKey) + { + DeletePet(petId, apiKey); + } + + public virtual List FindPetsByStatus(NancyContext context, List status) + { + return FindPetsByStatus(status); + } + + public virtual List FindPetsByTags(NancyContext context, List tags) + { + return FindPetsByTags(tags); + } + + public virtual Pet GetPetById(NancyContext context, long? petId) + { + return GetPetById(petId); + } + + public virtual void UpdatePet(NancyContext context, Pet body) + { + UpdatePet(body); + } + + public virtual void UpdatePetWithForm(NancyContext context, string petId, string name, string status) + { + UpdatePetWithForm(petId, name, status); + } + + public virtual void UploadFile(NancyContext context, long? petId, string additionalMetadata, System.IO.Stream file) + { + UploadFile(petId, additionalMetadata, file); + } + + protected abstract void AddPet(Pet body); + + protected abstract void DeletePet(long? petId, string apiKey); + + protected abstract List FindPetsByStatus(List status); + + protected abstract List FindPetsByTags(List tags); + + protected abstract Pet GetPetById(long? petId); + + protected abstract void UpdatePet(Pet body); + + protected abstract void UpdatePetWithForm(string petId, string name, string status); + + protected abstract void UploadFile(long? petId, string additionalMetadata, System.IO.Stream file); + } + +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/StoreModule.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/StoreModule.cs new file mode 100644 index 000000000000..06f397db4082 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/StoreModule.cs @@ -0,0 +1,126 @@ +using System; +using Nancy; +using Nancy.ModelBinding; +using System.Collections.Generic; +using Sharpility.Base; +using IO.Swagger.v2.Models; +using IO.Swagger.v2.Utils; +using NodaTime; + +namespace IO.Swagger.v2.Modules +{ + + /// + /// Module processing requests of Store domain. + /// + public sealed class StoreModule : NancyModule + { + /// + /// Sets up HTTP methods mappings. + /// + /// Service handling requests + public StoreModule(StoreService service) : base("/v2") + { + Delete["/store/order/{orderId}"] = parameters => + { + var orderId = Parameters.ValueOf(parameters, Context.Request, "orderId", ParameterType.Path); + Preconditions.IsNotNull(orderId, "Required parameter: 'orderId' is missing at 'DeleteOrder'"); + + service.DeleteOrder(Context, orderId); + return new Response { ContentType = "application/json"}; + }; + + Get["/store/inventory"] = parameters => + { + + return service.GetInventory(Context); + }; + + Get["/store/order/{orderId}"] = parameters => + { + var orderId = Parameters.ValueOf(parameters, Context.Request, "orderId", ParameterType.Path); + Preconditions.IsNotNull(orderId, "Required parameter: 'orderId' is missing at 'GetOrderById'"); + + return service.GetOrderById(Context, orderId); + }; + + Post["/store/order"] = parameters => + { + var body = this.Bind(); + return service.PlaceOrder(Context, body); + }; + } + } + + /// + /// Service handling Store requests. + /// + public interface StoreService + { + /// + /// For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + /// + /// Context of request + /// ID of the order that needs to be deleted + /// + void DeleteOrder(NancyContext context, string orderId); + + /// + /// Returns a map of status codes to quantities + /// + /// Context of request + /// Dictionary<string, int?> + Dictionary GetInventory(NancyContext context); + + /// + /// For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions + /// + /// Context of request + /// ID of pet that needs to be fetched + /// Order + Order GetOrderById(NancyContext context, string orderId); + + /// + /// + /// + /// Context of request + /// order placed for purchasing the pet (optional) + /// Order + Order PlaceOrder(NancyContext context, Order body); + } + + /// + /// Abstraction of StoreService. + /// + public abstract class AbstractStoreService: StoreService + { + public virtual void DeleteOrder(NancyContext context, string orderId) + { + DeleteOrder(orderId); + } + + public virtual Dictionary GetInventory(NancyContext context) + { + return GetInventory(); + } + + public virtual Order GetOrderById(NancyContext context, string orderId) + { + return GetOrderById(orderId); + } + + public virtual Order PlaceOrder(NancyContext context, Order body) + { + return PlaceOrder(body); + } + + protected abstract void DeleteOrder(string orderId); + + protected abstract Dictionary GetInventory(); + + protected abstract Order GetOrderById(string orderId); + + protected abstract Order PlaceOrder(Order body); + } + +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/UserModule.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/UserModule.cs new file mode 100644 index 000000000000..8350479ef121 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Modules/UserModule.cs @@ -0,0 +1,221 @@ +using System; +using Nancy; +using Nancy.ModelBinding; +using System.Collections.Generic; +using Sharpility.Base; +using IO.Swagger.v2.Models; +using IO.Swagger.v2.Utils; +using NodaTime; + +namespace IO.Swagger.v2.Modules +{ + + /// + /// Module processing requests of User domain. + /// + public sealed class UserModule : NancyModule + { + /// + /// Sets up HTTP methods mappings. + /// + /// Service handling requests + public UserModule(UserService service) : base("/v2") + { + Post["/user"] = parameters => + { + var body = this.Bind(); + service.CreateUser(Context, body); + return new Response { ContentType = "application/json"}; + }; + + Post["/user/createWithArray"] = parameters => + { + var body = this.Bind>(); + service.CreateUsersWithArrayInput(Context, body); + return new Response { ContentType = "application/json"}; + }; + + Post["/user/createWithList"] = parameters => + { + var body = this.Bind>(); + service.CreateUsersWithListInput(Context, body); + return new Response { ContentType = "application/json"}; + }; + + Delete["/user/{username}"] = parameters => + { + var username = Parameters.ValueOf(parameters, Context.Request, "username", ParameterType.Path); + Preconditions.IsNotNull(username, "Required parameter: 'username' is missing at 'DeleteUser'"); + + service.DeleteUser(Context, username); + return new Response { ContentType = "application/json"}; + }; + + Get["/user/{username}"] = parameters => + { + var username = Parameters.ValueOf(parameters, Context.Request, "username", ParameterType.Path); + Preconditions.IsNotNull(username, "Required parameter: 'username' is missing at 'GetUserByName'"); + + return service.GetUserByName(Context, username); + }; + + Get["/user/login"] = parameters => + { + var username = Parameters.ValueOf(parameters, Context.Request, "username", ParameterType.Query); + var password = Parameters.ValueOf(parameters, Context.Request, "password", ParameterType.Query); + return service.LoginUser(Context, username, password); + }; + + Get["/user/logout"] = parameters => + { + + service.LogoutUser(Context); + return new Response { ContentType = "application/json"}; + }; + + Put["/user/{username}"] = parameters => + { + var username = Parameters.ValueOf(parameters, Context.Request, "username", ParameterType.Path); + var body = this.Bind(); + Preconditions.IsNotNull(username, "Required parameter: 'username' is missing at 'UpdateUser'"); + + service.UpdateUser(Context, username, body); + return new Response { ContentType = "application/json"}; + }; + } + } + + /// + /// Service handling User requests. + /// + public interface UserService + { + /// + /// This can only be done by the logged in user. + /// + /// Context of request + /// Created user object (optional) + /// + void CreateUser(NancyContext context, User body); + + /// + /// + /// + /// Context of request + /// List of user object (optional) + /// + void CreateUsersWithArrayInput(NancyContext context, List body); + + /// + /// + /// + /// Context of request + /// List of user object (optional) + /// + void CreateUsersWithListInput(NancyContext context, List body); + + /// + /// This can only be done by the logged in user. + /// + /// Context of request + /// The name that needs to be deleted + /// + void DeleteUser(NancyContext context, string username); + + /// + /// + /// + /// Context of request + /// The name that needs to be fetched. Use user1 for testing. + /// User + User GetUserByName(NancyContext context, string username); + + /// + /// + /// + /// Context of request + /// The user name for login (optional) + /// The password for login in clear text (optional) + /// string + string LoginUser(NancyContext context, string username, string password); + + /// + /// + /// + /// Context of request + /// + void LogoutUser(NancyContext context); + + /// + /// This can only be done by the logged in user. + /// + /// Context of request + /// name that need to be deleted + /// Updated user object (optional) + /// + void UpdateUser(NancyContext context, string username, User body); + } + + /// + /// Abstraction of UserService. + /// + public abstract class AbstractUserService: UserService + { + public virtual void CreateUser(NancyContext context, User body) + { + CreateUser(body); + } + + public virtual void CreateUsersWithArrayInput(NancyContext context, List body) + { + CreateUsersWithArrayInput(body); + } + + public virtual void CreateUsersWithListInput(NancyContext context, List body) + { + CreateUsersWithListInput(body); + } + + public virtual void DeleteUser(NancyContext context, string username) + { + DeleteUser(username); + } + + public virtual User GetUserByName(NancyContext context, string username) + { + return GetUserByName(username); + } + + public virtual string LoginUser(NancyContext context, string username, string password) + { + return LoginUser(username, password); + } + + public virtual void LogoutUser(NancyContext context) + { + LogoutUser(); + } + + public virtual void UpdateUser(NancyContext context, string username, User body) + { + UpdateUser(username, body); + } + + protected abstract void CreateUser(User body); + + protected abstract void CreateUsersWithArrayInput(List body); + + protected abstract void CreateUsersWithListInput(List body); + + protected abstract void DeleteUser(string username); + + protected abstract User GetUserByName(string username); + + protected abstract string LoginUser(string username, string password); + + protected abstract void LogoutUser(); + + protected abstract void UpdateUser(string username, User body); + } + +} diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/Utils/Parameters.cs b/samples/server/petstore/nancyfx/src/IO.Swagger/Utils/Parameters.cs new file mode 100644 index 000000000000..954683f095f5 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/Utils/Parameters.cs @@ -0,0 +1,414 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Nancy; +using NodaTime; +using NodaTime.Text; +using Sharpility.Base; +using Sharpility.Extensions; +using Sharpility.Util; + +namespace IO.Swagger.v2.Utils +{ + internal static class Parameters + { + private static readonly IDictionary> Parsers = CreateParsers(); + + internal static TValue ValueOf(dynamic parameters, Request request, string name, ParameterType parameterType) + { + var valueType = typeof(TValue); + var valueUnderlyingType = Nullable.GetUnderlyingType(valueType); + var isNullable = default(TValue) == null; + string value = RawValueOf(parameters, request, name, parameterType); + Preconditions.Evaluate(!string.IsNullOrEmpty(value) || isNullable, string.Format("Required parameter: '{0}' is missing", name)); + if (value == null && isNullable) + { + return default(TValue); + } + if (valueType.IsEnum || (valueUnderlyingType != null && valueUnderlyingType.IsEnum)) + { + return EnumValueOf(name, value); + } + return ValueOf(parameters, name, value, valueType, request, parameterType); + } + + private static string RawValueOf(dynamic parameters, Request request, string name, ParameterType parameterType) + { + try + { + switch (parameterType) + { + case ParameterType.Query: + string querValue = request.Query[name]; + return querValue; + case ParameterType.Path: + string pathValue = parameters[name]; + return pathValue; + case ParameterType.Header: + var headerValue = request.Headers[name]; + return headerValue != null ? string.Join(",", headerValue) : null; + } + } + catch (Exception e) + { + throw new InvalidOperationException(string.Format("Could not obtain value of '{0}' parameter", name), e); + } + throw new InvalidOperationException(string.Format("Parameter with type: {0} is not supported", parameterType)); + } + + private static TValue EnumValueOf(string name, string value) + { + var valueType = typeof(TValue); + var enumType = valueType.IsEnum ? valueType : Nullable.GetUnderlyingType(valueType); + Preconditions.IsNotNull(enumType, () => new InvalidOperationException( + string.Format("Could not parse parameter: '{0}' to enum. Type {1} is not enum", name, valueType))); + var values = Enum.GetValues(enumType); + foreach (var entry in values) + { + if (entry.ToString().EqualsIgnoreCases(value) + || ((int)entry).ToString().EqualsIgnoreCases(value)) + { + return (TValue)entry; + } + } + throw new ArgumentException(string.Format("Parameter: '{0}' value: '{1}' is not supported. Expected one of: {2}", + name, value, Strings.ToString(values))); + } + + private static TValue ValueOf(dynamic parameters, string name, string value, Type valueType, Request request, ParameterType parameterType) + { + var parser = Parsers.GetIfPresent(valueType); + if (parser != null) + { + return ParseValueUsing(name, value, valueType, parser); + } + if (parameterType == ParameterType.Path) + { + return DynamicValueOf(parameters, name); + } + if (parameterType == ParameterType.Query) + { + return DynamicValueOf(request.Query, name); + } + throw new InvalidOperationException(string.Format("Could not get value for {0} with type {1}", name, valueType)); + } + + private static TValue ParseValueUsing(string name, string value, Type valueType, Func parser) + { + var result = parser(Parameter.Of(name, value)); + try + { + return (TValue)result; + } + catch (InvalidCastException) + { + throw new InvalidOperationException( + string.Format("Could not parse parameter: '{0}' with value: '{1}'. " + + "Received: '{2}', expected: '{3}'.", + name, value, result.GetType(), valueType)); + } + } + + private static TValue DynamicValueOf(dynamic parameters, string name) + { + string value = parameters[name]; + try + { + TValue result = parameters[name]; + return result; + } + catch (InvalidCastException) + { + throw new InvalidOperationException(Strings.Format("Parameter: '{0}' value: '{1}' could not be parsed. " + + "Expected type: '{2}' is not supported", + name, value, typeof(TValue))); + } + catch (Exception e) + { + throw new InvalidOperationException(string.Format("Could not get '{0}' value of '{1}' type dynamicly", + name, typeof(TValue)), e); + } + } + + private static IDictionary> CreateParsers() + { + var parsers = ImmutableDictionary.CreateBuilder>(); + parsers.Put(typeof(string), value => value); + parsers.Put(typeof(bool), SafeParse(bool.Parse)); + parsers.Put(typeof(bool?), SafeParse(bool.Parse)); + parsers.Put(typeof(byte), SafeParse(byte.Parse)); + parsers.Put(typeof(sbyte?), SafeParse(sbyte.Parse)); + parsers.Put(typeof(short), SafeParse(short.Parse)); + parsers.Put(typeof(short?), SafeParse(short.Parse)); + parsers.Put(typeof(ushort), SafeParse(ushort.Parse)); + parsers.Put(typeof(ushort?), SafeParse(ushort.Parse)); + parsers.Put(typeof(int), SafeParse(int.Parse)); + parsers.Put(typeof(int?), SafeParse(int.Parse)); + parsers.Put(typeof(uint), SafeParse(uint.Parse)); + parsers.Put(typeof(uint?), SafeParse(uint.Parse)); + parsers.Put(typeof(long), SafeParse(long.Parse)); + parsers.Put(typeof(long?), SafeParse(long.Parse)); + parsers.Put(typeof(ulong), SafeParse(ulong.Parse)); + parsers.Put(typeof(ulong?), SafeParse(ulong.Parse)); + parsers.Put(typeof(float), SafeParse(float.Parse)); + parsers.Put(typeof(float?), SafeParse(float.Parse)); + parsers.Put(typeof(double), SafeParse(double.Parse)); + parsers.Put(typeof(double?), SafeParse(double.Parse)); + parsers.Put(typeof(decimal), SafeParse(decimal.Parse)); + parsers.Put(typeof(decimal?), SafeParse(decimal.Parse)); + parsers.Put(typeof(DateTime), SafeParse(DateTime.Parse)); + parsers.Put(typeof(DateTime?), SafeParse(DateTime.Parse)); + parsers.Put(typeof(TimeSpan), SafeParse(TimeSpan.Parse)); + parsers.Put(typeof(TimeSpan?), SafeParse(TimeSpan.Parse)); + parsers.Put(typeof(ZonedDateTime), SafeParse(ParseZonedDateTime)); + parsers.Put(typeof(ZonedDateTime?), SafeParse(ParseZonedDateTime)); + parsers.Put(typeof(LocalTime), SafeParse(ParseLocalTime)); + parsers.Put(typeof(LocalTime?), SafeParse(ParseLocalTime)); + + parsers.Put(typeof(IEnumerable), value => value); + parsers.Put(typeof(ICollection), value => value); + parsers.Put(typeof(IList), value => value); + parsers.Put(typeof(List), value => value); + parsers.Put(typeof(ISet), value => value); + parsers.Put(typeof(HashSet), value => value); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(bool.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(bool.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(bool.Parse)); + parsers.Put(typeof(List), ListParse(bool.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(bool.Parse)); + parsers.Put(typeof(HashSet), SetParse(bool.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(byte.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(byte.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(byte.Parse)); + parsers.Put(typeof(List), ListParse(byte.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(byte.Parse)); + parsers.Put(typeof(HashSet), SetParse(byte.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(sbyte.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(sbyte.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(sbyte.Parse)); + parsers.Put(typeof(List), ListParse(sbyte.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(sbyte.Parse)); + parsers.Put(typeof(HashSet), SetParse(sbyte.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(short.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(short.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(short.Parse)); + parsers.Put(typeof(List), ListParse(short.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(short.Parse)); + parsers.Put(typeof(HashSet), SetParse(short.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(ushort.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(ushort.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(ushort.Parse)); + parsers.Put(typeof(List), ListParse(ushort.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(ushort.Parse)); + parsers.Put(typeof(HashSet), SetParse(ushort.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(int.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(int.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(int.Parse)); + parsers.Put(typeof(List), ListParse(int.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(int.Parse)); + parsers.Put(typeof(HashSet), SetParse(int.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(uint.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(uint.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(uint.Parse)); + parsers.Put(typeof(List), ListParse(uint.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(uint.Parse)); + parsers.Put(typeof(HashSet), SetParse(uint.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(long.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(long.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(long.Parse)); + parsers.Put(typeof(List), ListParse(long.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(long.Parse)); + parsers.Put(typeof(HashSet), SetParse(long.Parse)); + parsers.Put(typeof(IEnumerable), ImmutableListParse(ulong.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(ulong.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(ulong.Parse)); + parsers.Put(typeof(List), ListParse(ulong.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(ulong.Parse)); + parsers.Put(typeof(HashSet), SetParse(ulong.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(float.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(float.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(float.Parse)); + parsers.Put(typeof(List), ListParse(float.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(float.Parse)); + parsers.Put(typeof(HashSet), SetParse(float.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(double.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(double.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(double.Parse)); + parsers.Put(typeof(List), ListParse(double.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(double.Parse)); + parsers.Put(typeof(HashSet), SetParse(double.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(decimal.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(decimal.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(decimal.Parse)); + parsers.Put(typeof(List), ListParse(decimal.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(decimal.Parse)); + parsers.Put(typeof(HashSet), SetParse(decimal.Parse)); + + + parsers.Put(typeof(IEnumerable), ImmutableListParse(DateTime.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(DateTime.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(DateTime.Parse)); + parsers.Put(typeof(List), ListParse(DateTime.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(DateTime.Parse)); + parsers.Put(typeof(HashSet), SetParse(DateTime.Parse)); + + parsers.Put(typeof(IEnumerable), ImmutableListParse(TimeSpan.Parse)); + parsers.Put(typeof(ICollection), ImmutableListParse(TimeSpan.Parse)); + parsers.Put(typeof(IList), ImmutableListParse(TimeSpan.Parse)); + parsers.Put(typeof(List), ListParse(TimeSpan.Parse)); + parsers.Put(typeof(ISet), ImmutableSetParse(TimeSpan.Parse)); + parsers.Put(typeof(HashSet), SetParse(TimeSpan.Parse)); + + return parsers.ToImmutableDictionary(); + } + + private static Func SafeParse(Func parse) + { + return parameter => + { + try + { + return parse(parameter.Value); + } + catch (OverflowException) + { + throw ParameterOutOfRange(parameter, typeof(T)); + } + catch (FormatException) + { + throw InvalidParameterFormat(parameter, typeof(T)); + } + catch (Exception e) + { + throw new InvalidOperationException(Strings.Format("Unable to parse parameter: '{0}' with value: '{1}' to {2}", + parameter.Name, parameter.Value, typeof(T)), e); + } + }; + } + + private static Func ListParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return new List(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToList(); + return results; + }; + } + + private static Func ImmutableListParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return Lists.EmptyList(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToImmutableList(); + return results; + }; + } + + private static Func SetParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return new HashSet(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToSet(); + return results; + }; + } + + private static Func ImmutableSetParse(Func itemParser) + { + return parameter => + { + if (string.IsNullOrEmpty(parameter.Value)) + { + return Sets.EmptySet(); + } + var results = parameter.Value.Split(new[] { ',' }, StringSplitOptions.None) + .Where(it => it != null) + .Select(it => it.Trim()) + .Select(itemParser) + .ToImmutableHashSet(); + return results; + }; + } + + private static ZonedDateTime ParseZonedDateTime(string value) + { + var dateTime = DateTime.Parse(value); + return new ZonedDateTime(Instant.FromDateTimeUtc(dateTime.ToUniversalTime()), DateTimeZone.Utc); + } + + private static LocalTime ParseLocalTime(string value) + { + return LocalTimePattern.ExtendedIsoPattern.Parse(value).Value; + } + + private static ArgumentException ParameterOutOfRange(Parameter parameter, Type type) + { + return new ArgumentException(Strings.Format("Query: '{0}' value: '{1}' is out of range for: '{2}'", + parameter.Name, parameter.Value, type)); + } + + private static ArgumentException InvalidParameterFormat(Parameter parameter, Type type) + { + return new ArgumentException(Strings.Format("Query '{0}' value: '{1}' format is invalid for: '{2}'", + parameter.Name, parameter.Value, type)); + } + + private class Parameter + { + internal string Name { get; private set; } + internal string Value { get; private set; } + + private Parameter(string name, string value) + { + Name = name; + Value = value; + } + + internal static Parameter Of(string name, string value) + { + return new Parameter(name, value); + } + } + } + + internal enum ParameterType + { + Undefined, + Query, + Path, + Header + } +} \ No newline at end of file diff --git a/samples/server/petstore/nancyfx/src/IO.Swagger/packages.config b/samples/server/petstore/nancyfx/src/IO.Swagger/packages.config new file mode 100644 index 000000000000..6d8651cdcf40 --- /dev/null +++ b/samples/server/petstore/nancyfx/src/IO.Swagger/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file