diff --git a/bin/fsharp-functions-server-petstore.sh b/bin/fsharp-functions-server-petstore.sh new file mode 100644 index 000000000000..23cce9c0e71c --- /dev/null +++ b/bin/fsharp-functions-server-petstore.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=$(ls -ld "$SCRIPT") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=$(dirname "$SCRIPT")/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=$(dirname "$SCRIPT")/.. + APP_DIR=$(cd "${APP_DIR}"; pwd) +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g fsharp-functions -o samples/server/petstore/fsharp-functions" + +java ${JAVA_OPTS} -jar ${executable} ${ags} diff --git a/bin/windows/fsharp-functions-server-petstore.bat b/bin/windows/fsharp-functions-server-petstore.bat new file mode 100644 index 000000000000..560697ffe1bf --- /dev/null +++ b/bin/windows/fsharp-functions-server-petstore.bat @@ -0,0 +1,10 @@ +set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties +set ags=generate --artifact-id "fsharp-functions-petstore-server" -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g fsharp-functions -o samples\server\petstore\fsharp-functions + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/docs/generators.md b/docs/generators.md index 7cdf880edd72..1e53c61e0ff1 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -75,6 +75,7 @@ The following generators are available: * [cpp-restbed-server](generators/cpp-restbed-server) * [csharp-nancyfx](generators/csharp-nancyfx) * [erlang-server](generators/erlang-server) +* [fsharp-functions](generators/fsharp-functions) * [fsharp-giraffe-server](generators/fsharp-giraffe-server) * [go-gin-server](generators/go-gin-server) * [go-server](generators/go-server) diff --git a/docs/generators/fsharp-functions.md b/docs/generators/fsharp-functions.md new file mode 100644 index 000000000000..b7a8ee78257b --- /dev/null +++ b/docs/generators/fsharp-functions.md @@ -0,0 +1,22 @@ + +--- +id: generator-opts-server-fsharp-functions +title: Config Options for fsharp-functions +sidebar_label: fsharp-functions +--- + +| Option | Description | Values | Default | +| ------ | ----------- | ------ | ------- | +|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| +|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true| +|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false| +|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false| +|licenseUrl|The URL of the license| |http://localhost| +|licenseName|The name of the license| |NoLicense| +|packageCopyright|Specifies an AssemblyCopyright for the .NET Framework global assembly attributes stored in the AssemblyInfo file.| |No Copyright| +|packageAuthors|Specifies Authors property in the .NET Core project file.| |OpenAPI| +|packageTitle|Specifies an AssemblyTitle for the .NET Framework global assembly attributes stored in the AssemblyInfo file.| |OpenAPI Library| +|packageName|F# module name (convention: Title.Case).| |OpenAPI| +|packageVersion|F# package version.| |1.0.0| +|packageGuid|The GUID that will be associated with the C# project| |null| +|sourceFolder|source folder for generated code| |OpenAPI/src| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java index 04a626eac774..5f79b777370f 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java @@ -29,11 +29,13 @@ import org.openapitools.codegen.utils.ModelUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.Exception; import java.io.File; import java.util.*; import static org.openapitools.codegen.utils.StringUtils.camelize; +import static org.openapitools.codegen.utils.StringUtils.underscore; public abstract class AbstractFSharpCodegen extends DefaultCodegen implements CodegenConfig { @@ -246,11 +248,6 @@ public void processOpts() { additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName); } - if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { - LOGGER.warn(String.format(Locale.ROOT, "%s is not used by F# generators. Please use %s", - CodegenConstants.INVOKER_PACKAGE, CodegenConstants.PACKAGE_NAME)); - } - // {{packageTitle}} if (additionalProperties.containsKey(CodegenConstants.PACKAGE_TITLE)) { setPackageTitle((String) additionalProperties.get(CodegenConstants.PACKAGE_TITLE)); @@ -300,32 +297,8 @@ public void processOpts() { additionalProperties.put(CodegenConstants.USE_DATETIME_OFFSET, useDateTimeOffsetFlag); } - if (additionalProperties.containsKey(CodegenConstants.USE_COLLECTION)) { - setUseCollection(convertPropertyToBooleanAndWriteBack(CodegenConstants.USE_COLLECTION)); - } else { - additionalProperties.put(CodegenConstants.USE_COLLECTION, useCollection); - } - - if (additionalProperties.containsKey(CodegenConstants.RETURN_ICOLLECTION)) { - setReturnICollection(convertPropertyToBooleanAndWriteBack(CodegenConstants.RETURN_ICOLLECTION)); - } else { - additionalProperties.put(CodegenConstants.RETURN_ICOLLECTION, returnICollection); - } - - if (additionalProperties.containsKey(CodegenConstants.NETCORE_PROJECT_FILE)) { - setNetCoreProjectFileFlag(convertPropertyToBooleanAndWriteBack(CodegenConstants.NETCORE_PROJECT_FILE)); - } else { - additionalProperties.put(CodegenConstants.NETCORE_PROJECT_FILE, netCoreProjectFileFlag); - } - - if (additionalProperties.containsKey(CodegenConstants.INTERFACE_PREFIX)) { - String useInterfacePrefix = additionalProperties.get(CodegenConstants.INTERFACE_PREFIX).toString(); - if ("false".equals(useInterfacePrefix.toLowerCase(Locale.ROOT))) { - setInterfacePrefix(""); - } else if (!"true".equals(useInterfacePrefix.toLowerCase(Locale.ROOT))) { - // NOTE: if user passes "true" explicitly, we use the default I- prefix. The other supported case here is a custom prefix. - setInterfacePrefix(sanitizeName(useInterfacePrefix)); - } + if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) { + setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING)); } // This either updates additionalProperties with the above fixes, or sets the default if the option was not specified. @@ -372,65 +345,49 @@ public Map postProcessAllModels(Map objs) { } /* - * F# does not allow forward declarations, so files must be imported in the correct order. - * Output of CodeGen models must therefore bein dependency order (rather than alphabetical order, which seems to be the default). - * We achieve this by creating a comparator to check whether the first model contains any properties of the comparison model's type - * This could probably be made more efficient if absolutely needed. - */ + * F# does not allow forward declarations, so files must be imported in the correct order. + * Output of CodeGen models must therefore bein dependency order (rather than alphabetical order, which seems to be the default). + * This could probably be made more efficient if absolutely needed. + */ @SuppressWarnings({"unchecked"}) - public Map postProcessDependencyOrders(final Map objs) { - Comparator comparator = new Comparator() { - @Override - public int compare(String key1, String key2) { - // Get the corresponding models - CodegenModel model1 = ModelUtils.getModelByName(key1, objs); - CodegenModel model2 = ModelUtils.getModelByName(key2, objs); - - List complexVars1 = new ArrayList(); - List complexVars2 = new ArrayList(); - - for (CodegenProperty prop : model1.vars) { - if (prop.complexType != null) - complexVars1.add(prop.complexType); - } - for (CodegenProperty prop : model2.vars) { - if (prop.complexType != null) - complexVars2.add(prop.complexType); - } - - // if first has complex vars and second has none, first is greater - if (complexVars1.size() > 0 && complexVars2.size() == 0) - return 1; - - // if second has complex vars and first has none, first is lesser - if (complexVars1.size() == 0 && complexVars2.size() > 0) - return -1; - - // if first has complex var that matches the second's key, first is greater - if (complexVars1.contains(key2)) - return 1; - - // if second has complex var that matches the first's key, first is lesser - if (complexVars2.contains(key1)) - return -1; - - // if none of the above, don't care - return 0; - - } - }; - PriorityQueue queue = new PriorityQueue(objs.size(), comparator); - for (Object k : objs.keySet()) { - queue.add(k.toString()); + public Map postProcessDependencyOrders(final Map objs) { + + Map> dependencies = new HashMap>(); + + List classNames = new ArrayList(); + + for(String k : objs.keySet()) { + CodegenModel model = ModelUtils.getModelByName(k, objs); + if(model == null || model.classname == null) { + throw new RuntimeException("Null model encountered"); } - - Map sorted = new LinkedHashMap(); - - while (queue.size() > 0) { - String key = queue.poll(); - sorted.put(key, objs.get(key)); + dependencies.put(model.classname, model.imports); + + classNames.add(model.classname); + } + + Object[] sortedKeys = classNames.toArray(); + + for(int i1 = 0 ; i1 < sortedKeys.length; i1++) { + String k1 = sortedKeys[i1].toString(); + for(int i2 = i1 + 1; i2 < sortedKeys.length; i2++) { + String k2 = sortedKeys[i2].toString(); + if(dependencies.get(k2).contains(k1)) { + sortedKeys[i2] = k1; + sortedKeys[i1] = k2; + i1 = -1; + break; + } } - return sorted; + } + + Map sorted = new LinkedHashMap(); + for(int i = sortedKeys.length - 1; i >= 0; i--) { + Object k = sortedKeys[i]; + sorted.put(k.toString(), objs.get(k)); + } + + return sorted; } /** @@ -684,6 +641,39 @@ public String toOperationId(String operationId) { return camelize(sanitizeName(operationId)); } + public String getModelPropertyNaming() { + return this.modelPropertyNaming; + } + + public void setModelPropertyNaming(String naming) { + if ("original".equals(naming) || "camelCase".equals(naming) || + "PascalCase".equals(naming) || "snake_case".equals(naming)) { + this.modelPropertyNaming = naming; + } else { + throw new IllegalArgumentException("Invalid model property naming '" + + naming + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + } + + + public String getNameUsingModelPropertyNaming(String name) { + switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) { + case original: + return name; + case camelCase: + return camelize(name, true); + case PascalCase: + return camelize(name); + case snake_case: + return underscore(name); + default: + throw new IllegalArgumentException("Invalid model property naming '" + + name + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + } + @Override public String toVarName(String name) { // sanitize name @@ -694,9 +684,8 @@ public String toVarName(String name) { return name; } - // camelize the variable name - // pet_id => PetId - name = camelize(name); + name = getNameUsingModelPropertyNaming(name); + // for reserved word or word starting with number, append _ if (isReservedWord(name) || name.matches("^\\d.*")) { name = escapeReservedWord(name); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpFunctionsServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpFunctionsServerCodegen.java new file mode 100644 index 000000000000..442cbc3601bb --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpFunctionsServerCodegen.java @@ -0,0 +1,129 @@ +package org.openapitools.codegen.languages; + +import org.openapitools.codegen.*; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.parameters.Parameter; + +import java.io.File; +import java.util.*; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FsharpFunctionsServerCodegen extends AbstractFSharpCodegen { + public static final String PROJECT_NAME = "projectName"; + + static Logger LOGGER = LoggerFactory.getLogger(FsharpFunctionsServerCodegen.class); + + public CodegenType getTag() { + return CodegenType.SERVER; + } + + public String getName() { + return "fsharp-functions"; + } + + public String getHelp() { + return "Generates a fsharp-functions server."; + } + + public FsharpFunctionsServerCodegen() { + super(); + + // CLI options + addOption(CodegenConstants.LICENSE_URL, + CodegenConstants.LICENSE_URL_DESC, + licenseUrl); + + addOption(CodegenConstants.LICENSE_NAME, + CodegenConstants.LICENSE_NAME_DESC, + licenseName); + + addOption(CodegenConstants.PACKAGE_COPYRIGHT, + CodegenConstants.PACKAGE_COPYRIGHT_DESC, + packageCopyright); + + addOption(CodegenConstants.PACKAGE_AUTHORS, + CodegenConstants.PACKAGE_AUTHORS_DESC, + packageAuthors); + + addOption(CodegenConstants.PACKAGE_TITLE, + CodegenConstants.PACKAGE_TITLE_DESC, + packageTitle); + + addOption(CodegenConstants.PACKAGE_NAME, + "F# module name (convention: Title.Case).", + packageName); + + addOption(CodegenConstants.PACKAGE_VERSION, + "F# package version.", + packageVersion); + + addOption(CodegenConstants.OPTIONAL_PROJECT_GUID, + CodegenConstants.OPTIONAL_PROJECT_GUID_DESC, + null); + + addOption(CodegenConstants.SOURCE_FOLDER, + CodegenConstants.SOURCE_FOLDER_DESC, + sourceFolder); + } + + @Override + public void processOpts() { + super.processOpts(); + + modelPackage = "Model"; + embeddedTemplateDir = templateDir = "fsharp-functions-server"; + + apiTemplateFiles.put("Handler.mustache", "Handler.fs"); + apiTemplateFiles.put("HandlerParams.mustache", "HandlerParams.fs"); + apiTemplateFiles.put("ServiceInterface.mustache", "ServiceInterface.fs"); + apiTemplateFiles.put("ServiceImpl.mustache", "Service.fs"); + modelTemplateFiles.put("Model.mustache", ".fs"); + + String implFolder = sourceFolder + File.separator + "impl"; + + supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); + supportingFiles.add(new SupportingFile("build.sh.mustache", projectFolder, "build.sh")); + supportingFiles.add(new SupportingFile("build.bat.mustache", projectFolder, "build.bat")); + supportingFiles.add(new SupportingFile("host.json", "", "host.json")); + supportingFiles.add(new SupportingFile("local.settings.json", "", "local.settings.json")); + supportingFiles.add(new SupportingFile("Project.fsproj.mustache", projectFolder, packageName + ".fsproj")); + + + } + + @Override + public String modelFileFolder() { + return super.modelFileFolder().replace("Model","model"); + } + + @Override + public String apiFileFolder() { + return super.apiFileFolder() + File.separator + "api"; + } + + private String implFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator + "impl"; + } + + @Override() + public String toModelImport(String name) { + return packageName + "." + modelPackage() + "." + name; + } + + @Override + public String apiFilename(String templateName, String tag) { + String result = super.apiFilename(templateName, tag); + if (templateName.endsWith("Impl.mustache")) { + int ix = result.lastIndexOf(File.separatorChar); + result = result.substring(0, ix) + result.substring(ix, result.length() - 2) + "fs"; + result = result.replace(apiFileFolder(), implFileFolder()); + } + return result; + } +} diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java index 8bbb27912a41..4cd842eed700 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java @@ -187,7 +187,6 @@ public void processOpts() { LOGGER.warn("Library flag not currently supported."); String authFolder = sourceFolder + File.separator + "auth"; - String serviceFolder = sourceFolder + File.separator + "services"; String implFolder = sourceFolder + File.separator + "impl"; String helperFolder = sourceFolder + File.separator + "helpers"; diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 5a6cb16c1ac2..67c0f473b506 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -117,3 +117,4 @@ org.openapitools.codegen.languages.TypeScriptNodeClientCodegen org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen org.openapitools.codegen.languages.FsharpGiraffeServerCodegen org.openapitools.codegen.languages.AsciidocDocumentationCodegen +org.openapitools.codegen.languages.FsharpFunctionsServerCodegen diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/Handler.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/Handler.mustache new file mode 100644 index 000000000000..8c8aebc852a5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/Handler.mustache @@ -0,0 +1,65 @@ +namespace {{packageName}} + +open {{classname}}HandlerParams +open {{classname}}ServiceImplementation +open Microsoft.AspNetCore.Mvc +open Microsoft.AspNetCore.Http +open Newtonsoft.Json +open Microsoft.Azure.WebJobs +open System.IO + +module {{classname}}Handlers = + + {{#operations}} + /// + /// {{description}} + /// + + {{#operation}} + //#region {{operationId}} + /// + /// {{#summary}}{{summary}}{{/summary}} + /// + [] + let {{operationId}} + ([] + req:HttpRequest ) = + + {{#hasBodyParam}} + use reader = StreamReader(req.Body) + + let mediaTypes = [{{#consumes}}"{{mediaType}}";{{/consumes}}] // currently unused + + {{#bodyParam}} + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject<{{operationId}}BodyParams> + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + {{/bodyParam}} + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = {{classname}}Service.{{operationId}} bodyParams + {{/hasBodyParam}} + {{^hasBodyParam}} + let result = {{classname}}Service.{{operationId}} () + {{/hasBodyParam}} + match result with + {{#responses}} + | {{operationId}}{{#isDefault}}Default{{/isDefault}}StatusCode{{^isDefault}}{{code}}{{/isDefault}} resolved -> + {{^primitiveType}} + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + {{/primitiveType}} + {{#primitiveType}} + let content = resolved.content + let responseContentType = "text/plain" + {{/primitiveType}} + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable({{code}})) + {{/responses}} + + {{/operation}} + {{/operations}} + + + diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/HandlerParams.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/HandlerParams.mustache new file mode 100644 index 000000000000..336ef2d55cf3 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/HandlerParams.mustache @@ -0,0 +1,147 @@ +namespace {{packageName}} + +{{#imports}} +{{#import}} +open {{import}} +{{/import}} +{{/imports}} +open System.Collections.Generic +open System + +module {{classname}}HandlerParams = + + {{#operations}} + {{#operation}} + {{#pathParams}} + {{#-first}} + //#region Path parameters + [] + type {{operationId}}PathParams = { + {{/-first}} + {{paramName}} : {{dataType}} {{^required}}option{{/required}}; + {{#-last}} + } + {{/-last}} + //#endregion + {{/pathParams}} + {{#queryParams}} + + {{#-first}} + //#region Query parameters + [] + type {{operationId}}QueryParams = { + {{/-first}} + {{paramName}} : {{dataType}} {{^required}}option{{/required}}; + + {{#-last}} + } + //#endregion + {{/-last}} + {{/queryParams}} + {{#bodyParams}} + + {{#-first}} + //#region Body parameters + [] + {{^hasMore}} + type {{operationId}}BodyParams = {{dataType}} + {{/hasMore}} + {{#hasMore}} + type {{operationId}}BodyParams = { + {{paramName}} : {{dataType}}; + {{/hasMore}} + {{/-first}} + {{^-first}} + {{paramName}} : {{dataType}}; + {{/-first}} + {{#-last}} + {{^-first}} + } + {{/-first}} + //#endregion + {{/-last}} + {{/bodyParams}} + {{#formParams}} + + //#region Form parameters + {{#-first}} + [] + type {{operationId}}FormParams = { + {{/-first}} + {{paramName}} : {{dataType}} {{^required}}option{{/required}}; + {{#-last}} + } + {{/-last}} + //#endregion + {{/formParams}} + {{#headerParams}} + + //#region Header parameters + {{#-first}} + [] + type {{operationId}}HeaderParams = { + {{/-first}} + {{paramName}} : {{dataType}} {{^required}}option{{/required}}; + {{#-last}} + } + {{/-last}} + //#endregion + {{/headerParams}} + {{#cookieParams}} + + //#region Cookie parameters + {{#-first}} + type {{operationId}}CookieParams = { + {{/-first}} + {{paramName}} : {{dataType}} {{^required}}option{{/required}}; + {{#-last}} + } + {{/-last}} + //#endregion + {{/cookieParams}} + + {{#responses}} + + type {{operationId}}{{#isDefault}}Default{{/isDefault}}StatusCode{{^isDefault}}{{code}}{{/isDefault}}Response = { + content:{{#dataType}}{{{.}}}{{/dataType}}{{^dataType}}string{{/dataType}}; + {{^code}}code:int{{/code}} + } + {{/responses}} + type {{operationId}}Result = {{#responses}}{{operationId}}{{#isDefault}}Default{{/isDefault}}StatusCode{{^isDefault}}{{code}}{{/isDefault}} of {{operationId}}{{#isDefault}}Default{{/isDefault}}StatusCode{{^isDefault}}{{code}}{{/isDefault}}Response{{#hasMore}}|{{/hasMore}}{{/responses}} + + {{#allParams}} + {{#-first}} + type {{operationId}}Args = { + {{/-first}} + {{/allParams}} + {{#hasHeaderParams}} + headerParams:{{operationId}}HeaderParams; + {{/hasHeaderParams}} + {{#pathParams}} + {{#-first}} + pathParams:{{operationId}}PathParams; + {{/-first}} + {{/pathParams}} + {{#queryParams}} + {{#-first}} + queryParams:Result<{{operationId}}QueryParams,string>; + {{/-first}} + {{/queryParams}} + {{#bodyParams}} + {{#-first}} + bodyParams:{{operationId}}BodyParams + {{/-first}} + {{/bodyParams}} + {{#formParams}} + {{#-first}} + formParams:Result<{{operationId}}FormParams,string> + {{/-first}} + {{/formParams}} + {{#allParams}} + {{#-first}} + } + {{/-first}} + {{/allParams}} + {{/operation}} + {{/operations}} + \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/Model.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/Model.mustache new file mode 100644 index 000000000000..8084cc0cf8f8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/Model.mustache @@ -0,0 +1,35 @@ +namespace {{packageName}}.{{modelPackage}} + +open System +open System.Collections.Generic +open Newtonsoft.Json +{{#imports}} +open {{import}} +{{/imports}} + +module {{classname}} = + + {{#models}} + {{#model}} + //#region {{classname}} + + {{^allowableValues}} + [] + type {{classname}} = { + {{#vars}} + [] + {{name}} : {{#isDateTime}}{{^required}}Nullable<{{/required}}{{/isDateTime}}{{{dataType}}}{{#isDateTime}}{{^required}}>{{/required}}{{/isDateTime}}; + {{/vars}} + } + {{/allowableValues}} + {{#allowableValues}} + {{#enumVars}} + let {{name}} = {{#isString}}"{{value}}"{{/isString}}{{#isInteger}}"{{value}}"{{/isInteger}} + {{/enumVars}} + type {{classname}} = {{#isString}}string{{/isString}}{{#isInteger}}int{{/isInteger}} + {{/allowableValues}} + + //#endregion + {{/model}} + {{/models}} + \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/Project.fsproj.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/Project.fsproj.mustache new file mode 100644 index 000000000000..c0b479a470f2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/Project.fsproj.mustache @@ -0,0 +1,41 @@ + + + {{packageName}} + {{packageName}} + netcoreapp2.1 + v2 + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + {{#models}} + {{#model}} + + {{/model}} + {{/models}} + {{#apiInfo}} + {{#apis}} + {{#operations}} + + + + + {{/operations}} + {{/apis}} + {{/apiInfo}} + + + \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/README.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/README.mustache new file mode 100644 index 000000000000..9441f3981f6f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/README.mustache @@ -0,0 +1,143 @@ +# {{packageName}} + +An [F# Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-fsharp) server stub for the {{packageName}} package, created via the [OpenAPI generator](https://github.com/OpenAPITools/openapi-generator/). + +## Models + +The following models have been auto-generated from the provided OpenAPI schema: + +{{#apiInfo}} +{{#models}} +{{#model}} +- model/{{classname}}Model.fs +{{/model}} +{{/models}} +{{/apiInfo}} + +## Operations + +Handlers have been auto-generated from the operations specified in the OpenAPI schema as follows: + +{{#apiInfo}} +{{#operations}} +{{#operation}} +- api/{{classname}}Handler.fs +{{/operation}} +{{/operations}} +{{/apiInfo}} + +## Operation Parameters + +Types have been generated for the URL, query, form, header and cookie parameters passed to each handler in the following files: + +{{#apiInfo}} +{{#apis}} +- api/{{classname}}HandlerParams.fs +{{/apis}} +{{/apiInfo}} + +## Service Interfaces + +Handlers will attempt to bind parameters to the applicable type and pass to a Service specific to that Handler. Service interfaces have been generated as follows: + +{{#apiInfo}} +{{#apis}} +- api/{{classname}}ServiceInterface.fs +{{/apis}} +{{/apiInfo}} + +Each Service contains functions for each [OperationId], each accepting a [OperationId]Params object that wraps the operation's parameters. + +If a requestBody is a ref type (i.e. a Model) or a single simple type, the operation parameter will be typed as the expected Model: + +`type AddPetBodyParams = Pet` + +If a requestBody is a simple type with named properties, the operation parameters will be typed to reflect those properties: + +`type AddFooBodyParams = { + Name:string; + Age:int +} + +Each Service/operation function must accept the [OperationId]Params object and return a [OperationId]Result type. For example: + +`type AddPetArgs = { bodyParams:AddPetBodyParams } +type IPetApiService = abstract member AddPet:HttpContext -> AddPetArgs->AddPetResult` + +[OperationId]Result is a discriminated union of all possible OpenAPI response types for that operation. + +This means that service implementations can only return status codes that have been declared in the OpenAPI specification. +However, if the OpenAPI spec declares a default Response for an operation, the service can manually set the status code. + +For example: + +`type FindPetsByStatusDefaultStatusCodeResponse = { content:Pet[];} +type FindPetsByStatusStatusCode400Response = { content:string; } +type FindPetsByStatusResult = FindPetsByStatusDefaultStatusCode of FindPetsByStatusDefaultStatusCodeResponse | FindPetsByStatusStatusCode400 of FindPetsByStatusStatusCode400Response` + +## Service Implementations + +Stubbed service implementations of those interfaces have been generated as follows: + +{{#apiInfo}} +{{#apis}} +- impl/{{classname}}Service.fs +{{/apis}} +{{/apiInfo}} + +You should manually edit these files to implement your business logic. + +## Additional Handlers + +Additional handlers can be configured in the Customization.fs + +`let handlers : HttpHandler list = [ + // insert your handlers here + GET >=> + choose [ + route "/login" >=> redirectToLogin + route "/logout" >=> logout + ] + ]` + +## TODO/currently unsupported + +- form request bodies (URL-encoded or multipart) +- limit handler access to specified oAuth scheme when multiple oAuth schemes defined +- XML content/response types +- http authentication +- testing header params + +## .openapi-generator-ignore + +It is recommended to add src/impl/** and the project's .fsproj file to the .openapi-generator-ignore file. + +This will allow you to regenerate model, operation and parameter files without overriding your implementations of business logic, authentication, data layers, and so on. + +## Build and test the application + +### Windows + +Run the `build.bat` script in order to restore, build and test (if you've selected to include tests) the application: + +``` +> ./build.bat +``` + +### Linux/macOS + +Run the `build.sh` script in order to restore, build and test (if you've selected to include tests) the application: + +``` +$ ./build.sh +``` + +## Run the application + +After a successful build you can start the web application by executing the following command in your terminal: + +``` +dotnet run --project src/{{packageName} +``` + +After the application has started visit [http://localhost:5000](http://localhost:5000) in your preferred browser. \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/ServiceImpl.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/ServiceImpl.mustache new file mode 100644 index 000000000000..18050015f8ce --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/ServiceImpl.mustache @@ -0,0 +1,43 @@ +namespace {{packageName}} +{{#imports}} +{{#import}} +open {{import}} +{{/import}} +{{/imports}} +open {{classname}}HandlerParams +open {{classname}}ServiceInterface +open System.Collections.Generic +open System + +module {{classname}}ServiceImplementation = + + //#region Service implementation + type {{classname}}ServiceImpl() = + interface I{{classname}}Service with + + {{#operations}} + {{#operation}} + member this.{{operationId}} {{^hasBodyParam}}(){{/hasBodyParam}}{{#hasBodyParam}}(parameters:{{operationId}}BodyParams){{/hasBodyParam}} = + {{#responses}} + {{#-first}} + {{#hasMore}} + if true then + {{/hasMore}} + {{/-first}} + {{^-first}} + {{#hasMore}} + else if true then + {{/hasMore}} + {{^hasMore}} + else + {{/hasMore}} + {{/-first}} + let content = "{{message}}" {{#dataType}}:> obj :?> {{{.}}} // this cast is obviously wrong, and is only intended to allow generated project to compile {{/dataType}} + {{operationId}}{{#isDefault}}Default{{/isDefault}}StatusCode{{^isDefault}}{{code}}{{/isDefault}} { content = content } + {{/responses}} + + {{/operation}} + {{/operations}} + //#endregion + + let {{classname}}Service = {{classname}}ServiceImpl() :> I{{classname}}Service \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/ServiceInterface.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/ServiceInterface.mustache new file mode 100644 index 000000000000..c57b01778fd9 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/ServiceInterface.mustache @@ -0,0 +1,16 @@ +namespace {{packageName}} +open {{classname}}HandlerParams +open System +open Microsoft.AspNetCore.Http + + +module {{classname}}ServiceInterface = + + //#region Service interface + type I{{classname}}Service = + {{#operations}} + {{#operation}} + abstract member {{operationId}} : {{^hasBodyParam}}unit{{/hasBodyParam}}{{#hasBodyParam}}{{operationId}}BodyParams{{/hasBodyParam}} -> {{operationId}}Result + {{/operation}} + {{/operations}} + //#endregion \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/build.bat.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/build.bat.mustache new file mode 100644 index 000000000000..9e7afd0a272f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/build.bat.mustache @@ -0,0 +1,3 @@ +dotnet restore {{packageName}}.fsproj +dotnet build {{packageName}}.fsproj + diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/build.sh.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/build.sh.mustache new file mode 100644 index 000000000000..ab63b07a1420 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/build.sh.mustache @@ -0,0 +1,4 @@ +#!/bin/sh +dotnet restore {{packageName}}.fsproj +dotnet build {{packageName}}.fsproj + diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/gitignore.mustache b/modules/openapi-generator/src/main/resources/fsharp-functions-server/gitignore.mustache new file mode 100644 index 000000000000..ab071890fc85 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/gitignore.mustache @@ -0,0 +1,265 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +**/packages/** +# except build/, which is used as an MSBuild target. +#!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +mercury_server/.paket/paket.exe +mercury_server/paket-files/ + +# FAKE - F# Make +mercury_server/.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/host.json b/modules/openapi-generator/src/main/resources/fsharp-functions-server/host.json new file mode 100644 index 000000000000..ccd1678a5e12 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/host.json @@ -0,0 +1,8 @@ +{ + "version": "2.0", + "extensions":{ + "http": { + "routePrefix": "" + } + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/fsharp-functions-server/local.settings.json b/modules/openapi-generator/src/main/resources/fsharp-functions-server/local.settings.json new file mode 100644 index 000000000000..3cdc862b5226 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/fsharp-functions-server/local.settings.json @@ -0,0 +1,7 @@ +{ + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "", + "FUNCTIONS_WORKER_RUNTIME": "dotnet" + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/fsharp/FSharpServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/fsharp/FSharpServerCodegenTest.java index 491b4123044f..12281dc29f5d 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/fsharp/FSharpServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/fsharp/FSharpServerCodegenTest.java @@ -23,7 +23,10 @@ import org.testng.annotations.Test; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Arrays; +import java.lang.Exception; @SuppressWarnings("static-method") public class FSharpServerCodegenTest { @@ -32,37 +35,43 @@ public class FSharpServerCodegenTest { public void testModelsAreSortedAccordingToDependencyOrder() throws Exception { final AbstractFSharpCodegen codegen = new P_AbstractFSharpCodegen(); - // parent - final CodegenModel parent = new CodegenModel(); - CodegenProperty childProp = new CodegenProperty(); - childProp.complexType = "child"; - childProp.name = "child"; - parent.setVars(Collections.singletonList(childProp)); + final CodegenModel wheel = new CodegenModel(); + wheel.setImports(new HashSet(Arrays.asList())); + wheel.setClassname("wheel"); - final CodegenModel child = new CodegenModel(); - CodegenProperty carProp = new CodegenProperty(); - carProp.complexType = "car"; - carProp.name = "car"; - child.setVars(Collections.singletonList(carProp)); + final CodegenModel bike = new CodegenModel(); + bike.setImports(new HashSet(Arrays.asList("wheel"))); + bike.setClassname("bike"); + + final CodegenModel parent = new CodegenModel(); + parent.setImports(new HashSet(Arrays.asList("bike", "car"))); + parent.setClassname("parent"); - // child final CodegenModel car = new CodegenModel(); - CodegenProperty modelProp = new CodegenProperty(); - modelProp.name = "model"; - car.setVars(Collections.singletonList(modelProp)); + car.setImports(new HashSet(Arrays.asList("wheel"))); + car.setClassname("car"); + + final CodegenModel child = new CodegenModel(); + child.setImports(new HashSet(Arrays.asList("car", "bike", "parent"))); + child.setClassname("child"); Map models = new HashMap(); models.put("parent", Collections.singletonMap("models", Collections.singletonList(Collections.singletonMap("model", parent)))); models.put("child", Collections.singletonMap("models", Collections.singletonList(Collections.singletonMap("model", child)))); models.put("car", Collections.singletonMap("models", Collections.singletonList(Collections.singletonMap("model", car)))); + models.put("bike", Collections.singletonMap("models", Collections.singletonList(Collections.singletonMap("model", bike)))); + models.put("wheel", Collections.singletonMap("models", Collections.singletonList(Collections.singletonMap("model", wheel)))); Map sorted = codegen.postProcessDependencyOrders(models); Object[] keys = sorted.keySet().toArray(); - - Assert.assertEquals(keys[0], "car"); - Assert.assertEquals(keys[1], "child"); - Assert.assertEquals(keys[2], "parent"); + + Assert.assertTrue(keys[0] == "wheel"); + Assert.assertTrue(keys[1] == "bike" || keys[1] == "car"); + Assert.assertTrue(keys[2] == "bike" || keys[2] == "car"); + Assert.assertEquals(keys[3], "parent"); + Assert.assertEquals(keys[4], "child"); + } @Test(description = "modify model imports to explicit set namespace and package name") diff --git a/samples/server/petstore/fsharp-functions/.gitignore b/samples/server/petstore/fsharp-functions/.gitignore new file mode 100644 index 000000000000..ab071890fc85 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/.gitignore @@ -0,0 +1,265 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +**/packages/** +# except build/, which is used as an MSBuild target. +#!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +mercury_server/.paket/paket.exe +mercury_server/paket-files/ + +# FAKE - F# Make +mercury_server/.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/.openapi-generator-ignore b/samples/server/petstore/fsharp-functions/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/fsharp-functions/.openapi-generator/VERSION b/samples/server/petstore/fsharp-functions/.openapi-generator/VERSION new file mode 100644 index 000000000000..0e97bd19efbf --- /dev/null +++ b/samples/server/petstore/fsharp-functions/.openapi-generator/VERSION @@ -0,0 +1 @@ +4.1.3-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/OpenAPI.fsproj b/samples/server/petstore/fsharp-functions/OpenAPI/OpenAPI.fsproj new file mode 100644 index 000000000000..e26976729b75 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/OpenAPI.fsproj @@ -0,0 +1,44 @@ + + + OpenAPI + OpenAPI + netcoreapp2.1 + v2 + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/build.bat b/samples/server/petstore/fsharp-functions/OpenAPI/build.bat new file mode 100644 index 000000000000..607db898bff9 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/build.bat @@ -0,0 +1,3 @@ +dotnet restore OpenAPI.fsproj +dotnet build OpenAPI.fsproj + diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/build.sh b/samples/server/petstore/fsharp-functions/OpenAPI/build.sh new file mode 100644 index 000000000000..9356b9ac120b --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/build.sh @@ -0,0 +1,4 @@ +#!/bin/sh +dotnet restore OpenAPI.fsproj +dotnet build OpenAPI.fsproj + diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiHandler.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiHandler.fs new file mode 100644 index 000000000000..53025caf26ed --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiHandler.fs @@ -0,0 +1,193 @@ +namespace OpenAPI + +open PetApiHandlerParams +open PetApiServiceImplementation +open Microsoft.AspNetCore.Mvc +open Microsoft.AspNetCore.Http +open Newtonsoft.Json +open Microsoft.Azure.WebJobs +open System.IO + +module PetApiHandlers = + + /// + /// + /// + + //#region AddPet + /// + /// Add a new pet to the store + /// + [] + let AddPet + ([] + req:HttpRequest ) = + + use reader = StreamReader(req.Body) + + let mediaTypes = ["application/json";"application/xml";] // currently unused + + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = PetApiService.AddPet bodyParams + match result with + | AddPetStatusCode405 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(405)) + + //#region DeletePet + /// + /// Deletes a pet + /// + [] + let DeletePet + ([] + req:HttpRequest ) = + + let result = PetApiService.DeletePet () + match result with + | DeletePetStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + + //#region FindPetsByStatus + /// + /// Finds Pets by status + /// + [] + let FindPetsByStatus + ([] + req:HttpRequest ) = + + let result = PetApiService.FindPetsByStatus () + match result with + | FindPetsByStatusDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + | FindPetsByStatusStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + + //#region FindPetsByTags + /// + /// Finds Pets by tags + /// + [] + let FindPetsByTags + ([] + req:HttpRequest ) = + + let result = PetApiService.FindPetsByTags () + match result with + | FindPetsByTagsDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + | FindPetsByTagsStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + + //#region GetPetById + /// + /// Find pet by ID + /// + [] + let GetPetById + ([] + req:HttpRequest ) = + + let result = PetApiService.GetPetById () + match result with + | GetPetByIdDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + | GetPetByIdStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + | GetPetByIdStatusCode404 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(404)) + + //#region UpdatePet + /// + /// Update an existing pet + /// + [] + let UpdatePet + ([] + req:HttpRequest ) = + + use reader = StreamReader(req.Body) + + let mediaTypes = ["application/json";"application/xml";] // currently unused + + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = PetApiService.UpdatePet bodyParams + match result with + | UpdatePetStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + | UpdatePetStatusCode404 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(404)) + | UpdatePetStatusCode405 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(405)) + + //#region UpdatePetWithForm + /// + /// Updates a pet in the store with form data + /// + [] + let UpdatePetWithForm + ([] + req:HttpRequest ) = + + let result = PetApiService.UpdatePetWithForm () + match result with + | UpdatePetWithFormStatusCode405 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(405)) + + //#region UploadFile + /// + /// uploads an image + /// + [] + let UploadFile + ([] + req:HttpRequest ) = + + let result = PetApiService.UploadFile () + match result with + | UploadFileDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + + + + diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiHandlerParams.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiHandlerParams.fs new file mode 100644 index 000000000000..f84ffb76b22c --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiHandlerParams.fs @@ -0,0 +1,210 @@ +namespace OpenAPI + +open OpenAPI.Model.ApiResponse +open OpenAPI.Model.Pet +open System.Collections.Generic +open System + +module PetApiHandlerParams = + + + //#region Body parameters + [] + type AddPetBodyParams = Pet + //#endregion + + + type AddPetStatusCode405Response = { + content:string; + + } + type AddPetResult = AddPetStatusCode405 of AddPetStatusCode405Response + + type AddPetArgs = { + bodyParams:AddPetBodyParams + } + //#region Path parameters + [] + type DeletePetPathParams = { + petId : int64 ; + } + //#endregion + + //#region Header parameters + [] + type DeletePetHeaderParams = { + apiKey : string option; + } + //#endregion + + + type DeletePetStatusCode400Response = { + content:string; + + } + type DeletePetResult = DeletePetStatusCode400 of DeletePetStatusCode400Response + + type DeletePetArgs = { + headerParams:DeletePetHeaderParams; + pathParams:DeletePetPathParams; + } + + //#region Query parameters + [] + type FindPetsByStatusQueryParams = { + status : string[] ; + + } + //#endregion + + + type FindPetsByStatusDefaultStatusCodeResponse = { + content:Pet[]; + + } + + type FindPetsByStatusStatusCode400Response = { + content:string; + + } + type FindPetsByStatusResult = FindPetsByStatusDefaultStatusCode of FindPetsByStatusDefaultStatusCodeResponse|FindPetsByStatusStatusCode400 of FindPetsByStatusStatusCode400Response + + type FindPetsByStatusArgs = { + queryParams:Result; + } + + //#region Query parameters + [] + type FindPetsByTagsQueryParams = { + tags : string[] ; + + } + //#endregion + + + type FindPetsByTagsDefaultStatusCodeResponse = { + content:Pet[]; + + } + + type FindPetsByTagsStatusCode400Response = { + content:string; + + } + type FindPetsByTagsResult = FindPetsByTagsDefaultStatusCode of FindPetsByTagsDefaultStatusCodeResponse|FindPetsByTagsStatusCode400 of FindPetsByTagsStatusCode400Response + + type FindPetsByTagsArgs = { + queryParams:Result; + } + //#region Path parameters + [] + type GetPetByIdPathParams = { + petId : int64 ; + } + //#endregion + + + type GetPetByIdDefaultStatusCodeResponse = { + content:Pet; + + } + + type GetPetByIdStatusCode400Response = { + content:string; + + } + + type GetPetByIdStatusCode404Response = { + content:string; + + } + type GetPetByIdResult = GetPetByIdDefaultStatusCode of GetPetByIdDefaultStatusCodeResponse|GetPetByIdStatusCode400 of GetPetByIdStatusCode400Response|GetPetByIdStatusCode404 of GetPetByIdStatusCode404Response + + type GetPetByIdArgs = { + pathParams:GetPetByIdPathParams; + } + + //#region Body parameters + [] + type UpdatePetBodyParams = Pet + //#endregion + + + type UpdatePetStatusCode400Response = { + content:string; + + } + + type UpdatePetStatusCode404Response = { + content:string; + + } + + type UpdatePetStatusCode405Response = { + content:string; + + } + type UpdatePetResult = UpdatePetStatusCode400 of UpdatePetStatusCode400Response|UpdatePetStatusCode404 of UpdatePetStatusCode404Response|UpdatePetStatusCode405 of UpdatePetStatusCode405Response + + type UpdatePetArgs = { + bodyParams:UpdatePetBodyParams + } + //#region Path parameters + [] + type UpdatePetWithFormPathParams = { + petId : int64 ; + } + //#endregion + + //#region Form parameters + [] + type UpdatePetWithFormFormParams = { + name : string option; + //#endregion + + //#region Form parameters + status : string option; + } + //#endregion + + + type UpdatePetWithFormStatusCode405Response = { + content:string; + + } + type UpdatePetWithFormResult = UpdatePetWithFormStatusCode405 of UpdatePetWithFormStatusCode405Response + + type UpdatePetWithFormArgs = { + pathParams:UpdatePetWithFormPathParams; + formParams:Result + } + //#region Path parameters + [] + type UploadFilePathParams = { + petId : int64 ; + } + //#endregion + + //#region Form parameters + [] + type UploadFileFormParams = { + additionalMetadata : string option; + //#endregion + + //#region Form parameters + file : System.IO.Stream option; + } + //#endregion + + + type UploadFileDefaultStatusCodeResponse = { + content:ApiResponse; + + } + type UploadFileResult = UploadFileDefaultStatusCode of UploadFileDefaultStatusCodeResponse + + type UploadFileArgs = { + pathParams:UploadFilePathParams; + formParams:Result + } + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiServiceInterface.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiServiceInterface.fs new file mode 100644 index 000000000000..d30fe21fff5d --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/PetApiServiceInterface.fs @@ -0,0 +1,19 @@ +namespace OpenAPI +open PetApiHandlerParams +open System +open Microsoft.AspNetCore.Http + + +module PetApiServiceInterface = + + //#region Service interface + type IPetApiService = + abstract member AddPet : AddPetBodyParams -> AddPetResult + abstract member DeletePet : unit -> DeletePetResult + abstract member FindPetsByStatus : unit -> FindPetsByStatusResult + abstract member FindPetsByTags : unit -> FindPetsByTagsResult + abstract member GetPetById : unit -> GetPetByIdResult + abstract member UpdatePet : UpdatePetBodyParams -> UpdatePetResult + abstract member UpdatePetWithForm : unit -> UpdatePetWithFormResult + abstract member UploadFile : unit -> UploadFileResult + //#endregion \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiHandler.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiHandler.fs new file mode 100644 index 000000000000..82c9a05e19ff --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiHandler.fs @@ -0,0 +1,110 @@ +namespace OpenAPI + +open StoreApiHandlerParams +open StoreApiServiceImplementation +open Microsoft.AspNetCore.Mvc +open Microsoft.AspNetCore.Http +open Newtonsoft.Json +open Microsoft.Azure.WebJobs +open System.IO + +module StoreApiHandlers = + + /// + /// + /// + + //#region DeleteOrder + /// + /// Delete purchase order by ID + /// + [] + let DeleteOrder + ([] + req:HttpRequest ) = + + let result = StoreApiService.DeleteOrder () + match result with + | DeleteOrderStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + | DeleteOrderStatusCode404 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(404)) + + //#region GetInventory + /// + /// Returns pet inventories by status + /// + [] + let GetInventory + ([] + req:HttpRequest ) = + + let result = StoreApiService.GetInventory () + match result with + | GetInventoryDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + + //#region GetOrderById + /// + /// Find purchase order by ID + /// + [] + let GetOrderById + ([] + req:HttpRequest ) = + + let result = StoreApiService.GetOrderById () + match result with + | GetOrderByIdDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + | GetOrderByIdStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + | GetOrderByIdStatusCode404 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(404)) + + //#region PlaceOrder + /// + /// Place an order for a pet + /// + [] + let PlaceOrder + ([] + req:HttpRequest ) = + + use reader = StreamReader(req.Body) + + let mediaTypes = [] // currently unused + + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = StoreApiService.PlaceOrder bodyParams + match result with + | PlaceOrderDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + | PlaceOrderStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + + + + diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiHandlerParams.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiHandlerParams.fs new file mode 100644 index 000000000000..2c9226f8abfe --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiHandlerParams.fs @@ -0,0 +1,88 @@ +namespace OpenAPI + +open System.Collections.Generic +open OpenAPI.Model.Order +open System.Collections.Generic +open System + +module StoreApiHandlerParams = + + //#region Path parameters + [] + type DeleteOrderPathParams = { + orderId : string ; + } + //#endregion + + + type DeleteOrderStatusCode400Response = { + content:string; + + } + + type DeleteOrderStatusCode404Response = { + content:string; + + } + type DeleteOrderResult = DeleteOrderStatusCode400 of DeleteOrderStatusCode400Response|DeleteOrderStatusCode404 of DeleteOrderStatusCode404Response + + type DeleteOrderArgs = { + pathParams:DeleteOrderPathParams; + } + + + type GetInventoryDefaultStatusCodeResponse = { + content:IDictionary; + + } + type GetInventoryResult = GetInventoryDefaultStatusCode of GetInventoryDefaultStatusCodeResponse + + //#region Path parameters + [] + type GetOrderByIdPathParams = { + orderId : int64 ; + } + //#endregion + + + type GetOrderByIdDefaultStatusCodeResponse = { + content:Order; + + } + + type GetOrderByIdStatusCode400Response = { + content:string; + + } + + type GetOrderByIdStatusCode404Response = { + content:string; + + } + type GetOrderByIdResult = GetOrderByIdDefaultStatusCode of GetOrderByIdDefaultStatusCodeResponse|GetOrderByIdStatusCode400 of GetOrderByIdStatusCode400Response|GetOrderByIdStatusCode404 of GetOrderByIdStatusCode404Response + + type GetOrderByIdArgs = { + pathParams:GetOrderByIdPathParams; + } + + //#region Body parameters + [] + type PlaceOrderBodyParams = Order + //#endregion + + + type PlaceOrderDefaultStatusCodeResponse = { + content:Order; + + } + + type PlaceOrderStatusCode400Response = { + content:string; + + } + type PlaceOrderResult = PlaceOrderDefaultStatusCode of PlaceOrderDefaultStatusCodeResponse|PlaceOrderStatusCode400 of PlaceOrderStatusCode400Response + + type PlaceOrderArgs = { + bodyParams:PlaceOrderBodyParams + } + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiServiceInterface.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiServiceInterface.fs new file mode 100644 index 000000000000..0e8e072b8b53 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/StoreApiServiceInterface.fs @@ -0,0 +1,15 @@ +namespace OpenAPI +open StoreApiHandlerParams +open System +open Microsoft.AspNetCore.Http + + +module StoreApiServiceInterface = + + //#region Service interface + type IStoreApiService = + abstract member DeleteOrder : unit -> DeleteOrderResult + abstract member GetInventory : unit -> GetInventoryResult + abstract member GetOrderById : unit -> GetOrderByIdResult + abstract member PlaceOrder : PlaceOrderBodyParams -> PlaceOrderResult + //#endregion \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiHandler.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiHandler.fs new file mode 100644 index 000000000000..35f1ddf71570 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiHandler.fs @@ -0,0 +1,211 @@ +namespace OpenAPI + +open UserApiHandlerParams +open UserApiServiceImplementation +open Microsoft.AspNetCore.Mvc +open Microsoft.AspNetCore.Http +open Newtonsoft.Json +open Microsoft.Azure.WebJobs +open System.IO + +module UserApiHandlers = + + /// + /// + /// + + //#region CreateUser + /// + /// Create user + /// + [] + let CreateUser + ([] + req:HttpRequest ) = + + use reader = StreamReader(req.Body) + + let mediaTypes = [] // currently unused + + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = UserApiService.CreateUser bodyParams + match result with + | CreateUserDefaultStatusCode resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(0)) + + //#region CreateUsersWithArrayInput + /// + /// Creates list of users with given input array + /// + [] + let CreateUsersWithArrayInput + ([] + req:HttpRequest ) = + + use reader = StreamReader(req.Body) + + let mediaTypes = [] // currently unused + + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = UserApiService.CreateUsersWithArrayInput bodyParams + match result with + | CreateUsersWithArrayInputDefaultStatusCode resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(0)) + + //#region CreateUsersWithListInput + /// + /// Creates list of users with given input array + /// + [] + let CreateUsersWithListInput + ([] + req:HttpRequest ) = + + use reader = StreamReader(req.Body) + + let mediaTypes = [] // currently unused + + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = UserApiService.CreateUsersWithListInput bodyParams + match result with + | CreateUsersWithListInputDefaultStatusCode resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(0)) + + //#region DeleteUser + /// + /// Delete user + /// + [] + let DeleteUser + ([] + req:HttpRequest ) = + + let result = UserApiService.DeleteUser () + match result with + | DeleteUserStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + | DeleteUserStatusCode404 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(404)) + + //#region GetUserByName + /// + /// Get user by user name + /// + [] + let GetUserByName + ([] + req:HttpRequest ) = + + let result = UserApiService.GetUserByName () + match result with + | GetUserByNameDefaultStatusCode resolved -> + let content = JsonConvert.SerializeObject resolved.content + let responseContentType = "application/json" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + | GetUserByNameStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + | GetUserByNameStatusCode404 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(404)) + + //#region LoginUser + /// + /// Logs user into the system + /// + [] + let LoginUser + ([] + req:HttpRequest ) = + + let result = UserApiService.LoginUser () + match result with + | LoginUserDefaultStatusCode resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(200)) + | LoginUserStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + + //#region LogoutUser + /// + /// Logs out current logged in user session + /// + [] + let LogoutUser + ([] + req:HttpRequest ) = + + let result = UserApiService.LogoutUser () + match result with + | LogoutUserDefaultStatusCode resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(0)) + + //#region UpdateUser + /// + /// Updated user + /// + [] + let UpdateUser + ([] + req:HttpRequest ) = + + use reader = StreamReader(req.Body) + + let mediaTypes = [] // currently unused + + let bind (contentType:string) body = + match (contentType.ToLower()) with + | "application/json" -> + body |> JsonConvert.DeserializeObject + | _ -> failwith (sprintf "TODO - ContentType %s not currently supported" contentType) + + let bodyParams = reader.ReadToEnd() |> bind req.ContentType + let result = UserApiService.UpdateUser bodyParams + match result with + | UpdateUserStatusCode400 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(400)) + | UpdateUserStatusCode404 resolved -> + let content = resolved.content + let responseContentType = "text/plain" + ContentResult(Content = content, ContentType = responseContentType, StatusCode = System.Nullable(404)) + + + + diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiHandlerParams.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiHandlerParams.fs new file mode 100644 index 000000000000..42c51c93a664 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiHandlerParams.fs @@ -0,0 +1,169 @@ +namespace OpenAPI + +open OpenAPI.Model.User +open System.Collections.Generic +open System + +module UserApiHandlerParams = + + + //#region Body parameters + [] + type CreateUserBodyParams = User + //#endregion + + + type CreateUserDefaultStatusCodeResponse = { + content:string; + + } + type CreateUserResult = CreateUserDefaultStatusCode of CreateUserDefaultStatusCodeResponse + + type CreateUserArgs = { + bodyParams:CreateUserBodyParams + } + + //#region Body parameters + [] + type CreateUsersWithArrayInputBodyParams = User[] + //#endregion + + + type CreateUsersWithArrayInputDefaultStatusCodeResponse = { + content:string; + + } + type CreateUsersWithArrayInputResult = CreateUsersWithArrayInputDefaultStatusCode of CreateUsersWithArrayInputDefaultStatusCodeResponse + + type CreateUsersWithArrayInputArgs = { + bodyParams:CreateUsersWithArrayInputBodyParams + } + + //#region Body parameters + [] + type CreateUsersWithListInputBodyParams = User[] + //#endregion + + + type CreateUsersWithListInputDefaultStatusCodeResponse = { + content:string; + + } + type CreateUsersWithListInputResult = CreateUsersWithListInputDefaultStatusCode of CreateUsersWithListInputDefaultStatusCodeResponse + + type CreateUsersWithListInputArgs = { + bodyParams:CreateUsersWithListInputBodyParams + } + //#region Path parameters + [] + type DeleteUserPathParams = { + username : string ; + } + //#endregion + + + type DeleteUserStatusCode400Response = { + content:string; + + } + + type DeleteUserStatusCode404Response = { + content:string; + + } + type DeleteUserResult = DeleteUserStatusCode400 of DeleteUserStatusCode400Response|DeleteUserStatusCode404 of DeleteUserStatusCode404Response + + type DeleteUserArgs = { + pathParams:DeleteUserPathParams; + } + //#region Path parameters + [] + type GetUserByNamePathParams = { + username : string ; + } + //#endregion + + + type GetUserByNameDefaultStatusCodeResponse = { + content:User; + + } + + type GetUserByNameStatusCode400Response = { + content:string; + + } + + type GetUserByNameStatusCode404Response = { + content:string; + + } + type GetUserByNameResult = GetUserByNameDefaultStatusCode of GetUserByNameDefaultStatusCodeResponse|GetUserByNameStatusCode400 of GetUserByNameStatusCode400Response|GetUserByNameStatusCode404 of GetUserByNameStatusCode404Response + + type GetUserByNameArgs = { + pathParams:GetUserByNamePathParams; + } + + //#region Query parameters + [] + type LoginUserQueryParams = { + username : string ; + + + password : string ; + + } + //#endregion + + + type LoginUserDefaultStatusCodeResponse = { + content:string; + + } + + type LoginUserStatusCode400Response = { + content:string; + + } + type LoginUserResult = LoginUserDefaultStatusCode of LoginUserDefaultStatusCodeResponse|LoginUserStatusCode400 of LoginUserStatusCode400Response + + type LoginUserArgs = { + queryParams:Result; + } + + + type LogoutUserDefaultStatusCodeResponse = { + content:string; + + } + type LogoutUserResult = LogoutUserDefaultStatusCode of LogoutUserDefaultStatusCodeResponse + + //#region Path parameters + [] + type UpdateUserPathParams = { + username : string ; + } + //#endregion + + //#region Body parameters + [] + type UpdateUserBodyParams = User + //#endregion + + + type UpdateUserStatusCode400Response = { + content:string; + + } + + type UpdateUserStatusCode404Response = { + content:string; + + } + type UpdateUserResult = UpdateUserStatusCode400 of UpdateUserStatusCode400Response|UpdateUserStatusCode404 of UpdateUserStatusCode404Response + + type UpdateUserArgs = { + pathParams:UpdateUserPathParams; + bodyParams:UpdateUserBodyParams + } + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiServiceInterface.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiServiceInterface.fs new file mode 100644 index 000000000000..d1aefa1cfb95 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/api/UserApiServiceInterface.fs @@ -0,0 +1,19 @@ +namespace OpenAPI +open UserApiHandlerParams +open System +open Microsoft.AspNetCore.Http + + +module UserApiServiceInterface = + + //#region Service interface + type IUserApiService = + abstract member CreateUser : CreateUserBodyParams -> CreateUserResult + abstract member CreateUsersWithArrayInput : CreateUsersWithArrayInputBodyParams -> CreateUsersWithArrayInputResult + abstract member CreateUsersWithListInput : CreateUsersWithListInputBodyParams -> CreateUsersWithListInputResult + abstract member DeleteUser : unit -> DeleteUserResult + abstract member GetUserByName : unit -> GetUserByNameResult + abstract member LoginUser : unit -> LoginUserResult + abstract member LogoutUser : unit -> LogoutUserResult + abstract member UpdateUser : UpdateUserBodyParams -> UpdateUserResult + //#endregion \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/PetApiService.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/PetApiService.fs new file mode 100644 index 000000000000..913aff5bc1ff --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/PetApiService.fs @@ -0,0 +1,71 @@ +namespace OpenAPI +open OpenAPI.Model.ApiResponse +open OpenAPI.Model.Pet +open PetApiHandlerParams +open PetApiServiceInterface +open System.Collections.Generic +open System + +module PetApiServiceImplementation = + + //#region Service implementation + type PetApiServiceImpl() = + interface IPetApiService with + + member this.AddPet (parameters:AddPetBodyParams) = + let content = "Invalid input" + AddPetStatusCode405 { content = content } + + member this.DeletePet () = + let content = "Invalid pet value" + DeletePetStatusCode400 { content = content } + + member this.FindPetsByStatus () = + if true then + let content = "successful operation" :> obj :?> Pet[] // this cast is obviously wrong, and is only intended to allow generated project to compile + FindPetsByStatusDefaultStatusCode { content = content } + else + let content = "Invalid status value" + FindPetsByStatusStatusCode400 { content = content } + + member this.FindPetsByTags () = + if true then + let content = "successful operation" :> obj :?> Pet[] // this cast is obviously wrong, and is only intended to allow generated project to compile + FindPetsByTagsDefaultStatusCode { content = content } + else + let content = "Invalid tag value" + FindPetsByTagsStatusCode400 { content = content } + + member this.GetPetById () = + if true then + let content = "successful operation" :> obj :?> Pet // this cast is obviously wrong, and is only intended to allow generated project to compile + GetPetByIdDefaultStatusCode { content = content } + else if true then + let content = "Invalid ID supplied" + GetPetByIdStatusCode400 { content = content } + else + let content = "Pet not found" + GetPetByIdStatusCode404 { content = content } + + member this.UpdatePet (parameters:UpdatePetBodyParams) = + if true then + let content = "Invalid ID supplied" + UpdatePetStatusCode400 { content = content } + else if true then + let content = "Pet not found" + UpdatePetStatusCode404 { content = content } + else + let content = "Validation exception" + UpdatePetStatusCode405 { content = content } + + member this.UpdatePetWithForm () = + let content = "Invalid input" + UpdatePetWithFormStatusCode405 { content = content } + + member this.UploadFile () = + let content = "successful operation" :> obj :?> ApiResponse // this cast is obviously wrong, and is only intended to allow generated project to compile + UploadFileDefaultStatusCode { content = content } + + //#endregion + + let PetApiService = PetApiServiceImpl() :> IPetApiService \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/StoreApiService.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/StoreApiService.fs new file mode 100644 index 000000000000..13ea7dde1501 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/StoreApiService.fs @@ -0,0 +1,48 @@ +namespace OpenAPI +open System.Collections.Generic +open OpenAPI.Model.Order +open StoreApiHandlerParams +open StoreApiServiceInterface +open System.Collections.Generic +open System + +module StoreApiServiceImplementation = + + //#region Service implementation + type StoreApiServiceImpl() = + interface IStoreApiService with + + member this.DeleteOrder () = + if true then + let content = "Invalid ID supplied" + DeleteOrderStatusCode400 { content = content } + else + let content = "Order not found" + DeleteOrderStatusCode404 { content = content } + + member this.GetInventory () = + let content = "successful operation" :> obj :?> IDictionary // this cast is obviously wrong, and is only intended to allow generated project to compile + GetInventoryDefaultStatusCode { content = content } + + member this.GetOrderById () = + if true then + let content = "successful operation" :> obj :?> Order // this cast is obviously wrong, and is only intended to allow generated project to compile + GetOrderByIdDefaultStatusCode { content = content } + else if true then + let content = "Invalid ID supplied" + GetOrderByIdStatusCode400 { content = content } + else + let content = "Order not found" + GetOrderByIdStatusCode404 { content = content } + + member this.PlaceOrder (parameters:PlaceOrderBodyParams) = + if true then + let content = "successful operation" :> obj :?> Order // this cast is obviously wrong, and is only intended to allow generated project to compile + PlaceOrderDefaultStatusCode { content = content } + else + let content = "Invalid Order" + PlaceOrderStatusCode400 { content = content } + + //#endregion + + let StoreApiService = StoreApiServiceImpl() :> IStoreApiService \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/UserApiService.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/UserApiService.fs new file mode 100644 index 000000000000..63d1bfcd1369 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/impl/UserApiService.fs @@ -0,0 +1,67 @@ +namespace OpenAPI +open OpenAPI.Model.User +open UserApiHandlerParams +open UserApiServiceInterface +open System.Collections.Generic +open System + +module UserApiServiceImplementation = + + //#region Service implementation + type UserApiServiceImpl() = + interface IUserApiService with + + member this.CreateUser (parameters:CreateUserBodyParams) = + let content = "successful operation" + CreateUserDefaultStatusCode { content = content } + + member this.CreateUsersWithArrayInput (parameters:CreateUsersWithArrayInputBodyParams) = + let content = "successful operation" + CreateUsersWithArrayInputDefaultStatusCode { content = content } + + member this.CreateUsersWithListInput (parameters:CreateUsersWithListInputBodyParams) = + let content = "successful operation" + CreateUsersWithListInputDefaultStatusCode { content = content } + + member this.DeleteUser () = + if true then + let content = "Invalid username supplied" + DeleteUserStatusCode400 { content = content } + else + let content = "User not found" + DeleteUserStatusCode404 { content = content } + + member this.GetUserByName () = + if true then + let content = "successful operation" :> obj :?> User // this cast is obviously wrong, and is only intended to allow generated project to compile + GetUserByNameDefaultStatusCode { content = content } + else if true then + let content = "Invalid username supplied" + GetUserByNameStatusCode400 { content = content } + else + let content = "User not found" + GetUserByNameStatusCode404 { content = content } + + member this.LoginUser () = + if true then + let content = "successful operation" :> obj :?> string // this cast is obviously wrong, and is only intended to allow generated project to compile + LoginUserDefaultStatusCode { content = content } + else + let content = "Invalid username/password supplied" + LoginUserStatusCode400 { content = content } + + member this.LogoutUser () = + let content = "successful operation" + LogoutUserDefaultStatusCode { content = content } + + member this.UpdateUser (parameters:UpdateUserBodyParams) = + if true then + let content = "Invalid user supplied" + UpdateUserStatusCode400 { content = content } + else + let content = "User not found" + UpdateUserStatusCode404 { content = content } + + //#endregion + + let UserApiService = UserApiServiceImpl() :> IUserApiService \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/model/ApiResponse.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/ApiResponse.fs new file mode 100644 index 000000000000..aed7bd6288fb --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/ApiResponse.fs @@ -0,0 +1,22 @@ +namespace OpenAPI.Model + +open System +open System.Collections.Generic +open Newtonsoft.Json + +module ApiResponse = + + //#region ApiResponse + + [] + type ApiResponse = { + [] + Code : int; + [] + Type : string; + [] + Message : string; + } + + //#endregion + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Category.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Category.fs new file mode 100644 index 000000000000..866d74e8d9e9 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Category.fs @@ -0,0 +1,20 @@ +namespace OpenAPI.Model + +open System +open System.Collections.Generic +open Newtonsoft.Json + +module Category = + + //#region Category + + [] + type Category = { + [] + Id : int64; + [] + Name : string; + } + + //#endregion + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Order.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Order.fs new file mode 100644 index 000000000000..8d5c9f769b17 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Order.fs @@ -0,0 +1,28 @@ +namespace OpenAPI.Model + +open System +open System.Collections.Generic +open Newtonsoft.Json + +module Order = + + //#region Order + + [] + type Order = { + [] + Id : int64; + [] + PetId : int64; + [] + Quantity : int; + [] + ShipDate : Nullable; + [] + Status : string; + [] + Complete : bool; + } + + //#endregion + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Pet.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Pet.fs new file mode 100644 index 000000000000..0917e14410f6 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Pet.fs @@ -0,0 +1,30 @@ +namespace OpenAPI.Model + +open System +open System.Collections.Generic +open Newtonsoft.Json +open OpenAPI.Model.Category +open OpenAPI.Model.Tag + +module Pet = + + //#region Pet + + [] + type Pet = { + [] + Id : int64; + [] + Category : Category; + [] + Name : string; + [] + PhotoUrls : string[]; + [] + Tags : Tag[]; + [] + Status : string; + } + + //#endregion + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Tag.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Tag.fs new file mode 100644 index 000000000000..3e4e1996b3ed --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/Tag.fs @@ -0,0 +1,20 @@ +namespace OpenAPI.Model + +open System +open System.Collections.Generic +open Newtonsoft.Json + +module Tag = + + //#region Tag + + [] + type Tag = { + [] + Id : int64; + [] + Name : string; + } + + //#endregion + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/OpenAPI/src/model/User.fs b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/User.fs new file mode 100644 index 000000000000..4c77e4c8a547 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/OpenAPI/src/model/User.fs @@ -0,0 +1,32 @@ +namespace OpenAPI.Model + +open System +open System.Collections.Generic +open Newtonsoft.Json + +module User = + + //#region User + + [] + type User = { + [] + Id : int64; + [] + Username : string; + [] + FirstName : string; + [] + LastName : string; + [] + Email : string; + [] + Password : string; + [] + Phone : string; + [] + UserStatus : int; + } + + //#endregion + \ No newline at end of file diff --git a/samples/server/petstore/fsharp-functions/host.json b/samples/server/petstore/fsharp-functions/host.json new file mode 100644 index 000000000000..ccd1678a5e12 --- /dev/null +++ b/samples/server/petstore/fsharp-functions/host.json @@ -0,0 +1,8 @@ +{ + "version": "2.0", + "extensions":{ + "http": { + "routePrefix": "" + } + } +} \ No newline at end of file diff --git a/samples/server/petstore/fsharp-giraffe/.openapi-generator/VERSION b/samples/server/petstore/fsharp-giraffe/.openapi-generator/VERSION index afa636560641..0e97bd19efbf 100644 --- a/samples/server/petstore/fsharp-giraffe/.openapi-generator/VERSION +++ b/samples/server/petstore/fsharp-giraffe/.openapi-generator/VERSION @@ -1 +1 @@ -4.0.0-SNAPSHOT \ No newline at end of file +4.1.3-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/PetApiTests.fs b/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/PetApiTests.fs index 8408a25602ee..aec008210d56 100644 --- a/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/PetApiTests.fs +++ b/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/PetApiTests.fs @@ -106,7 +106,7 @@ module PetApiHandlerTests = // add your setup code here - let path = "/v2/pet/findByTags" + "?tags=ADDME&maxCount=ADDME" + let path = "/v2/pet/findByTags" + "?tags=ADDME" HttpGet client path |> isStatus (enum(200)) @@ -123,7 +123,7 @@ module PetApiHandlerTests = // add your setup code here - let path = "/v2/pet/findByTags" + "?tags=ADDME&maxCount=ADDME" + let path = "/v2/pet/findByTags" + "?tags=ADDME" HttpGet client path |> isStatus (enum(400)) diff --git a/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/UserApiTestsHelper.fs b/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/UserApiTestsHelper.fs index 352c553e0c02..fca7987ef4c8 100644 --- a/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/UserApiTestsHelper.fs +++ b/samples/server/petstore/fsharp-giraffe/OpenAPI.Tests/UserApiTestsHelper.fs @@ -40,8 +40,17 @@ module UserApiHandlerTestsHelper = let mutable CreateUsersWithArrayInputExamples = Map.empty let mutable CreateUsersWithArrayInputBody = "" - CreateUsersWithArrayInputBody <- WebUtility.HtmlDecode "" - CreateUsersWithArrayInputExamples <- CreateUsersWithArrayInputExamples.Add("", CreateUsersWithArrayInputBody) + CreateUsersWithArrayInputBody <- WebUtility.HtmlDecode "{ + "firstName" : "firstName", + "lastName" : "lastName", + "password" : "password", + "userStatus" : 6, + "phone" : "phone", + "id" : 0, + "email" : "email", + "username" : "username" +}" + CreateUsersWithArrayInputExamples <- CreateUsersWithArrayInputExamples.Add("application/json", CreateUsersWithArrayInputBody) let getCreateUsersWithArrayInputExample mediaType = CreateUsersWithArrayInputExamples.[mediaType] @@ -50,8 +59,17 @@ module UserApiHandlerTestsHelper = let mutable CreateUsersWithListInputExamples = Map.empty let mutable CreateUsersWithListInputBody = "" - CreateUsersWithListInputBody <- WebUtility.HtmlDecode "" - CreateUsersWithListInputExamples <- CreateUsersWithListInputExamples.Add("", CreateUsersWithListInputBody) + CreateUsersWithListInputBody <- WebUtility.HtmlDecode "{ + "firstName" : "firstName", + "lastName" : "lastName", + "password" : "password", + "userStatus" : 6, + "phone" : "phone", + "id" : 0, + "email" : "email", + "username" : "username" +}" + CreateUsersWithListInputExamples <- CreateUsersWithListInputExamples.Add("application/json", CreateUsersWithListInputBody) let getCreateUsersWithListInputExample mediaType = CreateUsersWithListInputExamples.[mediaType] diff --git a/samples/server/petstore/fsharp-giraffe/OpenAPI/README.md b/samples/server/petstore/fsharp-giraffe/OpenAPI/README.md index 42731ee69c65..c529ef85cdd8 100644 --- a/samples/server/petstore/fsharp-giraffe/OpenAPI/README.md +++ b/samples/server/petstore/fsharp-giraffe/OpenAPI/README.md @@ -6,7 +6,6 @@ A [Giraffe](https://github.com/giraffe-fsharp/Giraffe) server stub for the OpenA The following models have been auto-generated from the provided OpenAPI schema: -- model/ApiResponseModel.fs - model/UserModel.fs - model/TagModel.fs - model/CategoryModel.fs @@ -14,6 +13,7 @@ The following models have been auto-generated from the provided OpenAPI schema: - model/InlineObject1Model.fs - model/InlineObjectModel.fs - model/PetModel.fs +- model/ApiResponseModel.fs ## Operations diff --git a/samples/server/petstore/fsharp-giraffe/OpenAPI/src/OpenAPI.fsproj b/samples/server/petstore/fsharp-giraffe/OpenAPI/src/OpenAPI.fsproj index a5d1a1bebb10..4b31d698ba33 100644 --- a/samples/server/petstore/fsharp-giraffe/OpenAPI/src/OpenAPI.fsproj +++ b/samples/server/petstore/fsharp-giraffe/OpenAPI/src/OpenAPI.fsproj @@ -21,7 +21,6 @@ - @@ -29,6 +28,7 @@ + diff --git a/samples/server/petstore/fsharp-giraffe/OpenAPI/src/api/PetApiHandlerParams.fs b/samples/server/petstore/fsharp-giraffe/OpenAPI/src/api/PetApiHandlerParams.fs index 6bc290e74a7a..f84ffb76b22c 100644 --- a/samples/server/petstore/fsharp-giraffe/OpenAPI/src/api/PetApiHandlerParams.fs +++ b/samples/server/petstore/fsharp-giraffe/OpenAPI/src/api/PetApiHandlerParams.fs @@ -78,9 +78,6 @@ module PetApiHandlerParams = type FindPetsByTagsQueryParams = { tags : string[] ; - - maxCount : int option; - } //#endregion