diff --git a/.gitignore b/.gitignore index 291d302ff08..7f6a9b4e5f0 100644 --- a/.gitignore +++ b/.gitignore @@ -169,3 +169,8 @@ effective.pom # kotlin samples/client/petstore/kotlin/src/main/kotlin/test/ \? + +# haskell +.stack-work +.cabal-sandbox +cabal.project.local diff --git a/.travis.yml b/.travis.yml index d6a4f8bedcc..7ca04a0ad95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ cache: - $HOME/.ivy2 - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ + - $HOME/.stack - $HOME/samples/client/petstore/php/SwaggerClient-php/vendor - $HOME/samples/client/petstore/ruby/venodr/bundle - $HOME/samples/client/petstore/python/.venv/ @@ -23,6 +24,7 @@ cache: - $HOME/samples/client/petstore/typescript-angularjs/node_modules - $HOME/samples/client/petstore/typescript-angularjs/typings - $HOME/.cocoapods/repos/master + timeout: 1000 # note: docker is not yet supported in iOS build #services: # - docker @@ -52,6 +54,9 @@ before_install: - brew install curl - brew install python3 - pip install virtualenv + - mkdir -p ~/.local/bin + - export PATH=$HOME/.local/bin:$PATH + - travis_retry curl --insecure -L https://www.stackage.org/stack/osx-x86_64 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin # start local petstore server - git clone -b docker --single-branch https://github.com/wing328/swagger-samples - cd swagger-samples/java/java-jersey-jaxrs @@ -76,6 +81,8 @@ before_install: - xcpretty -v # show go version - go version + # show stack version + - stack --version install: # Add Godeps dependencies to GOPATH and PATH diff --git a/bin/haskell-http-client-petstore.sh b/bin/haskell-http-client-petstore.sh new file mode 100755 index 00000000000..ac21b66a745 --- /dev/null +++ b/bin/haskell-http-client-petstore.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -t modules/swagger-codegen/src/main/resources/haskell-http-client -i modules/swagger-codegen/src/test/resources/2_0/petstore.yaml -l haskell-http-client -o samples/client/petstore/haskell-http-client" + +java $JAVA_OPTS -jar $executable $ags diff --git a/bin/windows/haskell-http-client-petstore.bat b/bin/windows/haskell-http-client-petstore.bat new file mode 100755 index 00000000000..95e16a1238c --- /dev/null +++ b/bin/windows/haskell-http-client-petstore.bat @@ -0,0 +1,10 @@ +set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties +set ags=generate -i modules\swagger-codegen\src\test\resources\2_0\petstore.yaml -l haskell-http-client -o samples\client\petstore\haskell-http-client + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/HaskellHttpClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/HaskellHttpClientCodegen.java new file mode 100644 index 00000000000..cd60a221aec --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/HaskellHttpClientCodegen.java @@ -0,0 +1,861 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.Model; +import io.swagger.models.ModelImpl; +import io.swagger.models.Operation; +import io.swagger.models.Swagger; +import io.swagger.models.parameters.Parameter; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.Property; + +import java.util.*; +import java.util.regex.Pattern; + +import org.apache.commons.io.FileUtils; + +import io.swagger.codegen.CliOption; +import io.swagger.codegen.CodegenConstants; +import io.swagger.codegen.CodegenModel; +import io.swagger.codegen.CodegenOperation; +import io.swagger.codegen.CodegenProperty; +import io.swagger.codegen.SupportingFile; +import io.swagger.util.Json; + +import java.io.IOException; +import java.io.File; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.text.WordUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenConfig { + + // source folder where to write the files + protected String sourceFolder = "src"; + protected String apiVersion = "0.0.1"; + + protected String artifactId = "swagger-haskell-http-client"; + protected String artifactVersion = "1.0.0"; + + protected String defaultDateTimeFormat = "%Y-%m-%dT%H:%M:%S%Q%z"; + protected String defaultDateFormat = "%Y-%m-%d"; + + // CLI + public static final String ALLOW_FROMJSON_NULLS = "allowFromJsonNulls"; + public static final String ALLOW_TOJSON_NULLS = "allowToJsonNulls"; + public static final String DATETIME_FORMAT = "dateTimeFormat"; + public static final String DATE_FORMAT = "dateFormat"; + public static final String GENERATE_FORM_URLENCODED_INSTANCES = "generateFormUrlEncodedInstances"; + public static final String GENERATE_LENSES = "generateLenses"; + public static final String GENERATE_MODEL_CONSTRUCTORS = "generateModelConstructors"; + public static final String MODEL_DERIVING = "modelDeriving"; + + // protected String MODEL_IMPORTS = "modelImports"; + // protected String MODEL_EXTENSIONS = "modelExtensions"; + + private static final Pattern LEADING_UNDERSCORE = Pattern.compile("^_+"); + + static final String MEDIA_TYPE = "mediaType"; + static final String MEDIA_DATA_TYPE = "x-mediaDataType"; + + + protected Map uniqueOptionalParamsByName = new HashMap(); + protected Map modelNames = new HashMap(); + protected Map> allMimeTypes = new HashMap>(); + protected Map knownMimeDataTypes = new HashMap(); + protected Map> modelMimeTypes = new HashMap>(); + protected String lastTag = ""; + protected ArrayList> unknownMimeTypes = new ArrayList>(); + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + public String getName() { + return "haskell-http-client"; + } + public String getHelp() { + return "Generates a Haskell http-client library."; + } + + + public HaskellHttpClientCodegen() { + super(); + + // override the mapping to keep the original mapping in Haskell + specialCharReplacements.put("-", "Dash"); + specialCharReplacements.put(">", "GreaterThan"); + specialCharReplacements.put("<", "LessThan"); + + // backslash and double quote need double the escapement for both Java and Haskell + specialCharReplacements.remove("\\"); + specialCharReplacements.remove("\""); + specialCharReplacements.put("\\\\", "Back_Slash"); + specialCharReplacements.put("\\\"", "Double_Quote"); + + // set the output folder here + outputFolder = "generated-code/haskell-http-client"; + + embeddedTemplateDir = templateDir = "haskell-http-client"; + apiPackage = "API"; + modelPackage = "Model"; + + // Haskell keywords and reserved function names, taken mostly from https://wiki.haskell.org/Keywords + setReservedWordsLowerCase( + Arrays.asList( + // Keywords + "as", "case", "of", + "class", "data", "family", + "default", "deriving", + "do", "forall", "foreign", "hiding", + "if", "then", "else", + "import", "infix", "infixl", "infixr", + "instance", "let", "in", + "mdo", "module", "newtype", + "proc", "qualified", "rec", + "type", "where" + ) + ); + + additionalProperties.put("apiVersion", apiVersion); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("stack.mustache", "", "stack.yaml")); + supportingFiles.add(new SupportingFile("Setup.mustache", "", "Setup.hs")); + supportingFiles.add(new SupportingFile(".gitignore", "", ".gitignore")); + supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml")); + supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + + supportingFiles.add(new SupportingFile("tests/ApproxEq.mustache", "tests", "ApproxEq.hs")); + supportingFiles.add(new SupportingFile("tests/Instances.mustache", "tests", "Instances.hs")); + supportingFiles.add(new SupportingFile("tests/PropMime.mustache", "tests", "PropMime.hs")); + supportingFiles.add(new SupportingFile("tests/Test.mustache", "tests", "Test.hs")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "Bool", + "String", + "Int", + "Integer", + "Float", + "Char", + "Double", + "List", + "FilePath" + ) + ); + + typeMapping.clear(); +// typeMapping.put("array", "List"); + typeMapping.put("set", "Set"); + typeMapping.put("boolean", "Bool"); + typeMapping.put("string", "Text"); + typeMapping.put("int", "Int"); + typeMapping.put("long", "Integer"); + typeMapping.put("short", "Int"); + typeMapping.put("char", "Char"); + typeMapping.put("float", "Float"); + typeMapping.put("double", "Double"); + typeMapping.put("Date", "Day"); + typeMapping.put("DateTime", "UTCTime"); + typeMapping.put("file", "FilePath"); + typeMapping.put("number", "Double"); + typeMapping.put("integer", "Int"); + typeMapping.put("any", "Value"); + typeMapping.put("UUID", "Text"); + typeMapping.put("binary", "ByteString"); + typeMapping.put("ByteArray", "ByteString"); + + knownMimeDataTypes.put("application/json", "MimeJSON"); + knownMimeDataTypes.put("application/xml", "MimeXML"); + knownMimeDataTypes.put("application/x-www-form-urlencoded", "MimeFormUrlEncoded"); + knownMimeDataTypes.put("application/octet-stream", "MimeOctetStream"); + knownMimeDataTypes.put("multipart/form-data", "MimeMultipartFormData"); + knownMimeDataTypes.put("text/plain", "MimePlainText"); + + importMapping.clear(); + importMapping.put("Map", "qualified Data.Map as Map"); + + cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC)); + cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC)); + + cliOptions.add(new CliOption(ALLOW_FROMJSON_NULLS, "allow JSON Null during model decoding from JSON").defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(ALLOW_TOJSON_NULLS, "allow emitting JSON Null during model encoding to JSON").defaultValue(Boolean.FALSE.toString())); + cliOptions.add(new CliOption(GENERATE_LENSES, "Generate Lens optics for Models").defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(GENERATE_MODEL_CONSTRUCTORS, "Generate smart constructors (only supply required fields) for models").defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(GENERATE_FORM_URLENCODED_INSTANCES, "Generate FromForm/ToForm instances for models that are used by operations that produce or consume application/x-www-form-urlencoded").defaultValue(Boolean.TRUE.toString())); + + cliOptions.add(new CliOption(MODEL_DERIVING, "Additional classes to include in the deriving() clause of Models")); + + cliOptions.add(new CliOption(DATETIME_FORMAT, "format string used to parse/render a datetime").defaultValue(defaultDateTimeFormat)); + cliOptions.add(new CliOption(DATE_FORMAT, "format string used to parse/render a date").defaultValue(defaultDateFormat)); + + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "hides the timestamp when files were generated").defaultValue(Boolean.TRUE.toString())); + + // cliOptions.add(new CliOption(MODEL_IMPORTS, "Additional imports in the Models file")); + // cliOptions.add(new CliOption(MODEL_EXTENSIONS, "Additional extensions in the Models file")); + } + + public void setAllowFromJsonNulls(Boolean value) { + additionalProperties.put(ALLOW_FROMJSON_NULLS, value); + } + + public void setAllowToJsonNulls(Boolean value) { + additionalProperties.put(ALLOW_TOJSON_NULLS, value); + } + + public void setGenerateModelConstructors(Boolean value) { + additionalProperties.put(GENERATE_MODEL_CONSTRUCTORS, value); + } + + public void setGenerateFormUrlEncodedInstances(Boolean value) { + additionalProperties.put(GENERATE_FORM_URLENCODED_INSTANCES, value); + } + + public void setGenerateLenses(Boolean value) { + additionalProperties.put(GENERATE_LENSES, value); + } + + public void setModelDeriving(String value) { + if (StringUtils.isBlank(value)) { + additionalProperties.remove(MODEL_DERIVING); + } else { + additionalProperties.put(MODEL_DERIVING, StringUtils.join(value.split(" "), ",")); + } + } + + public void setDateTimeFormat(String value) { + if (StringUtils.isBlank(value)) { + additionalProperties.remove(DATETIME_FORMAT); + } else { + additionalProperties.put(DATETIME_FORMAT, value); + } + + } + + public void setDateFormat(String value) { + if (StringUtils.isBlank(value)) { + additionalProperties.remove(DATE_FORMAT); + } else { + additionalProperties.put(DATE_FORMAT, value); + } + } + + @Override + public void processOpts() { + super.processOpts(); + // default HIDE_GENERATION_TIMESTAMP to true + if (additionalProperties.containsKey(CodegenConstants.HIDE_GENERATION_TIMESTAMP)) { + convertPropertyToBooleanAndWriteBack(CodegenConstants.HIDE_GENERATION_TIMESTAMP); + } else { + additionalProperties.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, true); + } + + if (additionalProperties.containsKey(ALLOW_FROMJSON_NULLS)) { + setAllowFromJsonNulls(convertPropertyToBoolean(ALLOW_FROMJSON_NULLS)); + } else { + setAllowFromJsonNulls(true); + } + + if (additionalProperties.containsKey(ALLOW_TOJSON_NULLS)) { + setAllowToJsonNulls(convertPropertyToBoolean(ALLOW_TOJSON_NULLS)); + } else { + setAllowToJsonNulls(false); + } + + if (additionalProperties.containsKey(GENERATE_MODEL_CONSTRUCTORS)) { + setGenerateModelConstructors(convertPropertyToBoolean(GENERATE_MODEL_CONSTRUCTORS)); + } else { + setGenerateModelConstructors(true); + } + + if (additionalProperties.containsKey(GENERATE_FORM_URLENCODED_INSTANCES)) { + setGenerateFormUrlEncodedInstances(convertPropertyToBoolean(GENERATE_FORM_URLENCODED_INSTANCES)); + } else { + setGenerateFormUrlEncodedInstances(true); + } + + if (additionalProperties.containsKey(GENERATE_LENSES)) { + setGenerateLenses(convertPropertyToBoolean(GENERATE_LENSES)); + } else { + setGenerateLenses(true); + } + + if (additionalProperties.containsKey(MODEL_DERIVING)) { + setModelDeriving(additionalProperties.get(MODEL_DERIVING).toString()); + } else { + setModelDeriving(""); + } + + if (additionalProperties.containsKey(DATETIME_FORMAT)) { + setDateTimeFormat(additionalProperties.get(DATETIME_FORMAT).toString()); + } else { + setDateTimeFormat(null); + } + + if (additionalProperties.containsKey(DATE_FORMAT)) { + setDateFormat(additionalProperties.get(DATE_FORMAT).toString()); + } else { + setDateFormat(null); + } + + } + +// @Override +// public String apiFileFolder() { +// String apiName = (String)additionalProperties.get("title"); +// return outputFolder + File.separator + "lib/" + apiName; +// } +// @Override +// public String modelFileFolder() { +// String apiName = (String)additionalProperties.get("title"); +// return outputFolder + File.separator + "lib/" + apiName; +// } + + @Override + public void preprocessSwagger(Swagger swagger) { + // From the title, compute a reasonable name for the package and the API + String title = swagger.getInfo().getTitle(); + + // Drop any API suffix + if (title == null) { + title = "Swagger"; + } else { + title = title.trim(); + if (title.toUpperCase().endsWith("API")) { + title = title.substring(0, title.length() - 3); + } + } + + String[] words = title.split(" "); + + // The package name is made by appending the lowercased words of the title interspersed with dashes + List wordsLower = new ArrayList(); + for (String word : words) { + wordsLower.add(word.toLowerCase()); + } + String cabalName = StringUtils.join(wordsLower, "-"); + String pathsName = StringUtils.join(wordsLower, "_"); + + // The API name is made by appending the capitalized words of the title + List wordsCaps = new ArrayList(); + for (String word : words) { + wordsCaps.add(firstLetterToUpper(word)); + } + String apiName = StringUtils.join(wordsCaps, ""); + + // Set the filenames to write for the API + + // root + supportingFiles.add(new SupportingFile("haskell-http-client.cabal.mustache", "", cabalName + ".cabal")); + + supportingFiles.add(new SupportingFile("haskell-http-client.cabal.mustache", "", cabalName + ".cabal")); + supportingFiles.add(new SupportingFile("package.mustache", "", "package.yaml")); + + // lib + supportingFiles.add(new SupportingFile("TopLevel.mustache", "lib/", apiName + ".hs")); + supportingFiles.add(new SupportingFile("Client.mustache", "lib/" + apiName, "Client.hs")); + + supportingFiles.add(new SupportingFile("API.mustache", "lib/" + apiName, "API.hs")); + supportingFiles.add(new SupportingFile("Model.mustache", "lib/" + apiName, "Model.hs")); + supportingFiles.add(new SupportingFile("MimeTypes.mustache", "lib/" + apiName, "MimeTypes.hs")); + + // modelTemplateFiles.put("API.mustache", ".hs"); + // apiTemplateFiles.put("Model.mustache", ".hs"); + + // lens + if ((boolean)additionalProperties.get(GENERATE_LENSES)) { + supportingFiles.add(new SupportingFile("Lens.mustache", "lib/" + apiName, "Lens.hs")); + } + + additionalProperties.put("title", apiName); + additionalProperties.put("titleLower", firstLetterToLower(apiName)); + additionalProperties.put("package", cabalName); + additionalProperties.put("pathsName", pathsName); + additionalProperties.put("requestType", apiName + "Request"); + additionalProperties.put("configType", apiName + "Config"); + additionalProperties.put("swaggerVersion", swagger.getSwagger()); + + // prepend ' +// List> replacements = new ArrayList<>(); +// Object[] replacementChars = specialCharReplacements.keySet().toArray(); +// for (int i = 0; i < replacementChars.length; i++) { +// String c = (String) replacementChars[i]; +// Map o = new HashMap<>(); +// o.put("char", c); +// o.put("replacement", "'" + specialCharReplacements.get(c)); +// o.put("hasMore", i != replacementChars.length - 1); +// replacements.add(o); +// } +// additionalProperties.put("specialCharReplacements", replacements); + + //copy input swagger to output folder + try { + String swaggerJson = Json.pretty(swagger); + FileUtils.writeStringToFile(new File(outputFolder + File.separator + "swagger.json"), swaggerJson); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e.getCause()); + } + + super.preprocessSwagger(swagger); + } + + + @Override + public String getTypeDeclaration(Property p) { + if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return "[" + getTypeDeclaration(inner) + "]"; + } else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + return "Map.Map String " + getTypeDeclaration(inner); + } + return fixModelChars(super.getTypeDeclaration(p)); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if (typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if (languageSpecificPrimitives.contains(type)) + return toModelName(type); + } else if (swaggerType == "object") { + type = "Value"; + } else if (typeMapping.containsValue(swaggerType)) { + type = swaggerType + "_"; + } else { + type = swaggerType; + } + return toModelName(type); + } + + @Override + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + Property additionalProperties2 = ap.getAdditionalProperties(); + String type = additionalProperties2.getType(); + if (null == type) { + LOGGER.error("No Type defined for Additional Property " + additionalProperties2 + "\n" // + + "\tIn Property: " + p); + } + String inner = getSwaggerType(additionalProperties2); + return "(Map.Map Text " + inner + ")"; + } else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + // Return only the inner type; the wrapping with QueryList is done + // somewhere else, where we have access to the collection format. + return inner; + } else { + return null; + } + } + + @Override + public CodegenOperation fromOperation(String resourcePath, String httpMethod, Operation operation, Map definitions, Swagger swagger) { + CodegenOperation op = super.fromOperation(resourcePath, httpMethod, operation, definitions, swagger); + + op.vendorExtensions.put("x-baseOperationId", op.operationId); + op.vendorExtensions.put("x-haddockPath", String.format("%s %s", op.httpMethod, op.path.replace("/", "\\/"))); + op.operationId = toHsVarName(op.operationId); + op.vendorExtensions.put("x-operationType", toHsTypeName(op.operationId)); + op.vendorExtensions.put("x-hasBodyOrFormParam", op.getHasBodyParam() || op.getHasFormParams()); + + for (CodegenParameter param : op.allParams) { + param.vendorExtensions.put("x-operationType", capitalize(op.operationId)); + param.vendorExtensions.put("x-isBodyOrFormParam", param.isBodyParam || param.isFormParam); + if (!StringUtils.isBlank(param.collectionFormat)) { + param.vendorExtensions.put("x-collectionFormat", mapCollectionFormat(param.collectionFormat)); + } + if (!param.required) { + op.vendorExtensions.put("x-hasOptionalParams", true); + + String paramNameType = capitalize(param.paramName); + + if (uniqueOptionalParamsByName.containsKey(paramNameType)) { + CodegenParameter lastParam = this.uniqueOptionalParamsByName.get(paramNameType); + if (lastParam.dataType != null && lastParam.dataType.equals(param.dataType)) { + param.vendorExtensions.put("x-duplicate", true); + } else { + paramNameType = paramNameType + param.dataType; + while (modelNames.containsKey(paramNameType)) { + paramNameType = generateNextName(paramNameType); + } + } + } else { + while (modelNames.containsKey(paramNameType)) { + paramNameType = generateNextName(paramNameType); + } + uniqueOptionalParamsByName.put(paramNameType, param); + } + + param.vendorExtensions.put("x-paramNameType", paramNameType); + op.vendorExtensions.put("x-hasBodyOrFormParam", op.getHasBodyParam() || op.getHasFormParams()); + } + } + if (op.getHasPathParams()) { + String remainingPath = op.path; + for (CodegenParameter param : op.pathParams) { + param.paramName = toHsVarName(param.paramName); + String[] pieces = remainingPath.split("\\{" + param.baseName + "\\}"); + if (pieces.length == 0) + throw new RuntimeException("paramName {" + param.baseName + "} not in path " + op.path); + if (pieces.length > 2) + throw new RuntimeException("paramName {" + param.baseName + "} found multiple times in path " + op.path); + if (pieces.length == 2) { + param.vendorExtensions.put("x-pathPrefix", pieces[0]); + remainingPath = pieces[1]; + } else { + if (remainingPath.startsWith("{" + param.baseName + "}")) { + remainingPath = pieces[0]; + } else { + param.vendorExtensions.put("x-pathPrefix", pieces[0]); + remainingPath = ""; + } + } + } + op.vendorExtensions.put("x-hasPathParams", true); + if (remainingPath.length() > 0) { + op.vendorExtensions.put("x-pathSuffix", remainingPath); + } + } else { + op.vendorExtensions.put("x-hasPathParams", false); + op.vendorExtensions.put("x-pathSuffix", op.path); + } + for (CodegenParameter param : op.queryParams) { + } + for (CodegenParameter param : op.headerParams) { + } + for (CodegenParameter param : op.bodyParams) { + } + for (CodegenParameter param : op.formParams) { + } + + if (op.hasConsumes) { + for (Map m : op.consumes) { + processMediaType(op,m); + } + if (isMultipart(op.consumes)) { + op.isMultipart = Boolean.TRUE; + } + } + if (op.hasProduces) { + for (Map m : op.produces) { + processMediaType(op,m); + } + } + + String returnType = op.returnType; + if (returnType == null || returnType.equals("null")) { + if(op.hasProduces) { + returnType = "res"; + op.vendorExtensions.put("x-hasUnknownReturn", true); + } else { + returnType = "NoContent"; + } + } + if (returnType.indexOf(" ") >= 0) { + returnType = "(" + returnType + ")"; + } + op.vendorExtensions.put("x-returnType", returnType); + + + return op; + } + + + @Override + public Map postProcessOperations(Map objs) { + Map ret = super.postProcessOperations(objs); + + HashMap pathOps = (HashMap)ret.get("operations"); + ArrayList ops = (ArrayList)pathOps.get("operation"); + if(ops.size() > 0) { + ops.get(0).vendorExtensions.put("x-hasNewTag", true); + } + + additionalProperties.put("x-hasUnknownMimeTypes", !unknownMimeTypes.isEmpty()); + additionalProperties.put("x-unknownMimeTypes", unknownMimeTypes); + + return ret; + } + + @Override + public Map postProcessOperationsWithModels(Map objs, List allModels) { + for (Object o : allModels) { + HashMap h = (HashMap) o; + CodegenModel m = (CodegenModel) h.get("model"); + if (modelMimeTypes.containsKey(m.classname)) { + Set mimeTypes = modelMimeTypes.get(m.classname); + m.vendorExtensions.put("x-mimeTypes", mimeTypes); + if ((boolean)additionalProperties.get(GENERATE_FORM_URLENCODED_INSTANCES) && mimeTypes.contains("MimeFormUrlEncoded")) { + Boolean hasMimeFormUrlEncoded = true; + for (CodegenProperty v : m.vars) { + if (!(v.isPrimitiveType || v.isString || v.isDate || v.isDateTime)) { + hasMimeFormUrlEncoded = false; + } + } + if (hasMimeFormUrlEncoded) { + m.vendorExtensions.put("x-hasMimeFormUrlEncoded", true); + } + } + } + + } + return objs; + } + + @Override + public CodegenModel fromModel(String name, Model mod, Map allDefinitions) { + CodegenModel model = super.fromModel(name, mod, allDefinitions); + + // Clean up the class name to remove invalid characters + model.classname = fixModelChars(model.classname); + if (typeMapping.containsValue(model.classname)) { + model.classname += "_"; + } + while (uniqueOptionalParamsByName.containsKey(model.classname)) { + model.classname = generateNextName(model.classname); + } + + // From the model name, compute the prefix for the fields. + String prefix = camelize(model.classname, true); + for (CodegenProperty prop : model.vars) { + prop.name = toVarName(prefix + camelize(fixOperatorChars(prop.name))); + } + + //String dataOrNewtype = "data"; + // check if it's a ModelImpl before casting + if (!(mod instanceof ModelImpl)) { + return model; + } + + // Create newtypes for things with non-object types +// String modelType = ((ModelImpl) mod).getType(); +// if(modelType != "object" && typeMapping.containsKey(modelType)) { +// String newtype = typeMapping.get(modelType); +// model.vendorExtensions.put("x-customNewtype", newtype); +// } + + modelNames.put(model.classname, model); + return model; + } + + @Override + public CodegenParameter fromParameter(Parameter param, Set imports) { + CodegenParameter p = super.fromParameter(param, imports); + p.paramName = toHsVarName(p.baseName); + p.dataType = fixModelChars(p.dataType); + return p; + } + + @Override + public String escapeReservedWord(String name) { + if (this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return "_" + name; + } + + @Override + public String toModelFilename(String name) { + // should be the same as the model name + return toModelName(name); + } + + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("{-", "{_-").replace("-}", "-_}"); + } + + @Override + public boolean isDataTypeFile(String dataType) { + return dataType != null && dataType.equals("FilePath"); + } + + @Override + public boolean isDataTypeBinary(final String dataType) { + return dataType != null && dataType.equals("B.ByteString"); + } + + private void processMediaType(CodegenOperation op, Map m) { + String mediaType = m.get(MEDIA_TYPE); + + if(StringUtils.isBlank(mediaType)) return; + + String[] mediaTypeParts = mediaType.split("/",2); + if(mediaTypeParts.length > 1) { + m.put("x-mediaMainType", mediaTypeParts[0]); + m.put("x-mediaSubType", mediaTypeParts[1]); + } else { + m.put("x-mediaMainType", mediaTypeParts[0]); + m.put("x-mediaSubType", ""); + } + + String mimeType = getMimeDataType(mediaType); + m.put(MEDIA_DATA_TYPE, mimeType); + + allMimeTypes.put(mediaType, m); + if(!knownMimeDataTypes.containsKey(mediaType) && !unknownMimeTypes.contains(m)) { + unknownMimeTypes.add(m); + } + for (CodegenParameter param : op.allParams) { + if (param.isBodyParam || param.isFormParam && (!param.isPrimitiveType && !param.isListContainer && !param.isMapContainer)) { + Set mimeTypes = modelMimeTypes.containsKey(param.dataType) ? modelMimeTypes.get(param.dataType) : new HashSet(); + mimeTypes.add(mimeType); + modelMimeTypes.put(param.dataType, mimeTypes); + } + } + } + + public String firstLetterToUpper(String word) { + if (word.length() == 0) { + return word; + } else if (word.length() == 1) { + return word.substring(0, 1).toUpperCase(); + } else { + return word.substring(0, 1).toUpperCase() + word.substring(1); + } + } + + public String firstLetterToLower(String word) { + if (word.length() == 0) { + return word; + } else if (word.length() == 1) { + return word.substring(0, 1).toLowerCase(); + } else { + return word.substring(0, 1).toLowerCase() + word.substring(1); + } + } + + private String mapCollectionFormat(String collectionFormat) { + switch (collectionFormat) { + case "csv": + return "CommaSeparated"; + case "tsv": + return "TabSeparated"; + case "ssv": + return "SpaceSeparated"; + case "pipes": + return "PipeSeparated"; + case "multi": + return "MultiParamArray"; + default: + throw new UnsupportedOperationException(); + } + } + + private String getMimeDataType(String mimeType) { + if (StringUtils.isBlank(mimeType)) { + return "MimeNoContent"; + } + if (knownMimeDataTypes.containsKey(mimeType)) { + return knownMimeDataTypes.get(mimeType); + } + String shortenedName = mimeType.replaceFirst("application/",""); + return "Mime" + toHsTypeName(shortenedName); + } + + private String toHsVarName(String paramName) { + return toVarName(camelize(fixOperatorChars(fixModelChars(paramName)), true)); + } + + private String toHsTypeName(String paramName) { + return toHsTypeName(paramName, ""); + } + + private String toHsTypeName(String paramName, String modelCharReplacement) { + return camelize(fixOperatorChars(fixModelChars(paramName, modelCharReplacement)), false); + } + + private String fixOperatorChars(String string) { + if(string == null) return null; + StringBuilder sb = new StringBuilder(); + String name = string; + //Check if it is a reserved word, in which case the underscore is added when property name is generated. + if (string.startsWith("_")) { + if (reservedWords.contains(string.substring(1, string.length()))) { + name = string.substring(1, string.length()); + } else if (reservedWordsMappings.containsValue(string)) { + name = LEADING_UNDERSCORE.matcher(string).replaceFirst(""); + } + } + // prepend ' + for (char c : name.toCharArray()) { + String cString = String.valueOf(c); + if (specialCharReplacements.containsKey(cString)) { +// sb.append("'"); + sb.append(specialCharReplacements.get(cString)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + // Remove characters from a string that do not belong in a model classname + private String fixModelChars(String string, String replacement) { + if(string == null) return null; + return string.replace(".", replacement).replace("-", replacement); + } + + private String fixModelChars(String string) { + return fixModelChars(string, ""); + } + + private String capitalize(String word) { + if(word == null) return null; + if (word.length() > 0) { + word = word.substring(0, 1).toUpperCase() + word.substring(1); + } + + return word; + } + private static String generateNextName(String name) { + Pattern pattern = Pattern.compile("\\d+\\z"); + Matcher matcher = pattern.matcher(name); + if (matcher.find()) { + String numStr = matcher.group(); + int num = Integer.parseInt(numStr) + 1; + return name.substring(0, name.length() - numStr.length()) + num; + } else { + return name + "2"; + } + } + private static boolean isMultipart(List> consumes) { + for(Map consume : consumes) { + if (consume != null) { + if ("multipart/form-data".equals(consume.get(MEDIA_TYPE))) { + return true; + } + } + } + return false; + } + +// private boolean isModelledType(CodegenParameter param) { +// return isModelledType(param.baseType == null ? param.dataType : param.baseType); +// } +// +// private boolean isModelledType(String typeName) { +// return !languageSpecificPrimitives.contains(typeName) && !typeMapping.values().contains(typeName); +// } +} diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig index fc1593b463d..c8438e09a30 100644 --- a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -20,6 +20,7 @@ io.swagger.codegen.languages.FlaskConnexionCodegen io.swagger.codegen.languages.GoClientCodegen io.swagger.codegen.languages.GoServerCodegen io.swagger.codegen.languages.GroovyClientCodegen +io.swagger.codegen.languages.HaskellHttpClientCodegen io.swagger.codegen.languages.HaskellServantCodegen io.swagger.codegen.languages.JMeterCodegen io.swagger.codegen.languages.JavaCXFClientCodegen diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/.gitignore b/modules/swagger-codegen/src/main/resources/haskell-http-client/.gitignore new file mode 100644 index 00000000000..aaed8f870ea --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/.gitignore @@ -0,0 +1,8 @@ +.stack-work +src/highlight.js +src/style.css +dist +dist-newstyle +cabal.project.local +.cabal-sandbox +cabal.sandbox.config \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/.travis.yml b/modules/swagger-codegen/src/main/resources/haskell-http-client/.travis.yml new file mode 100644 index 00000000000..a90f612b74d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/.travis.yml @@ -0,0 +1,16 @@ +sudo: false +language: c +addons: + apt: + packages: + - libgmp-dev +before_install: +- mkdir -p ~/.local/bin +- export PATH=$HOME/.local/bin:$PATH +- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' +script: +- stack --install-ghc --no-haddock-deps haddock +- stack test +cache: + directories: + - $HOME/.stack diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/API.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/API.mustache new file mode 100644 index 00000000000..7b9745acb06 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/API.mustache @@ -0,0 +1,298 @@ +{-| +Module : {{title}}.API +-} + +{-# LANGUAGE RecordWildCards #-} + +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE InstanceSigs #-} +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module {{title}}.API where + + +import {{title}}.Model as M +import {{title}}.MimeTypes + +import qualified Data.Aeson as A +import Data.Aeson (Value) + +import qualified Data.Time as TI +import Data.Time (UTCTime) + +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import Data.ByteString.Lazy (ByteString) +import qualified Data.ByteString.Builder as BB +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy.Char8 as BCL + +import qualified Network.HTTP.Client.MultipartFormData as NH +import qualified Network.HTTP.Media as ME +import qualified Network.HTTP.Types as NH + +import qualified Web.HttpApiData as WH +import qualified Web.FormUrlEncoded as WH + +import qualified Data.CaseInsensitive as CI +import qualified Data.Data as P (Typeable) +import qualified Data.Foldable as P +import qualified Data.Map as Map +import qualified Data.Maybe as P +import qualified Data.Proxy as P (Proxy(..)) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Text.Lazy as TL +import qualified Data.Text.Lazy.Encoding as TL +import qualified GHC.Base as P (Alternative) +import qualified Control.Arrow as P (left) + +import Data.Monoid ((<>)) +import Data.Function ((&)) +import Data.Set (Set) +import Data.Text (Text) +import GHC.Base ((<|>)) + +import Prelude ((==),(/=),($), (.),(<$>),(<*>),(>>=),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor) +import qualified Prelude as P + +-- * Operations +{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}{{#vendorExtensions.x-hasNewTag}} + +-- ** {{baseName}}{{/vendorExtensions.x-hasNewTag}} + +-- *** {{operationId}} + +-- | @{{{vendorExtensions.x-haddockPath}}}@ +-- {{#summary}} +-- {{{.}}} +-- {{/summary}}{{#notes}} +-- {{{.}}} +-- {{/notes}}{{#hasAuthMethods}} +-- AuthMethod: {{#authMethods}}{{{name}}}{{#hasMore}}, {{/hasMore}}{{/authMethods}} +-- {{/hasAuthMethods}}{{#vendorExtensions.x-hasUnknownReturn}} +-- Note: Has 'Produces' instances, but no response schema +-- {{/vendorExtensions.x-hasUnknownReturn}} +{{operationId}} + :: {{#vendorExtensions.x-hasBodyOrFormParam}}(Consumes {{{vendorExtensions.x-operationType}}} contentType{{#allParams}}{{#isBodyParam}}{{#required}}, MimeRender contentType {{dataType}}{{/required}}{{/isBodyParam}}{{/allParams}}) + => contentType -- ^ request content-type ('MimeType') + -> {{/vendorExtensions.x-hasBodyOrFormParam}}{{#allParams}}{{#required}}{{dataType}} -- ^ "{{{paramName}}}"{{#description}} - {{/description}} {{{description}}} + -> {{/required}}{{/allParams}}{{requestType}} {{{vendorExtensions.x-operationType}}} {{#vendorExtensions.x-hasBodyOrFormParam}}contentType{{/vendorExtensions.x-hasBodyOrFormParam}}{{^vendorExtensions.x-hasBodyOrFormParam}}MimeNoContent{{/vendorExtensions.x-hasBodyOrFormParam}} {{vendorExtensions.x-returnType}} +{{operationId}} {{#vendorExtensions.x-hasBodyOrFormParam}}_ {{/vendorExtensions.x-hasBodyOrFormParam}}{{#allParams}}{{#required}}{{{paramName}}} {{/required}}{{/allParams}}= + _mkRequest "{{httpMethod}}" [{{#pathParams}}{{#vendorExtensions.x-pathPrefix}}"{{.}}",{{/vendorExtensions.x-pathPrefix}}toPath {{{paramName}}}{{#hasMore}},{{/hasMore}}{{/pathParams}}{{#vendorExtensions.x-pathSuffix}}{{#vendorExtensions.x-hasPathParams}},{{/vendorExtensions.x-hasPathParams}}"{{.}}"{{/vendorExtensions.x-pathSuffix}}]{{#allParams}}{{#required}} + {{#isHeaderParam}}`setHeader` {{>_headerColl}} ("{{{baseName}}}", {{{paramName}}}){{/isHeaderParam}}{{#isQueryParam}}`_setQuery` {{>_queryColl}} ("{{{baseName}}}", Just {{{paramName}}}){{/isQueryParam}}{{#isFormParam}}{{#isFile}}`_addMultiFormPart` NH.partFileSource "{{{baseName}}}" {{{paramName}}}{{/isFile}}{{^isFile}}{{#isMultipart}}`_addMultiFormPart` NH.partLBS "{{{baseName}}}" (mimeRender' MimeMultipartFormData {{{paramName}}}){{/isMultipart}}{{^isMultipart}}`_addForm` {{>_formColl}} ("{{{baseName}}}", {{{paramName}}}){{/isMultipart}}{{/isFile}}{{/isFormParam}}{{#isBodyParam}}`setBodyParam` {{{paramName}}}{{/isBodyParam}}{{/required}}{{/allParams}}{{#isDeprecated}} + +{-# DEPRECATED {{operationId}} "" #-}{{/isDeprecated}} + +data {{{vendorExtensions.x-operationType}}} {{#allParams}}{{#isBodyParam}}{{#description}} + +-- | /Body Param/ "{{{baseName}}}" - {{{description}}}{{/description}} +instance HasBodyParam {{{vendorExtensions.x-operationType}}} {{{dataType}}}{{/isBodyParam}}{{/allParams}} {{#vendorExtensions.x-hasOptionalParams}}{{#allParams}}{{^isBodyParam}}{{^required}}{{#description}} + +-- | /Optional Param/ "{{{baseName}}}" - {{{description}}}{{/description}} +instance HasOptionalParam {{{vendorExtensions.x-operationType}}} {{{vendorExtensions.x-paramNameType}}} where + applyOptionalParam req ({{{vendorExtensions.x-paramNameType}}} xs) = + {{#isHeaderParam}}req `setHeader` {{>_headerColl}} ("{{{baseName}}}", xs){{/isHeaderParam}}{{#isQueryParam}}req `_setQuery` {{>_queryColl}} ("{{{baseName}}}", Just xs){{/isQueryParam}}{{#isFormParam}}{{#isFile}}req `_addMultiFormPart` NH.partFileSource "{{{baseName}}}" xs{{/isFile}}{{^isFile}}{{#isMultipart}}req `_addMultiFormPart` NH.partLBS "{{{baseName}}}" (mimeRender' MimeMultipartFormData xs){{/isMultipart}}{{^isMultipart}}req `_addForm` {{>_formColl}} ("{{{baseName}}}", xs){{/isMultipart}}{{/isFile}}{{/isFormParam}}{{/required}}{{/isBodyParam}}{{/allParams}}{{/vendorExtensions.x-hasOptionalParams}}{{#hasConsumes}} + +{{#consumes}}-- | @{{{mediaType}}}@ +instance Consumes {{{vendorExtensions.x-operationType}}} {{{x-mediaDataType}}} +{{/consumes}}{{/hasConsumes}}{{#hasProduces}} +{{#produces}}-- | @{{{mediaType}}}@ +instance Produces {{{vendorExtensions.x-operationType}}} {{{x-mediaDataType}}} +{{/produces}}{{/hasProduces}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} + + +-- * HasBodyParam + +-- | Designates the body parameter of a request +class HasBodyParam req param where + setBodyParam :: forall contentType res. (Consumes req contentType, MimeRender contentType param) => {{requestType}} req contentType res -> param -> {{requestType}} req contentType res + setBodyParam req xs = + req `_setBodyLBS` mimeRender (P.Proxy :: P.Proxy contentType) xs & _setContentTypeHeader + +-- * HasOptionalParam + +-- | Designates the optional parameters of a request +class HasOptionalParam req param where + {-# MINIMAL applyOptionalParam | (-&-) #-} + + -- | Apply an optional parameter to a request + applyOptionalParam :: {{requestType}} req contentType res -> param -> {{requestType}} req contentType res + applyOptionalParam = (-&-) + {-# INLINE applyOptionalParam #-} + + -- | infix operator \/ alias for 'addOptionalParam' + (-&-) :: {{requestType}} req contentType res -> param -> {{requestType}} req contentType res + (-&-) = applyOptionalParam + {-# INLINE (-&-) #-} + +infixl 2 -&- + +-- * Optional Request Parameter Types + +{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}{{#vendorExtensions.x-hasOptionalParams}}{{#allParams}}{{^required}}{{^vendorExtensions.x-duplicate}} +newtype {{{vendorExtensions.x-paramNameType}}} = {{{vendorExtensions.x-paramNameType}}} { un{{{vendorExtensions.x-paramNameType}}} :: {{{dataType}}} } deriving (P.Eq, P.Show) +{{/vendorExtensions.x-duplicate}}{{/required}}{{/allParams}}{{/vendorExtensions.x-hasOptionalParams}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} + +-- * {{requestType}} + +-- | Represents a request. The "req" type variable is the request type. The "res" type variable is the response type. +data {{requestType}} req contentType res = {{requestType}} + { rMethod :: NH.Method -- ^ Method of {{requestType}} + , urlPath :: [BCL.ByteString] -- ^ Endpoint of {{requestType}} + , params :: Params -- ^ params of {{requestType}} + } + deriving (P.Show) + +-- | Request Params +data Params = Params + { paramsQuery :: NH.Query + , paramsHeaders :: NH.RequestHeaders + , paramsBody :: ParamBody + } + deriving (P.Show) + +-- | Request Body +data ParamBody + = ParamBodyNone + | ParamBodyB B.ByteString + | ParamBodyBL BL.ByteString + | ParamBodyFormUrlEncoded WH.Form + | ParamBodyMultipartFormData [NH.Part] + deriving (P.Show) + +-- ** {{requestType}} Utils + +_mkRequest :: NH.Method -- ^ Method + -> [BCL.ByteString] -- ^ Endpoint + -> {{requestType}} req contentType res -- ^ req: Request Type, res: Response Type +_mkRequest m u = {{requestType}} m u _mkParams + +_mkParams :: Params +_mkParams = Params [] [] ParamBodyNone + +setHeader :: {{requestType}} req contentType res -> [NH.Header] -> {{requestType}} req contentType res +setHeader req header = + let _params = params (req `removeHeader` P.fmap P.fst header) + in req { params = _params { paramsHeaders = header P.++ paramsHeaders _params } } + +removeHeader :: {{requestType}} req contentType res -> [NH.HeaderName] -> {{requestType}} req contentType res +removeHeader req header = + let _params = params req + in req { params = _params { paramsHeaders = [h | h <- paramsHeaders _params, cifst h `P.notElem` P.fmap CI.mk header] } } + where cifst = CI.mk . P.fst + + +_setContentTypeHeader :: forall req contentType res. MimeType contentType => {{requestType}} req contentType res -> {{requestType}} req contentType res +_setContentTypeHeader req = + case mimeType (P.Proxy :: P.Proxy contentType) of + Just m -> req `setHeader` [("content-type", BC.pack $ P.show m)] + Nothing -> req `removeHeader` ["content-type"] + +_setAcceptHeader :: forall req contentType res accept. MimeType accept => {{requestType}} req contentType res -> accept -> {{requestType}} req contentType res +_setAcceptHeader req accept = + case mimeType' accept of + Just m -> req `setHeader` [("accept", BC.pack $ P.show m)] + Nothing -> req `removeHeader` ["accept"] + +_setQuery :: {{requestType}} req contentType res -> [NH.QueryItem] -> {{requestType}} req contentType res +_setQuery req query = + let _params = params req + in req { params = _params { paramsQuery = query P.++ [q | q <- paramsQuery _params, cifst q `P.notElem` P.fmap cifst query] } } + where cifst = CI.mk . P.fst + +_addForm :: {{requestType}} req contentType res -> WH.Form -> {{requestType}} req contentType res +_addForm req newform = + let _params = params req + form = case paramsBody _params of + ParamBodyFormUrlEncoded _form -> _form + _ -> mempty + in req { params = _params { paramsBody = ParamBodyFormUrlEncoded (newform <> form) } } + +_addMultiFormPart :: {{requestType}} req contentType res -> NH.Part -> {{requestType}} req contentType res +_addMultiFormPart req newpart = + let _params = params req + parts = case paramsBody _params of + ParamBodyMultipartFormData _parts -> _parts + _ -> [] + in req { params = _params { paramsBody = ParamBodyMultipartFormData (newpart : parts) } } + +_setBodyBS :: {{requestType}} req contentType res -> B.ByteString -> {{requestType}} req contentType res +_setBodyBS req body = + let _params = params req + in req { params = _params { paramsBody = ParamBodyB body } } + +_setBodyLBS :: {{requestType}} req contentType res -> BL.ByteString -> {{requestType}} req contentType res +_setBodyLBS req body = + let _params = params req + in req { params = _params { paramsBody = ParamBodyBL body } } + + +-- ** Params Utils + +toPath + :: WH.ToHttpApiData a + => a -> BCL.ByteString +toPath = BB.toLazyByteString . WH.toEncodedUrlPiece + +toHeader :: WH.ToHttpApiData a => (NH.HeaderName, a) -> [NH.Header] +toHeader x = [fmap WH.toHeader x] + +toForm :: WH.ToHttpApiData v => (BC.ByteString, v) -> WH.Form +toForm (k,v) = WH.toForm [(BC.unpack k,v)] + +toQuery :: WH.ToHttpApiData a => (BC.ByteString, Maybe a) -> [NH.QueryItem] +toQuery x = [(fmap . fmap) toQueryParam x] + where toQueryParam = T.encodeUtf8 . WH.toQueryParam + +-- *** Swagger `CollectionFormat` Utils + +-- | Determines the format of the array if type array is used. +data CollectionFormat + = CommaSeparated -- ^ CSV format for multiple parameters. + | SpaceSeparated -- ^ Also called "SSV" + | TabSeparated -- ^ Also called "TSV" + | PipeSeparated -- ^ `value1|value2|value2` + | MultiParamArray -- ^ Using multiple GET parameters, e.g. `foo=bar&foo=baz`. This is valid only for parameters in "query" ('NH.Query') or "formData" ('WH.Form') + +toHeaderColl :: WH.ToHttpApiData a => CollectionFormat -> (NH.HeaderName, [a]) -> [NH.Header] +toHeaderColl c xs = _toColl c toHeader xs + +toFormColl :: WH.ToHttpApiData v => CollectionFormat -> (BC.ByteString, [v]) -> WH.Form +toFormColl c xs = WH.toForm $ fmap unpack $ _toColl c toHeader $ pack xs + where + pack (k,v) = (CI.mk k, v) + unpack (k,v) = (BC.unpack (CI.original k), BC.unpack v) + +toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query +toQueryColl c xs = _toCollA c toQuery xs + +_toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)] +_toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs)) + where fencode = fmap (fmap Just) . encode . fmap P.fromJust + {-# INLINE fencode #-} + +_toCollA :: (P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t BC.ByteString)]) -> f (t [a]) -> [(b, t BC.ByteString)] +_toCollA c encode xs = _toCollA' c encode BC.singleton xs + +_toCollA' :: (P.Monoid c, P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t c)]) -> (Char -> c) -> f (t [a]) -> [(b, t c)] +_toCollA' c encode one xs = case c of + CommaSeparated -> go (one ',') + SpaceSeparated -> go (one ' ') + TabSeparated -> go (one '\t') + PipeSeparated -> go (one '|') + MultiParamArray -> expandList + where + go sep = + [P.foldl1 (\(sk, sv) (_, v) -> (sk, (combine sep <$> sv <*> v) <|> sv <|> v)) expandList] + combine sep x y = x <> sep <> y + expandList = (P.concatMap encode . (P.traverse . P.traverse) P.toList) xs + {-# INLINE go #-} + {-# INLINE expandList #-} + {-# INLINE combine #-} + diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/Client.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/Client.mustache new file mode 100644 index 00000000000..d044001284e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/Client.mustache @@ -0,0 +1,317 @@ +{-| +Module : {{title}}.Client +-} + +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveTraversable #-} +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module {{title}}.Client where + +import {{title}}.Model +import {{title}}.API +import {{title}}.MimeTypes + +import qualified Control.Monad.IO.Class as P +import qualified Data.Aeson as A +import qualified Data.Aeson.Types as A +import qualified Data.Proxy as P (Proxy(..)) +import Data.Function ((&)) +import Data.Monoid ((<>)) +import Data.Text (Text) +import GHC.Exts (IsString(..)) +import Web.FormUrlEncoded as WH +import Web.HttpApiData as WH +import Control.Monad.Catch (MonadThrow) + +import qualified Control.Monad.Logger as LG + +import qualified Data.Time as TI +import qualified Data.Map as Map +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Text.Printf as T + +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy.Char8 as BCL +import qualified Data.ByteString.Builder as BB +import qualified Network.HTTP.Client as NH +import qualified Network.HTTP.Client.TLS as NH +import qualified Network.HTTP.Client.MultipartFormData as NH +import qualified Network.HTTP.Types.Method as NH +import qualified Network.HTTP.Types as NH +import qualified Network.HTTP.Types.URI as NH + +import qualified Control.Exception.Safe as E +-- * Config + +-- | +data {{configType}} = {{configType}} + { configHost :: BCL.ByteString -- ^ host supplied in the Request + , configUserAgent :: Text -- ^ user-agent supplied in the Request + , configExecLoggingT :: ExecLoggingT -- ^ Run a block using a MonadLogger instance + , configLoggingFilter :: LG.LogSource -> LG.LogLevel -> Bool -- ^ Only log messages passing the given predicate function. + } + +-- | display the config +instance Show {{configType}} where + show c = + T.printf + "{ configHost = %v, configUserAgent = %v, ..}" + (show (configHost c)) + (show (configUserAgent c)) + +-- | constructs a default {{configType}} +-- +-- configHost: +-- +-- @{{basePath}}@ +-- +-- configUserAgent: +-- +-- @"{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}{{{artifactId}}}/{{{artifactVersion}}}{{/httpUserAgent}}"@ +-- +-- configExecLoggingT: 'runNullLoggingT' +-- +-- configLoggingFilter: 'infoLevelFilter' +newConfig :: {{configType}} +newConfig = + {{configType}} + { configHost = "{{basePath}}" + , configUserAgent = "{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}{{{artifactId}}}/{{{artifactVersion}}}{{/httpUserAgent}}" + , configExecLoggingT = runNullLoggingT + , configLoggingFilter = infoLevelFilter + } + +-- | updates the config to use a MonadLogger instance which prints to stdout. +withStdoutLogging :: {{configType}} -> {{configType}} +withStdoutLogging p = p { configExecLoggingT = LG.runStdoutLoggingT} + +-- | updates the config to use a MonadLogger instance which prints to stderr. +withStderrLogging :: {{configType}} -> {{configType}} +withStderrLogging p = p { configExecLoggingT = LG.runStderrLoggingT} + +-- | updates the config to disable logging +withNoLogging :: {{configType}} -> {{configType}} +withNoLogging p = p { configExecLoggingT = runNullLoggingT} + +-- * Dispatch + +-- ** Lbs + +-- | send a request returning the raw http response +dispatchLbs + :: (Produces req accept, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> {{configType}} -- ^ config + -> {{requestType}} req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchLbs manager config request accept = do + initReq <- _toInitRequest config request accept + dispatchInitUnsafe manager config initReq + +-- ** Mime + +-- | pair of decoded http body and http response +data MimeResult res = + MimeResult { mimeResult :: Either MimeError res -- ^ decoded http body + , mimeResultResponse :: NH.Response BCL.ByteString -- ^ http response + } + deriving (Show, Functor, Foldable, Traversable) + +-- | pair of unrender/parser error and http response +data MimeError = + MimeError { + mimeError :: String -- ^ unrender/parser error + , mimeErrorResponse :: NH.Response BCL.ByteString -- ^ http response + } deriving (Eq, Show) + +-- | send a request returning the 'MimeResult' +dispatchMime + :: (Produces req accept, MimeUnrender accept res, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> {{configType}} -- ^ config + -> {{requestType}} req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (MimeResult res) -- ^ response +dispatchMime manager config request accept = do + httpResponse <- dispatchLbs manager config request accept + parsedResult <- + runExceptionLoggingT "Client" config $ + do case mimeUnrender' accept (NH.responseBody httpResponse) of + Left s -> do + logNST LG.LevelError "Client" (T.pack s) + pure (Left (MimeError s httpResponse)) + Right r -> pure (Right r) + return (MimeResult parsedResult httpResponse) + +-- | like 'dispatchMime', but only returns the decoded http body +dispatchMime' + :: (Produces req accept, MimeUnrender accept res, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> {{configType}} -- ^ config + -> {{requestType}} req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (Either MimeError res) -- ^ response +dispatchMime' manager config request accept = do + MimeResult parsedResult _ <- dispatchMime manager config request accept + return parsedResult + +-- ** Unsafe + +-- | like 'dispatchReqLbs', but does not validate the operation is a 'Producer' of the "accept" 'MimeType'. (Useful if the server's response is undocumented) +dispatchLbsUnsafe + :: (MimeType accept, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> {{configType}} -- ^ config + -> {{requestType}} req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchLbsUnsafe manager config request accept = do + initReq <- _toInitRequest config request accept + dispatchInitUnsafe manager config initReq + +-- | dispatch an InitRequest +dispatchInitUnsafe + :: NH.Manager -- ^ http-client Connection manager + -> {{configType}} -- ^ config + -> InitRequest req contentType res accept -- ^ init request + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchInitUnsafe manager config (InitRequest req) = do + runExceptionLoggingT logSrc config $ + do logNST LG.LevelInfo logSrc requestLogMsg + logNST LG.LevelDebug logSrc requestDbgLogMsg + res <- P.liftIO $ NH.httpLbs req manager + logNST LG.LevelInfo logSrc (responseLogMsg res) + logNST LG.LevelDebug logSrc ((T.pack . show) res) + return res + where + logSrc = "Client" + endpoint = + T.pack $ + BC.unpack $ + NH.method req <> " " <> NH.host req <> NH.path req <> NH.queryString req + requestLogMsg = "REQ:" <> endpoint + requestDbgLogMsg = + "Headers=" <> (T.pack . show) (NH.requestHeaders req) <> " Body=" <> + (case NH.requestBody req of + NH.RequestBodyLBS xs -> T.decodeUtf8 (BL.toStrict xs) + _ -> "") + responseStatusCode = (T.pack . show) . NH.statusCode . NH.responseStatus + responseLogMsg res = + "RES:statusCode=" <> responseStatusCode res <> " (" <> endpoint <> ")" + +-- * InitRequest + +-- | wraps an http-client 'Request' with request/response type parameters +newtype InitRequest req contentType res accept = InitRequest + { unInitRequest :: NH.Request + } deriving (Show) + +-- | Build an http-client 'Request' record from the supplied config and request +_toInitRequest + :: (MimeType accept, MimeType contentType) + => {{configType}} -- ^ config + -> {{requestType}} req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (InitRequest req contentType res accept) -- ^ initialized request +_toInitRequest config req0 accept = do + parsedReq <- NH.parseRequest $ BCL.unpack $ BCL.append (configHost config) (BCL.concat (urlPath req0)) + let req1 = _setAcceptHeader req0 accept & _setContentTypeHeader + reqHeaders = ("User-Agent", WH.toHeader (configUserAgent config)) : paramsHeaders (params req1) + reqQuery = NH.renderQuery True (paramsQuery (params req1)) + pReq = parsedReq { NH.method = (rMethod req1) + , NH.requestHeaders = reqHeaders + , NH.queryString = reqQuery + } + outReq <- case paramsBody (params req1) of + ParamBodyNone -> pure (pReq { NH.requestBody = mempty }) + ParamBodyB bs -> pure (pReq { NH.requestBody = NH.RequestBodyBS bs }) + ParamBodyBL bl -> pure (pReq { NH.requestBody = NH.RequestBodyLBS bl }) + ParamBodyFormUrlEncoded form -> pure (pReq { NH.requestBody = NH.RequestBodyLBS (WH.urlEncodeForm form) }) + ParamBodyMultipartFormData parts -> NH.formDataBody parts pReq + + pure (InitRequest outReq) + +-- | modify the underlying Request +modifyInitRequest :: InitRequest req contentType res accept -> (NH.Request -> NH.Request) -> InitRequest req contentType res accept +modifyInitRequest (InitRequest req) f = InitRequest (f req) + +-- | modify the underlying Request (monadic) +modifyInitRequestM :: Monad m => InitRequest req contentType res accept -> (NH.Request -> m NH.Request) -> m (InitRequest req contentType res accept) +modifyInitRequestM (InitRequest req) f = fmap InitRequest (f req) + +-- * Logging + +-- | A block using a MonadLogger instance +type ExecLoggingT = forall m. P.MonadIO m => + forall a. LG.LoggingT m a -> m a + +-- ** Null Logger + +-- | a logger which disables logging +nullLogger :: LG.Loc -> LG.LogSource -> LG.LogLevel -> LG.LogStr -> IO () +nullLogger _ _ _ _ = return () + +-- | run the monad transformer that disables logging +runNullLoggingT :: LG.LoggingT m a -> m a +runNullLoggingT = (`LG.runLoggingT` nullLogger) + +-- ** Logging Filters + +-- | a log filter that uses 'LevelError' as the minimum logging level +errorLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool +errorLevelFilter = minLevelFilter LG.LevelError + +-- | a log filter that uses 'LevelInfo' as the minimum logging level +infoLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool +infoLevelFilter = minLevelFilter LG.LevelInfo + +-- | a log filter that uses 'LevelDebug' as the minimum logging level +debugLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool +debugLevelFilter = minLevelFilter LG.LevelDebug + +minLevelFilter :: LG.LogLevel -> LG.LogSource -> LG.LogLevel -> Bool +minLevelFilter l _ l' = l' >= l + +-- ** Logging + +-- | Log a message using the current time +logNST :: (P.MonadIO m, LG.MonadLogger m) => LG.LogLevel -> Text -> Text -> m () +logNST level src msg = do + now <- P.liftIO (formatTimeLog <$> TI.getCurrentTime) + LG.logOtherNS sourceLog level (now <> " " <> msg) + where + sourceLog = "{{title}}/" <> src + formatTimeLog = + T.pack . TI.formatTime TI.defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Z" + +-- | re-throws exceptions after logging them +logExceptions + :: (LG.MonadLogger m, E.MonadCatch m, P.MonadIO m) + => Text -> m a -> m a +logExceptions src = + E.handle + (\(e :: E.SomeException) -> do + logNST LG.LevelError src ((T.pack . show) e) + E.throw e) + +-- | Run a block using the configured MonadLogger instance +runLoggingT :: {{configType}} -> ExecLoggingT +runLoggingT config = + configExecLoggingT config . LG.filterLogger (configLoggingFilter config) + +-- | Run a block using the configured MonadLogger instance (logs exceptions) +runExceptionLoggingT + :: (E.MonadCatch m, P.MonadIO m) + => T.Text -> {{configType}} -> LG.LoggingT m a -> m a +runExceptionLoggingT logSrc config = runLoggingT config . logExceptions logSrc diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/Lens.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/Lens.mustache new file mode 100644 index 00000000000..4df5c4a8cdd --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/Lens.mustache @@ -0,0 +1,66 @@ +{-| +Module : {{title}}.Lens +-} + +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} +{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module {{title}}.Lens where + +import Data.Text (Text) + +import qualified Data.Aeson as A +import Data.Aeson (Value) +import qualified Data.ByteString as B +import Data.ByteString.Lazy (ByteString) +import qualified Data.Data as P (Data, Typeable) +import qualified Data.Map as Map + +import qualified Data.Time as TI +import Data.Time (UTCTime) + +import Prelude (($), (.),(<$>),(<*>),(=<<),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor) +import qualified Prelude as P + +import {{title}}.Model + +-- * Type Aliases + +type Traversal_' s a = Traversal_ s s a a +type Traversal_ s t a b = forall (f :: * -> *). Applicative f => (a -> f b) -> s -> f t +type Lens_' s a = Lens_ s s a a +type Lens_ s t a b = forall (f :: * -> *). Functor f => (a -> f b) -> s -> f t + +{{#models}} +{{#model}} + +-- * {{classname}} + +{{#vars}} +{{#required}} +-- | '{{name}}' Lens +{{name}}L :: Lens_' {{classname}} {{datatype}} +{{name}}L f {{classname}}{..} = (\{{name}} -> {{classname}} { {{name}}, ..} ) <$> f {{name}} +{-# INLINE {{name}}L #-} +{{/required}} +{{^required}} +-- | '{{name}}' Traversal +{{name}}T :: Traversal_' {{classname}} {{datatype}} +{{name}}T f s = _mtraversal {{name}} (\b -> s { {{name}} = Just b}) f s +{-# INLINE {{name}}T #-} +{{/required}} + +{{/vars}} + +{{/model}} +{{/models}} + + +-- * Helpers + +_mtraversal :: Applicative f => (b -> Maybe t) -> (a -> b) -> (t -> f a) -> b -> f b +_mtraversal x fsb f s = maybe (pure s) (\a -> fsb <$> f a) (x s) +{-# INLINE _mtraversal #-} diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/MimeTypes.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/MimeTypes.mustache new file mode 100644 index 00000000000..43e969d82d4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/MimeTypes.mustache @@ -0,0 +1,204 @@ + +{-| +Module : {{title}}.MimeTypes +-} + +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module {{title}}.MimeTypes where + + +import qualified Data.Aeson as A + +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Builder as BB +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy.Char8 as BCL + +import qualified Network.HTTP.Media as ME + +import qualified Web.FormUrlEncoded as WH + +import qualified Data.Data as P (Typeable) +import qualified Data.Proxy as P (Proxy(..)) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Control.Arrow as P (left) + +import Prelude (($), (.),(<$>),(<*>),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty) +import qualified Prelude as P + +-- * Content Negotiation + +-- | A type for responses without content-body. +data NoContent = NoContent + deriving (P.Show, P.Eq) + +-- ** Mime Types + +data MimeJSON = MimeJSON deriving (P.Typeable) +data MimeXML = MimeXML deriving (P.Typeable) +data MimePlainText = MimePlainText deriving (P.Typeable) +data MimeFormUrlEncoded = MimeFormUrlEncoded deriving (P.Typeable) +data MimeMultipartFormData = MimeMultipartFormData deriving (P.Typeable) +data MimeOctetStream = MimeOctetStream deriving (P.Typeable) +data MimeNoContent = MimeNoContent deriving (P.Typeable) + +{{#x-unknownMimeTypes}}data {{{x-mediaDataType}}} = {{{x-mediaDataType}}} deriving (P.Typeable) +{{/x-unknownMimeTypes}} + +-- ** MimeType Class + +class P.Typeable mtype => MimeType mtype where + {-# MINIMAL mimeType | mimeTypes #-} + + mimeTypes :: P.Proxy mtype -> [ME.MediaType] + mimeTypes p = + case mimeType p of + Just x -> [x] + Nothing -> [] + + mimeType :: P.Proxy mtype -> Maybe ME.MediaType + mimeType p = + case mimeTypes p of + [] -> Nothing + (x:_) -> Just x + + mimeType' :: mtype -> Maybe ME.MediaType + mimeType' _ = mimeType (P.Proxy :: P.Proxy mtype) + mimeTypes' :: mtype -> [ME.MediaType] + mimeTypes' _ = mimeTypes (P.Proxy :: P.Proxy mtype) + +-- ** MimeType Instances + +-- | @application/json@ +instance MimeType MimeJSON where + mimeTypes _ = + [ "application" ME.// "json" ME./: ("charset", "utf-8") + , "application" ME.// "json" + ] + +-- | @application/xml@ +instance MimeType MimeXML where + mimeType _ = Just $ "application" ME.// "xml" + +-- | @application/x-www-form-urlencoded@ +instance MimeType MimeFormUrlEncoded where + mimeType _ = Just $ "application" ME.// "x-www-form-urlencoded" + +-- | @multipart/form-data@ +instance MimeType MimeMultipartFormData where + mimeType _ = Just $ "multipart" ME.// "form-data" + +-- | @text/plain;charset=utf-8@ +instance MimeType MimePlainText where + mimeType _ = Just $ "text" ME.// "plain" ME./: ("charset", "utf-8") +instance MimeType MimeOctetStream where + mimeType _ = Just $ "application" ME.// "octet-stream" +instance MimeType MimeNoContent where + mimeType _ = Nothing + +{{#x-unknownMimeTypes}} +-- | @{{{mediaType}}}@ +instance MimeType {{{x-mediaDataType}}} where + mimeType _ = Just $ "{{{x-mediaMainType}}}" ME.// "{{{x-mediaSubType}}}" + +{{/x-unknownMimeTypes}} + +-- ** MimeRender Class + +class MimeType mtype => MimeRender mtype x where + mimeRender :: P.Proxy mtype -> x -> BL.ByteString + mimeRender' :: mtype -> x -> BL.ByteString + mimeRender' _ x = mimeRender (P.Proxy :: P.Proxy mtype) x + + +-- ** MimeRender Instances + +-- | `A.encode` +instance A.ToJSON a => MimeRender MimeJSON a where mimeRender _ = A.encode +-- | @WH.urlEncodeAsForm@ +instance WH.ToForm a => MimeRender MimeFormUrlEncoded a where mimeRender _ = WH.urlEncodeAsForm + +-- | @P.id@ +instance MimeRender MimePlainText BL.ByteString where mimeRender _ = P.id +-- | @BL.fromStrict . T.encodeUtf8@ +instance MimeRender MimePlainText T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8 +-- | @BCL.pack@ +instance MimeRender MimePlainText String where mimeRender _ = BCL.pack + +-- | @P.id@ +instance MimeRender MimeOctetStream BL.ByteString where mimeRender _ = P.id +-- | @BL.fromStrict . T.encodeUtf8@ +instance MimeRender MimeOctetStream T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8 +-- | @BCL.pack@ +instance MimeRender MimeOctetStream String where mimeRender _ = BCL.pack + +-- | @P.id@ +instance MimeRender MimeMultipartFormData BL.ByteString where mimeRender _ = P.id +-- | @BL.fromStrict . T.encodeUtf8@ +instance MimeRender MimeMultipartFormData T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8 +-- | @BCL.pack@ +instance MimeRender MimeMultipartFormData String where mimeRender _ = BCL.pack + +-- | @P.Right . P.const NoContent@ +instance MimeRender MimeNoContent NoContent where mimeRender _ = P.const BCL.empty + +-- instance MimeRender MimeOctetStream Double where mimeRender _ = BB.toLazyByteString . BB.doubleDec +-- instance MimeRender MimeOctetStream Float where mimeRender _ = BB.toLazyByteString . BB.floatDec +-- instance MimeRender MimeOctetStream Int where mimeRender _ = BB.toLazyByteString . BB.intDec +-- instance MimeRender MimeOctetStream Integer where mimeRender _ = BB.toLazyByteString . BB.integerDec + +{{#x-unknownMimeTypes}} +-- instance MimeRender {{{x-mediaDataType}}} T.Text where mimeRender _ = undefined +{{/x-unknownMimeTypes}} + +-- ** MimeUnrender Class + +class MimeType mtype => MimeUnrender mtype o where + mimeUnrender :: P.Proxy mtype -> BL.ByteString -> P.Either String o + mimeUnrender' :: mtype -> BL.ByteString -> P.Either String o + mimeUnrender' _ x = mimeUnrender (P.Proxy :: P.Proxy mtype) x + +-- ** MimeUnrender Instances + +-- | @A.eitherDecode@ +instance A.FromJSON a => MimeUnrender MimeJSON a where mimeUnrender _ = A.eitherDecode +-- | @P.left T.unpack . WH.urlDecodeAsForm@ +instance WH.FromForm a => MimeUnrender MimeFormUrlEncoded a where mimeUnrender _ = P.left T.unpack . WH.urlDecodeAsForm +-- | @P.Right . P.id@ + +instance MimeUnrender MimePlainText BL.ByteString where mimeUnrender _ = P.Right . P.id +-- | @P.left P.show . TL.decodeUtf8'@ +instance MimeUnrender MimePlainText T.Text where mimeUnrender _ = P.left P.show . T.decodeUtf8' . BL.toStrict +-- | @P.Right . BCL.unpack@ +instance MimeUnrender MimePlainText String where mimeUnrender _ = P.Right . BCL.unpack + +-- | @P.Right . P.id@ +instance MimeUnrender MimeOctetStream BL.ByteString where mimeUnrender _ = P.Right . P.id +-- | @P.left P.show . T.decodeUtf8' . BL.toStrict@ +instance MimeUnrender MimeOctetStream T.Text where mimeUnrender _ = P.left P.show . T.decodeUtf8' . BL.toStrict +-- | @P.Right . BCL.unpack@ +instance MimeUnrender MimeOctetStream String where mimeUnrender _ = P.Right . BCL.unpack + +-- | @P.Right . P.const NoContent@ +instance MimeUnrender MimeNoContent NoContent where mimeUnrender _ = P.Right . P.const NoContent + +{{#x-unknownMimeTypes}} +-- instance MimeUnrender {{{x-mediaDataType}}} T.Text where mimeUnrender _ = undefined +{{/x-unknownMimeTypes}} + +-- ** Request Consumes + +class MimeType mtype => Consumes req mtype where + +-- ** Request Produces + +class MimeType mtype => Produces req mtype where diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/Model.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/Model.mustache new file mode 100644 index 00000000000..8bac6084805 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/Model.mustache @@ -0,0 +1,170 @@ +{-| +Module : {{title}}.Model +-} + +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module {{title}}.Model where + +import Data.Aeson ((.:),(.:!),(.:?),(.=)) +import Data.Text (Text) + +import Data.Aeson (Value) +import Data.ByteString.Lazy (ByteString) + +import qualified Data.Aeson as A +import qualified Data.ByteString as B +import qualified Data.Data as P (Data, Typeable) +import qualified Data.HashMap.Lazy as HM +import qualified Data.Map as Map +import qualified Data.Maybe as P +import qualified Data.Foldable as P +import qualified Web.FormUrlEncoded as WH +import qualified Web.HttpApiData as WH + +import qualified Data.Time as TI +import qualified Data.Time.ISO8601 as TI +import Data.Time (UTCTime) + +import Control.Applicative ((<|>)) +import Control.Applicative (Alternative) +import Prelude (($), (.),(<$>),(<*>),(>>=),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor) +import qualified Prelude as P + + +{{#imports}}import {{import}} +{{/imports}} + +-- * Models + +{{#models}} +{{#model}} + +-- ** {{classname}} +-- |{{#title}} +-- {{{.}}} +-- {{/title}}{{#description}} +-- {{{.}}}{{/description}} +{{^vendorExtensions.x-customNewtype}} +data {{classname}} = {{classname}} + { {{#vars}}{{name}} :: {{^required}}Maybe {{/required}}{{datatype}} -- ^ {{#required}}/Required/ {{/required}}{{#readOnly}}/ReadOnly/ {{/readOnly}}"{{baseName}}"{{#description}} - {{description}}{{/description}}{{#hasMore}} + , {{/hasMore}}{{/vars}} + } deriving (P.Show,P.Eq,P.Typeable{{#modelDeriving}},{{modelDeriving}}{{/modelDeriving}}) + +instance A.FromJSON {{classname}} where + parseJSON = A.withObject "{{classname}}" $ \o -> + {{classname}} + <$>{{#vars}} (o {{#required}}.: {{/required}}{{^required}}{{^allowFromJsonNulls}}.:!{{/allowFromJsonNulls}}{{#allowFromJsonNulls}}.:?{{/allowFromJsonNulls}}{{/required}} "{{baseName}}"{{#isDateTime}} >>={{^required}} P.mapM{{/required}} _readDateTime{{/isDateTime}}{{#isDate}} >>={{^required}} P.mapM{{/required}} _showDate{{/isDate}}){{#hasMore}} + <*>{{/hasMore}}{{/vars}} + +instance A.ToJSON {{classname}} where + toJSON {{classname}} {..} = + {{^allowToJsonNulls}}_omitNulls{{/allowToJsonNulls}}{{#allowToJsonNulls}}A.object{{/allowToJsonNulls}} + [ {{#vars}}"{{baseName}}" .= {{#isDateTime}}{{^required}}P.fmap {{/required}}_showDateTime{{/isDateTime}}{{#isDate}}{{^required}}P.fmap {{/required}}_showDate{{/isDate}} {{name}}{{#hasMore}} + , {{/hasMore}}{{/vars}} + ] + +{{#vendorExtensions.x-hasMimeFormUrlEncoded}} +instance WH.FromForm {{classname}} where + fromForm f = + {{classname}} + <$>{{#vars}} ({{#required}}WH.parseUnique {{/required}}{{^required}}WH.parseMaybe {{/required}}"{{baseName}}" f{{#isDateTime}} >>={{^required}} P.mapM{{/required}} _readDateTime{{/isDateTime}}{{#isDate}} >>={{^required}} P.mapM{{/required}} _showDate{{/isDate}}){{#hasMore}} + <*>{{/hasMore}}{{/vars}} + +instance WH.ToForm {{classname}} where + toForm {{classname}} {..} = + WH.Form $ HM.fromList $ P.catMaybes $ + [ {{#vars}}_toFormItem "{{baseName}}" ({{#required}}Just $ {{/required}}{{#isDateTime}}{{^required}}P.fmap {{/required}}_showDateTime {{/isDateTime}}{{#isDate}}{{^required}}P.fmap {{/required}}_showDate {{/isDate}}{{name}}){{#hasMore}} + , {{/hasMore}}{{/vars}} + ] +{{/vendorExtensions.x-hasMimeFormUrlEncoded}} + +{{#generateModelConstructors}} +-- | Construct a value of type '{{classname}}' (by applying it's required fields, if any) +mk{{classname}} + :: {{#requiredVars}}{{{datatype}}} -- ^ '{{name}}'{{#description}}:{{/description}} {{{description}}} + -> {{/requiredVars}}{{classname}} +mk{{classname}} {{#requiredVars}}{{name}} {{/requiredVars}}= + {{classname}} + { {{#vars}}{{#required}}{{name}}{{/required}}{{^required}}{{name}} = {{#isListContainer}}Nothing{{/isListContainer}}{{#isMapContainer}}Nothing{{/isMapContainer}}{{^isContainer}}Nothing{{/isContainer}}{{/required}}{{#hasMore}} + , {{/hasMore}}{{/vars}} + } +{{/generateModelConstructors}} + +{{/vendorExtensions.x-customNewtype}} +{{#vendorExtensions.x-customNewtype}} +newtype {{classname}} = {{classname}} {{vendorExtensions.x-customNewtype}} deriving (P.Show, P.Eq, P.Data, P.Typeable, P.Generic, A.FromJSON, A.ToJSON) +{-# WARNING {{classname}} "untested/unimlemented behavior" #-} +{{/vendorExtensions.x-customNewtype}} + +{{/model}} +{{/models}} + +-- * Utils + +-- | Removes Null fields. (OpenAPI-Specification 2.0 does not allow Null in JSON) + +_omitNulls :: [(Text, A.Value)] -> A.Value +_omitNulls = A.object . P.filter notNull + where + notNull (_, A.Null) = False + notNull _ = True + +_toFormItem :: (WH.ToHttpApiData a, Functor f) => t -> f a -> f (t, [Text]) +_toFormItem name x = (name,) . (:[]) . WH.toQueryParam <$> x + +_emptyToNothing :: Maybe String -> Maybe String +_emptyToNothing (Just "") = Nothing +_emptyToNothing x = x +{-# INLINE _emptyToNothing #-} + +_memptyToNothing :: (P.Monoid a, P.Eq a) => Maybe a -> Maybe a +_memptyToNothing (Just x) | x P.== P.mempty = Nothing +_memptyToNothing x = x +{-# INLINE _memptyToNothing #-} + +-- * DateTime Formatting + +-- | @{{^dateTimeFormat}}_parseISO8601{{/dateTimeFormat}}{{#dateTimeFormat}}TI.parseTimeM True TI.defaultTimeLocale "{{{dateTimeFormat}}}"{{/dateTimeFormat}}@ +_readDateTime :: (TI.ParseTime t, Monad m, {{^dateTimeFormat}}Alternative m{{/dateTimeFormat}}) => String -> m t +_readDateTime = + {{^dateTimeFormat}}_parseISO8601{{/dateTimeFormat}}{{#dateTimeFormat}}TI.parseTimeM True TI.defaultTimeLocale "{{{dateTimeFormat}}}"{{/dateTimeFormat}} +{-# INLINE _readDateTime #-} + +-- | @{{^dateTimeFormat}}TI.formatISO8601Millis{{/dateTimeFormat}}{{#dateTimeFormat}}TI.formatTime TI.defaultTimeLocale "{{{dateTimeFormat}}}"{{/dateTimeFormat}}@ +_showDateTime :: ({{^dateTimeFormat}}t ~ UTCTime, {{/dateTimeFormat}}TI.FormatTime t) => t -> String +_showDateTime = + {{^dateTimeFormat}}TI.formatISO8601Millis{{/dateTimeFormat}}{{#dateTimeFormat}}TI.formatTime TI.defaultTimeLocale "{{{dateTimeFormat}}}"{{/dateTimeFormat}} +{-# INLINE _showDateTime #-} + +_parseISO8601 :: (TI.ParseTime t, Monad m, Alternative m) => String -> m t +_parseISO8601 t = + P.asum $ + P.flip (TI.parseTimeM True TI.defaultTimeLocale) t <$> + ["%FT%T%QZ", "%FT%T%Q%z", "%FT%T%Q%Z"] +{-# INLINE _parseISO8601 #-} + +-- * Date Formatting + +-- | @TI.parseTimeM True TI.defaultTimeLocale "{{{dateFormat}}}"@ +_readDate :: (TI.ParseTime t, Monad m) => String -> m t +_readDate = + TI.parseTimeM True TI.defaultTimeLocale "{{{dateFormat}}}" +{-# INLINE _readDate #-} + +-- | @TI.formatTime TI.defaultTimeLocale "{{{dateFormat}}}"@ +_showDate :: TI.FormatTime t => t -> String +_showDate = + TI.formatTime TI.defaultTimeLocale "{{{dateFormat}}}" +{-# INLINE _showDate #-} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/README.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/README.mustache new file mode 100644 index 00000000000..39c9c6d457d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/README.mustache @@ -0,0 +1,163 @@ +## Swagger Auto-Generated [http-client](https://www.stackage.org/lts-9.0/package/http-client-0.5.7.0) Bindings to `{{title}}` + +The library in `lib` provides auto-generated-from-Swagger [http-client](https://www.stackage.org/lts-9.0/package/http-client-0.5.7.0) bindings to the {{title}} API. + +Targeted swagger version: {{swaggerVersion}} + +OpenAPI-Specification: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/{{swaggerVersion}}.md + +## Installation + +Installation follows the standard approach to installing Stack-based projects. + +1. Install the [Haskell `stack` tool](http://docs.haskellstack.org/en/stable/README). +2. To build the package, and generate the documentation (recommended): +``` +stack haddock +``` +which will generate docs for this lib in the `docs` folder. + +To generate the docs in the normal location (to enable hyperlinks to external libs), remove +``` +build: + haddock-arguments: + haddock-args: + - "--odir=./docs" +``` +from the stack.yaml file and run `stack haddock` again. + +3. To run unit tests: +``` +stack test +``` + +## Swagger-Codegen + +The code generator that produced this library, and which explains how +to obtain and use the swagger-codegen cli tool lives at + +https://github.com/swagger-api/swagger-codegen + +The _language_ argument (`--lang`) passed to the cli tool used should be + +``` +haskell-http-client +``` + +### Unsupported Swagger Features + +* Auth Methods (https://swagger.io/docs/specification/2-0/authentication/) + + - use `setHeader` to add any required headers to requests + +* Default Parameter Values + +* Enum Parameters + +This is beta software; other cases may not be supported. + +### Codegen "config option" parameters + +These options allow some customization of the code generation process. + +**haskell-http-client specific options:** + +| OPTION | DESCRIPTION | DEFAULT | ACTUAL | +| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------- | +| allowFromJsonNulls | allow JSON Null during model decoding from JSON | true | {{allowFromJsonNulls}} | +| allowToJsonNulls | allow emitting JSON Null during model encoding to JSON | false | {{allowToJsonNulls}} | +| dateFormat | format string used to parse/render a date | %Y-%m-%d | {{dateFormat}} | +| dateTimeFormat | format string used to parse/render a datetime. (Defaults to [formatISO8601Millis][1] when not provided) | | {{dateTimeFormat}} | +| generateFormUrlEncodedInstances | Generate FromForm/ToForm instances for models used by x-www-form-urlencoded operations (model fields must be primitive types) | true | {{generateFormUrlEncodedInstances}} | +| generateLenses | Generate Lens optics for Models | true | {{generateLenses}} | +| generateModelConstructors | Generate smart constructors (only supply required fields) for models | true | {{generateModelConstructors}} | +| modelDeriving | Additional classes to include in the deriving() clause of Models | | {{modelDeriving}} | + +[1]: https://www.stackage.org/haddock/lts-9.0/iso8601-time-0.1.4/Data-Time-ISO8601.html#v:formatISO8601Millis + +View the full list of Codegen "config option" parameters with the command: + +``` +java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar config-help -l haskell-http-client +``` + +### Example SwaggerPetstore Haddock documentation + +An example of the generated haddock documentation targeting the server http://petstore.swagger.io/ (SwaggerPetstore) can be found [here][2] + +[2]: https://jonschoning.github.io/swaggerpetstore-haskell-http-client/ + +### Example SwaggerPetstore App + +An example application using the auto-generated haskell-http-client bindings for the server http://petstore.swagger.io/ can be found [here][3] + +[3]: https://github.com/jonschoning/swagger-codegen/tree/haskell-http-client/samples/client/petstore/haskell-http-client/example-app + +### Usage Notes + +This library is intended to be imported qualified. + +| MODULE | NOTES | +| ------------------- | --------------------------------------------------- | +| {{title}}.Client | use the "dispatch" functions to send requests | +| {{title}}.API | construct requetss | +| {{title}}.Model | describes models | +| {{title}}.MimeTypes | encoding/decoding MIME types (content-types/accept) | +| {{title}}.Lens | lenses & traversals for model fields | + +This library adds type safety around what swagger specifies as +Produces and Consumes for each Operation (e.g. the list of MIME types an +Operation can Produce (using 'accept' headers) and Consume (using 'content-type' headers). + +For example, if there is an Operation named _addFoo_, there will be a +data type generated named _AddFoo_ (note the capitalization) which +describes additional constraints and actions on the _addFoo_ +operation, which can be viewed in GHCi or via the Haddocks. + +* requried parameters are included as function arguments to _addFoo_ +* optional non-body parameters are included by using `applyOptionalParam` +* optional body parameters are set by using `setBodyParam` + +Example for pretend _addFoo_ operation: + +```haskell +data AddFoo +instance Consumes AddFoo MimeJSON +instance Produces AddFoo MimeJSON +instance Produces AddFoo MimeXML +instance HasBodyParam AddFoo FooModel +instance HasOptionalParam AddFoo FooName +instance HasOptionalParam AddFoo FooId +``` + +this would indicate that: + +* the _addFoo_ operation can consume JSON +* the _addFoo_ operation produces JSON or XML, depending on the argument passed to the dispatch function +* the _addFoo_ operation can set it's body param of _FooModel_ via `setBodyParam` +* the _addFoo_ operation can set 2 different optional parameters via `applyOptionalParam` + +putting this together: + +```haskell +let addFooRequest = addFoo MimeJSON foomodel requiredparam1 requiredparam2 + `applyOptionalParam` FooId 1 + `applyOptionalParam` FooName "name" + `setHeader` [("api_key","xxyy")] +addFooResult <- dispatchMime mgr config addFooRequest MimeXML +``` + +If the swagger spec doesn't declare it can accept or produce a certain +MIME type for a given Operation, you should either add a Produces or +Consumes instance for the desired MIME types (assuming the server +supports it), use `dispatchLbsUnsafe` or modify the swagger spec and +run the generator again. + +New MIME type instances can be added via MimeType/MimeRender/MimeUnrender + +Only JSON instances are generated by default, and in some case +x-www-form-urlencoded instances (FromFrom, ToForm) will also be +generated if the model fields are primitive types, and there are +Operations using x-www-form-urlencoded which use those models. + +See the example app and the haddocks for details. diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/Setup.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/Setup.mustache new file mode 100644 index 00000000000..9a994af677b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/Setup.mustache @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/TopLevel.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/TopLevel.mustache new file mode 100644 index 00000000000..91e97ff9cd9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/TopLevel.mustache @@ -0,0 +1,17 @@ +{-| +Module : {{title}} +-} + +module {{title}} + ( module {{title}}.Client + , module {{title}}.API + , module {{title}}.Model + , module {{title}}.MimeTypes + , {{#generateLenses}}module {{title}}.Lens{{/generateLenses}} + ) where + +import {{title}}.API +import {{title}}.Client +import {{title}}.Model +import {{title}}.MimeTypes +{{#generateLenses}}import {{title}}.Lens{{/generateLenses}} diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/_formColl.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/_formColl.mustache new file mode 100644 index 00000000000..0984ad9af6f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/_formColl.mustache @@ -0,0 +1 @@ +toForm{{#collectionFormat}}Coll {{vendorExtensions.x-collectionFormat}}{{/collectionFormat}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/_headerColl.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/_headerColl.mustache new file mode 100644 index 00000000000..857498867ff --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/_headerColl.mustache @@ -0,0 +1 @@ +toHeader{{#collectionFormat}}Coll {{vendorExtensions.x-collectionFormat}}{{/collectionFormat}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/_queryColl.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/_queryColl.mustache new file mode 100644 index 00000000000..e494efc52d1 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/_queryColl.mustache @@ -0,0 +1 @@ +toQuery{{#collectionFormat}}Coll {{vendorExtensions.x-collectionFormat}}{{/collectionFormat}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/git_push.sh.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/git_push.sh.mustache new file mode 100644 index 00000000000..e153ce23ecf --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/git_push.sh.mustache @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="{{{gitUserId}}}" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="{{{gitRepoId}}}" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="{{{releaseNote}}}" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git crediential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/haskell-http-client.cabal.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/haskell-http-client.cabal.mustache new file mode 100644 index 00000000000..5e5a6223507 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/haskell-http-client.cabal.mustache @@ -0,0 +1,96 @@ +-- This file has been generated from package.yaml by hpack version 0.17.1. +-- +-- see: https://github.com/sol/hpack + +name: {{package}} +version: 0.1.0.0 +synopsis: Auto-generated {{package}} API Client +description: . + Client library for calling the {{package}} API based on http-client. + . + base path: {{basePath}} + . + apiVersion: {{apiVersion}} + . + swagger version: {{swaggerVersion}} + . + {{^hideGenerationTimestamp}}Generated on: {{generatedDate}} + . + {{/hideGenerationTimestamp}}OpenAPI-Specification: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/{{swaggerVersion}}.md +category: Web +homepage: https://github.com/swagger-api/swagger-codegen#readme +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +build-type: Simple +cabal-version: >= 1.10 + +extra-source-files: + README.md + swagger.json + +library + hs-source-dirs: + lib + ghc-options: -Wall + build-depends: + base >=4.7 && <5.0 + , transformers >=0.4.0.0 + , mtl >=2.2.1 + , unordered-containers + , aeson >=1.0 && <2.0 + , bytestring >=0.10.0 && <0.11 + , containers >=0.5.0.0 && <0.6 + , http-types >=0.8 && <0.10 + , http-client >=0.5 && <0.6 + , http-client-tls + , http-api-data >= 0.3.4 && <0.4 + , http-media >= 0.4 && < 0.8 + , text >=0.11 && <1.3 + , time >=1.5 && <1.9 + , iso8601-time >=0.1.3 && <0.2.0 + , vector >=0.10.9 && <0.13 + , network >=2.6.2 && <2.7 + , random >=1.1 + , exceptions >= 0.4 + , monad-logger >=0.3 && <0.4 + , safe-exceptions <0.2 + , case-insensitive + exposed-modules: + {{title}} + {{title}}.API + {{title}}.Client + {{title}}.Model + {{title}}.MimeTypes + {{#generateLenses}}{{title}}.Lens{{/generateLenses}} + other-modules: + Paths_{{pathsName}} + default-language: Haskell2010 + +test-suite tests + type: exitcode-stdio-1.0 + main-is: Test.hs + hs-source-dirs: + tests + ghc-options: -fno-warn-orphans + build-depends: + base >=4.7 && <5.0 + , transformers >=0.4.0.0 + , mtl >=2.2.1 + , unordered-containers + , {{package}} + , bytestring >=0.10.0 && <0.11 + , containers + , hspec >=1.8 + , text + , time + , iso8601-time + , aeson + , semigroups + , QuickCheck + other-modules: + ApproxEq + Instances + PropMime + default-language: Haskell2010 diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/package.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/package.mustache new file mode 100644 index 00000000000..c0747d40afd --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/package.mustache @@ -0,0 +1,84 @@ +name: {{package}} +version: '0.1.0.0' +synopsis: Auto-generated {{package}} API Client +description: ! ' + + Client library for calling the {{package}} API based on http-client. + + host: {{host}} + + + base path: {{basePath}} + + + apiVersion: {{apiVersion}} + + + swagger version: {{swaggerVersion}} + + + {{^hideGenerationTimestamp}}Generated on: {{generatedDate}} + + + {{/hideGenerationTimestamp}}OpenAPI-Specification: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/{{swaggerVersion}}.md +' +category: Web +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +homepage: https://github.com/swagger-api/swagger-codegen#readme +extra-source-files: +- README.md +- swagger.json +dependencies: +- base >=4.7 && <5.0 +- transformers >=0.4.0.0 +- mtl >=2.2.1 +- unordered-containers +library: + source-dirs: lib + ghc-options: -Wall + exposed-modules: + - {{title}} + - {{title}}.API + - {{title}}.Client + - {{title}}.Model + - {{title}}.MimeTypes + {{#generateLenses}}- {{title}}.Lens{{/generateLenses}} + dependencies: + - aeson >=1.0 && <2.0 + - bytestring >=0.10.0 && <0.11 + - containers >=0.5.0.0 && <0.6 + - http-types >=0.8 && <0.10 + - http-client >=0.5 && <0.6 + - http-client-tls + - http-api-data >= 0.3.4 && <0.4 + - http-media >= 0.4 && < 0.8 + - text >=0.11 && <1.3 + - time >=1.5 && <1.9 + - iso8601-time >=0.1.3 && <0.2.0 + - vector >=0.10.9 && <0.13 + - network >=2.6.2 && <2.7 + - random >=1.1 + - exceptions >= 0.4 + - monad-logger >=0.3 && <0.4 + - safe-exceptions <0.2 + - case-insensitive +tests: + tests: + main: Test.hs + source-dirs: tests + ghc-options: + - -fno-warn-orphans + dependencies: + - {{package}} + - bytestring >=0.10.0 && <0.11 + - containers + - hspec >=1.8 + - text + - time + - iso8601-time + - aeson + - semigroups + - QuickCheck diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/stack.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/stack.mustache new file mode 100644 index 00000000000..174a76815bc --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/stack.mustache @@ -0,0 +1,8 @@ +resolver: lts-9.0 +build: + haddock-arguments: + haddock-args: + - "--odir=./docs" +extra-deps: [] +packages: +- '.' diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/ApproxEq.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/ApproxEq.mustache new file mode 100644 index 00000000000..88ca2110a06 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/ApproxEq.mustache @@ -0,0 +1,81 @@ +{-# LANGUAGE DefaultSignatures #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeOperators #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} + +module ApproxEq where + +import Data.Text (Text) +import Data.Time.Clock +import Test.QuickCheck +import GHC.Generics as G + +(==~) + :: (ApproxEq a, Show a) + => a -> a -> Property +a ==~ b = counterexample (show a ++ " !=~ " ++ show b) (a =~ b) + +class GApproxEq f where + gApproxEq :: f a -> f a -> Bool + +instance GApproxEq U1 where + gApproxEq U1 U1 = True + +instance (GApproxEq a, GApproxEq b) => + GApproxEq (a :+: b) where + gApproxEq (L1 a) (L1 b) = gApproxEq a b + gApproxEq (R1 a) (R1 b) = gApproxEq a b + gApproxEq _ _ = False + +instance (GApproxEq a, GApproxEq b) => + GApproxEq (a :*: b) where + gApproxEq (a1 :*: b1) (a2 :*: b2) = gApproxEq a1 a2 && gApproxEq b1 b2 + +instance (ApproxEq a) => + GApproxEq (K1 i a) where + gApproxEq (K1 a) (K1 b) = a =~ b + +instance (GApproxEq f) => + GApproxEq (M1 i t f) where + gApproxEq (M1 a) (M1 b) = gApproxEq a b + +class ApproxEq a where + (=~) :: a -> a -> Bool + default (=~) :: (Generic a, GApproxEq (Rep a)) => a -> a -> Bool + a =~ b = gApproxEq (G.from a) (G.from b) + +instance ApproxEq Text where + (=~) = (==) + +instance ApproxEq Char where + (=~) = (==) + +instance ApproxEq Bool where + (=~) = (==) + +instance ApproxEq Int where + (=~) = (==) + +instance ApproxEq Double where + (=~) = (==) + +instance ApproxEq a => + ApproxEq (Maybe a) + +instance ApproxEq UTCTime where + (=~) = (==) + +instance ApproxEq a => + ApproxEq [a] where + as =~ bs = and (zipWith (=~) as bs) + +instance (ApproxEq l, ApproxEq r) => + ApproxEq (Either l r) where + Left a =~ Left b = a =~ b + Right a =~ Right b = a =~ b + _ =~ _ = False + +instance (ApproxEq l, ApproxEq r) => + ApproxEq (l, r) where + (=~) (l1, r1) (l2, r2) = l1 =~ l2 && r1 =~ r2 diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/Instances.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/Instances.mustache new file mode 100644 index 00000000000..51de32c1727 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/Instances.mustache @@ -0,0 +1,53 @@ +module Instances where + +import Data.Text (Text, pack) +import Data.Char (isSpace) +import Data.List (sort) +import Data.Time.Calendar (Day(..)) +import Data.Time.Clock (UTCTime(..), secondsToDiffTime) +import Test.QuickCheck +import qualified Data.HashMap.Strict as HM +import qualified Data.Set as Set + +import ApproxEq +import {{title}}.Model + +instance Arbitrary Text where + arbitrary = pack <$> arbitrary + +instance Arbitrary Day where + arbitrary = ModifiedJulianDay . (2000 +) <$> arbitrary + shrink = (ModifiedJulianDay <$>) . shrink . toModifiedJulianDay + +instance Arbitrary UTCTime where + arbitrary = + UTCTime <$> arbitrary <*> (secondsToDiffTime <$> choose (0, 86401)) + +-- | Checks if a given list has no duplicates in _O(n log n)_. +hasNoDups + :: (Ord a) + => [a] -> Bool +hasNoDups = go Set.empty + where + go _ [] = True + go s (x:xs) + | s' <- Set.insert x s + , Set.size s' > Set.size s = go s' xs + | otherwise = False + +instance ApproxEq Day where + (=~) = (==) + +-- * Models + +{{#models}} +{{#model}} +instance Arbitrary {{classname}} where + arbitrary = + {{classname}} + <$> {{#vars}}arbitrary -- {{name}} :: {{^required}}Maybe {{/required}}{{datatype}} + {{#hasMore}}<*> {{/hasMore}}{{/vars}} + +{{/model}} +{{/models}} + diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/PropMime.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/PropMime.mustache new file mode 100644 index 00000000000..763ceed8935 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/PropMime.mustache @@ -0,0 +1,50 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ConstraintKinds #-} + +module PropMime where + +import Data.Aeson +import Data.Aeson.Types (parseEither) +import Data.Monoid ((<>)) +import Data.Typeable (Proxy(..), typeOf, Typeable) +import qualified Data.ByteString.Lazy.Char8 as BL8 +import Test.Hspec +import Test.QuickCheck +import Test.QuickCheck.Property +import Test.Hspec.QuickCheck (prop) + +import {{title}}.MimeTypes + +import ApproxEq + +-- * Type Aliases + +type ArbitraryMime mime a = ArbitraryRoundtrip (MimeUnrender mime) (MimeRender mime) a + +type ArbitraryRoundtrip from to a = (from a, to a, Arbitrary' a) + +type Arbitrary' a = (Arbitrary a, Show a, Typeable a) + +-- * Mime + +propMime + :: forall a b mime. + (ArbitraryMime mime a, Testable b) + => String -> (a -> a -> b) -> mime -> Proxy a -> Spec +propMime eqDescr eq m _ = + prop + (show (typeOf (undefined :: a)) <> " " <> show (typeOf (undefined :: mime)) <> " roundtrip " <> eqDescr) $ + \(x :: a) -> + let rendered = mimeRender' m x + actual = mimeUnrender' m rendered + expected = Right x + failMsg = + "ACTUAL: " <> show actual <> "\nRENDERED: " <> BL8.unpack rendered + in counterexample failMsg $ + either reject property (eq <$> actual <*> expected) + where + reject = property . const rejected + +propMimeEq :: (ArbitraryMime mime a, Eq a) => mime -> Proxy a -> Spec +propMimeEq = propMime "(EQ)" (==) diff --git a/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/Test.mustache b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/Test.mustache new file mode 100644 index 00000000000..e829e013040 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/haskell-http-client/tests/Test.mustache @@ -0,0 +1,23 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE PartialTypeSignatures #-} + +module Main where + +import Data.Typeable (Proxy(..)) +import Test.Hspec +import Test.Hspec.QuickCheck + +import PropMime +import Instances () + +import {{title}}.Model +import {{title}}.MimeTypes + +main :: IO () +main = + hspec $ modifyMaxSize (const 10) $ + do describe "JSON instances" $ + do {{#models}}{{#model}}propMimeEq MimeJSON (Proxy :: Proxy {{classname}}) + {{/model}}{{/models}} diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/haskellhttpclient/HaskellHttpClientOptionsTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/haskellhttpclient/HaskellHttpClientOptionsTest.java new file mode 100644 index 00000000000..b63a4bf4888 --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/haskellhttpclient/HaskellHttpClientOptionsTest.java @@ -0,0 +1,53 @@ +package io.swagger.codegen.haskellhttpclient; + +import io.swagger.codegen.AbstractOptionsTest; +import io.swagger.codegen.CodegenConfig; +import io.swagger.codegen.languages.HaskellHttpClientCodegen; +import io.swagger.codegen.options.HaskellHttpClientOptionsProvider; +import mockit.Expectations; +import mockit.Tested; + +public class HaskellHttpClientOptionsTest extends AbstractOptionsTest { + + @Tested + private HaskellHttpClientCodegen clientCodegen; + + public HaskellHttpClientOptionsTest() { + super(new HaskellHttpClientOptionsProvider()); + } + + @Override + protected CodegenConfig getCodegenConfig() { + return clientCodegen; + } + + @Override + protected void setExpectations() { + new Expectations(clientCodegen) {{ + clientCodegen.setModelPackage(HaskellHttpClientOptionsProvider.MODEL_PACKAGE_VALUE); + times = 1; + clientCodegen.setApiPackage(HaskellHttpClientOptionsProvider.API_PACKAGE_VALUE); + times = 1; + clientCodegen.setSortParamsByRequiredFlag(Boolean.valueOf(HaskellHttpClientOptionsProvider.SORT_PARAMS_VALUE)); + times = 1; + + clientCodegen.setAllowFromJsonNulls(Boolean.valueOf(HaskellHttpClientOptionsProvider.ALLOW_FROMJSON_NULLS)); + times = 1; + clientCodegen.setAllowToJsonNulls(Boolean.valueOf(HaskellHttpClientOptionsProvider.ALLOW_TOJSON_NULLS)); + times = 1; + clientCodegen.setGenerateModelConstructors(Boolean.valueOf(HaskellHttpClientOptionsProvider.GENERATE_MODEL_CONSTRUCTORS)); + times = 1; + clientCodegen.setGenerateFormUrlEncodedInstances(Boolean.valueOf(HaskellHttpClientOptionsProvider.GENERATE_FORM_URLENCODED_INSTANCES)); + times = 1; + clientCodegen.setGenerateLenses(Boolean.valueOf(HaskellHttpClientOptionsProvider.GENERATE_LENSES)); + times = 1; + clientCodegen.setModelDeriving(HaskellHttpClientOptionsProvider.MODEL_DERIVING); + times = 1; + clientCodegen.setDateTimeFormat(HaskellHttpClientOptionsProvider.DATETIME_FORMAT); + times = 1; + clientCodegen.setDateFormat(HaskellHttpClientOptionsProvider.DATE_FORMAT); + times = 1; + + }}; + } +} diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/haskellhttpclient/HaskellHttpClientTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/haskellhttpclient/HaskellHttpClientTest.java new file mode 100644 index 00000000000..6c7e4f8cfc8 --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/haskellhttpclient/HaskellHttpClientTest.java @@ -0,0 +1,12 @@ +package io.swagger.codegen.haskellhttpclient; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class HaskellHttpClientTest { + + @Test(description = "convert a haskell model with dots") + public void modelTest() { + Assert.assertEquals(true, true); + } +} diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/HaskellHttpClientOptionsProvider.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/HaskellHttpClientOptionsProvider.java new file mode 100644 index 00000000000..8e589ac13a4 --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/HaskellHttpClientOptionsProvider.java @@ -0,0 +1,57 @@ +package io.swagger.codegen.options; + +import com.google.common.collect.ImmutableMap; +import io.swagger.codegen.CodegenConstants; +import io.swagger.codegen.languages.HaskellHttpClientCodegen; + +import java.util.Map; + +public class HaskellHttpClientOptionsProvider implements OptionsProvider { + public static final String MODEL_PACKAGE_VALUE = "Model"; + public static final String API_PACKAGE_VALUE = "Api"; + public static final String SORT_PARAMS_VALUE = "false"; + public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true"; + public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false"; + public static final String HIDE_GENERATION_TIMESTAMP = "true"; + + public static final String ALLOW_FROMJSON_NULLS = "true"; + public static final String ALLOW_TOJSON_NULLS = "false"; + public static final String DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S%Q%z"; + public static final String DATE_FORMAT = "%Y-%m-%d"; + public static final String MODEL_DERIVING = ""; + public static final String GENERATE_FORM_URLENCODED_INSTANCES = "true"; + public static final String GENERATE_LENSES = "true"; + public static final String GENERATE_MODEL_CONSTRUCTORS = "true"; + + @Override + public String getLanguage() { + return "haskell-http-client"; + } + + @Override + public Map createOptions() { + ImmutableMap.Builder builder = new ImmutableMap.Builder(); + return builder.put(CodegenConstants.MODEL_PACKAGE, MODEL_PACKAGE_VALUE) + .put(CodegenConstants.API_PACKAGE, API_PACKAGE_VALUE) + .put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE) + .put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE) + .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) + .put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, HIDE_GENERATION_TIMESTAMP) + + .put(HaskellHttpClientCodegen.ALLOW_FROMJSON_NULLS, ALLOW_FROMJSON_NULLS) + .put(HaskellHttpClientCodegen.ALLOW_TOJSON_NULLS, ALLOW_TOJSON_NULLS) + .put(HaskellHttpClientCodegen.DATETIME_FORMAT, DATETIME_FORMAT) + .put(HaskellHttpClientCodegen.DATE_FORMAT, DATE_FORMAT) + .put(HaskellHttpClientCodegen.MODEL_DERIVING, MODEL_DERIVING) + .put(HaskellHttpClientCodegen.GENERATE_FORM_URLENCODED_INSTANCES, GENERATE_FORM_URLENCODED_INSTANCES) + .put(HaskellHttpClientCodegen.GENERATE_LENSES, GENERATE_LENSES) + .put(HaskellHttpClientCodegen.GENERATE_MODEL_CONSTRUCTORS, GENERATE_MODEL_CONSTRUCTORS) + + .build(); + } + + @Override + public boolean isServer() { + return false; + } +} diff --git a/pom.xml b/pom.xml index fe4c198e2da..7f6cb047984 100644 --- a/pom.xml +++ b/pom.xml @@ -360,6 +360,30 @@ samples/client/petstore/clojure + + haskell-http-client + + + env + haskell-http-client + + + + samples/client/petstore/haskell-http-client + + + + haskell-http-client-integration-test + + + env + haskell-http-client + + + + samples/client/petstore/haskell-http-client/tests-integration + + java-client-jersey1 @@ -823,6 +847,8 @@ samples/client/petstore/akka-scala samples/client/petstore/javascript samples/client/petstore/python + + samples/client/petstore/typescript-fetch/builds/default samples/client/petstore/typescript-fetch/builds/es6-target samples/client/petstore/typescript-fetch/builds/with-npm-version diff --git a/samples/client/petstore/haskell-http-client/.gitignore b/samples/client/petstore/haskell-http-client/.gitignore new file mode 100644 index 00000000000..aaed8f870ea --- /dev/null +++ b/samples/client/petstore/haskell-http-client/.gitignore @@ -0,0 +1,8 @@ +.stack-work +src/highlight.js +src/style.css +dist +dist-newstyle +cabal.project.local +.cabal-sandbox +cabal.sandbox.config \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/.swagger-codegen-ignore b/samples/client/petstore/haskell-http-client/.swagger-codegen-ignore new file mode 100644 index 00000000000..c5fa491b4c5 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# 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 Swagger Codgen 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/client/petstore/haskell-http-client/.swagger-codegen/VERSION b/samples/client/petstore/haskell-http-client/.swagger-codegen/VERSION new file mode 100644 index 00000000000..f9f7450d135 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.0-SNAPSHOT \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/.travis.yml b/samples/client/petstore/haskell-http-client/.travis.yml new file mode 100644 index 00000000000..a90f612b74d --- /dev/null +++ b/samples/client/petstore/haskell-http-client/.travis.yml @@ -0,0 +1,16 @@ +sudo: false +language: c +addons: + apt: + packages: + - libgmp-dev +before_install: +- mkdir -p ~/.local/bin +- export PATH=$HOME/.local/bin:$PATH +- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' +script: +- stack --install-ghc --no-haddock-deps haddock +- stack test +cache: + directories: + - $HOME/.stack diff --git a/samples/client/petstore/haskell-http-client/README.md b/samples/client/petstore/haskell-http-client/README.md new file mode 100644 index 00000000000..d1ee4f9c200 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/README.md @@ -0,0 +1,163 @@ +## Swagger Auto-Generated [http-client](https://www.stackage.org/lts-9.0/package/http-client-0.5.7.0) Bindings to `SwaggerPetstore` + +The library in `lib` provides auto-generated-from-Swagger [http-client](https://www.stackage.org/lts-9.0/package/http-client-0.5.7.0) bindings to the SwaggerPetstore API. + +Targeted swagger version: 2.0 + +OpenAPI-Specification: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md + +## Installation + +Installation follows the standard approach to installing Stack-based projects. + +1. Install the [Haskell `stack` tool](http://docs.haskellstack.org/en/stable/README). +2. To build the package, and generate the documentation (recommended): +``` +stack haddock +``` +which will generate docs for this lib in the `docs` folder. + +To generate the docs in the normal location (to enable hyperlinks to external libs), remove +``` +build: + haddock-arguments: + haddock-args: + - "--odir=./docs" +``` +from the stack.yaml file and run `stack haddock` again. + +3. To run unit tests: +``` +stack test +``` + +## Swagger-Codegen + +The code generator that produced this library, and which explains how +to obtain and use the swagger-codegen cli tool lives at + +https://github.com/swagger-api/swagger-codegen + +The _language_ argument (`--lang`) passed to the cli tool used should be + +``` +haskell-http-client +``` + +### Unsupported Swagger Features + +* Auth Methods (https://swagger.io/docs/specification/2-0/authentication/) + + - use `setHeader` to add any required headers to requests + +* Default Parameter Values + +* Enum Parameters + +This is beta software; other cases may not be supported. + +### Codegen "config option" parameters + +These options allow some customization of the code generation process. + +**haskell-http-client specific options:** + +| OPTION | DESCRIPTION | DEFAULT | ACTUAL | +| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------- | +| allowFromJsonNulls | allow JSON Null during model decoding from JSON | true | true | +| allowToJsonNulls | allow emitting JSON Null during model encoding to JSON | false | false | +| dateFormat | format string used to parse/render a date | %Y-%m-%d | | +| dateTimeFormat | format string used to parse/render a datetime. (Defaults to [formatISO8601Millis][1] when not provided) | | | +| generateFormUrlEncodedInstances | Generate FromForm/ToForm instances for models used by x-www-form-urlencoded operations (model fields must be primitive types) | true | true | +| generateLenses | Generate Lens optics for Models | true | true | +| generateModelConstructors | Generate smart constructors (only supply required fields) for models | true | true | +| modelDeriving | Additional classes to include in the deriving() clause of Models | | | + +[1]: https://www.stackage.org/haddock/lts-9.0/iso8601-time-0.1.4/Data-Time-ISO8601.html#v:formatISO8601Millis + +View the full list of Codegen "config option" parameters with the command: + +``` +java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar config-help -l haskell-http-client +``` + +### Example SwaggerPetstore Haddock documentation + +An example of the generated haddock documentation targeting the server http://petstore.swagger.io/ (SwaggerPetstore) can be found [here][2] + +[2]: https://jonschoning.github.io/swaggerpetstore-haskell-http-client/ + +### Example SwaggerPetstore App + +An example application using the auto-generated haskell-http-client bindings for the server http://petstore.swagger.io/ can be found [here][3] + +[3]: https://github.com/jonschoning/swagger-codegen/tree/haskell-http-client/samples/client/petstore/haskell-http-client/example-app + +### Usage Notes + +This library is intended to be imported qualified. + +| MODULE | NOTES | +| ------------------- | --------------------------------------------------- | +| SwaggerPetstore.Client | use the "dispatch" functions to send requests | +| SwaggerPetstore.API | construct requetss | +| SwaggerPetstore.Model | describes models | +| SwaggerPetstore.MimeTypes | encoding/decoding MIME types (content-types/accept) | +| SwaggerPetstore.Lens | lenses & traversals for model fields | + +This library adds type safety around what swagger specifies as +Produces and Consumes for each Operation (e.g. the list of MIME types an +Operation can Produce (using 'accept' headers) and Consume (using 'content-type' headers). + +For example, if there is an Operation named _addFoo_, there will be a +data type generated named _AddFoo_ (note the capitalization) which +describes additional constraints and actions on the _addFoo_ +operation, which can be viewed in GHCi or via the Haddocks. + +* requried parameters are included as function arguments to _addFoo_ +* optional non-body parameters are included by using `applyOptionalParam` +* optional body parameters are set by using `setBodyParam` + +Example for pretend _addFoo_ operation: + +```haskell +data AddFoo +instance Consumes AddFoo MimeJSON +instance Produces AddFoo MimeJSON +instance Produces AddFoo MimeXML +instance HasBodyParam AddFoo FooModel +instance HasOptionalParam AddFoo FooName +instance HasOptionalParam AddFoo FooId +``` + +this would indicate that: + +* the _addFoo_ operation can consume JSON +* the _addFoo_ operation produces JSON or XML, depending on the argument passed to the dispatch function +* the _addFoo_ operation can set it's body param of _FooModel_ via `setBodyParam` +* the _addFoo_ operation can set 2 different optional parameters via `applyOptionalParam` + +putting this together: + +```haskell +let addFooRequest = addFoo MimeJSON foomodel requiredparam1 requiredparam2 + `applyOptionalParam` FooId 1 + `applyOptionalParam` FooName "name" + `setHeader` [("api_key","xxyy")] +addFooResult <- dispatchMime mgr config addFooRequest MimeXML +``` + +If the swagger spec doesn't declare it can accept or produce a certain +MIME type for a given Operation, you should either add a Produces or +Consumes instance for the desired MIME types (assuming the server +supports it), use `dispatchLbsUnsafe` or modify the swagger spec and +run the generator again. + +New MIME type instances can be added via MimeType/MimeRender/MimeUnrender + +Only JSON instances are generated by default, and in some case +x-www-form-urlencoded instances (FromFrom, ToForm) will also be +generated if the model fields are primitive types, and there are +Operations using x-www-form-urlencoded which use those models. + +See the example app and the haddocks for details. diff --git a/samples/client/petstore/haskell-http-client/Setup.hs b/samples/client/petstore/haskell-http-client/Setup.hs new file mode 100644 index 00000000000..9a994af677b --- /dev/null +++ b/samples/client/petstore/haskell-http-client/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/samples/client/petstore/haskell-http-client/docs.sh b/samples/client/petstore/haskell-http-client/docs.sh new file mode 100755 index 00000000000..5db07846482 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +cabal_file=$(find . -maxdepth 1 -name "*.cabal" -print -quit) + +if [ ! -f "$cabal_file" ]; then + echo "Run this script in the top-level package directory" + exit 1 +fi + +pkg=$(awk -F ":[[:space:]]*" 'tolower($1)=="name" { print $2 }' < "$cabal_file") +ver=$(awk -F ":[[:space:]]*" 'tolower($1)=="version" { print $2 }' < "$cabal_file") + +if [ -z "$pkg" ]; then + echo "Unable to determine package name" + exit 1 +fi + +if [ -z "$ver" ]; then + echo "Unable to determine package version" + exit 1 +fi + +echo "Detected package: $pkg-$ver" + +cabal haddock --hyperlink-source --html-location='https://www.stackage.org/haddock/nightly-2017-08-25/$pkg-$version' --contents-location='https://www.stackage.org/nightly-2017-08-25/package/$pkg-$version' + +dir="build-docs" +trap 'rm -r "$dir"' EXIT +mkdir -p $dir +cp -R dist/doc/html/$pkg/ $dir/$pkg-$ver-docs diff --git a/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-API.html b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-API.html new file mode 100644 index 00000000000..2dab043222b --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-API.html @@ -0,0 +1,4 @@ +SwaggerPetstore.API

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Safe HaskellNone
LanguageHaskell2010

SwaggerPetstore.API

Description

 

Synopsis

Operations

Pet

addPet

addPet Source #

Arguments

:: (Consumes AddPet contentType, MimeRender contentType Pet) 
=> contentType

request content-type (MimeType)

-> Pet

"body" - Pet object that needs to be added to the store

-> SwaggerPetstoreRequest AddPet contentType res 
POST /pet

Add a new pet to the store

AuthMethod: petstore_auth

Note: Has Produces instances, but no response schema

data AddPet Source #

Instances

Produces AddPet MimeXML Source #
application/xml
Produces AddPet MimeJSON Source #
application/json
Consumes AddPet MimeXML Source #
application/xml
Consumes AddPet MimeJSON Source #
application/json
HasBodyParam AddPet Pet Source #

Body Param "body" - Pet object that needs to be added to the store

Methods

setBodyParam :: (Consumes AddPet contentType, MimeRender contentType Pet) => SwaggerPetstoreRequest AddPet contentType res -> Pet -> SwaggerPetstoreRequest AddPet contentType res Source #

deletePet

deletePet Source #

Arguments

:: Integer

"petId" - Pet id to delete

-> SwaggerPetstoreRequest DeletePet MimeNoContent res 
DELETE /pet/{petId}

Deletes a pet

AuthMethod: petstore_auth

Note: Has Produces instances, but no response schema

findPetsByStatus

findPetsByStatus Source #

Arguments

:: [Text]

"status" - Status values that need to be considered for filter

-> SwaggerPetstoreRequest FindPetsByStatus MimeNoContent [Pet] 
GET /pet/findByStatus

Finds Pets by status

Multiple status values can be provided with comma separated strings

AuthMethod: petstore_auth

findPetsByTags

findPetsByTags Source #

Arguments

:: [Text]

"tags" - Tags to filter by

-> SwaggerPetstoreRequest FindPetsByTags MimeNoContent [Pet] 

Deprecated:

GET /pet/findByTags

Finds Pets by tags

Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.

AuthMethod: petstore_auth

getPetById

getPetById Source #

Arguments

:: Integer

"petId" - ID of pet to return

-> SwaggerPetstoreRequest GetPetById MimeNoContent Pet 
GET /pet/{petId}

Find pet by ID

Returns a single pet

AuthMethod: api_key

data GetPetById Source #

Instances

updatePet

updatePet Source #

Arguments

:: (Consumes UpdatePet contentType, MimeRender contentType Pet) 
=> contentType

request content-type (MimeType)

-> Pet

"body" - Pet object that needs to be added to the store

-> SwaggerPetstoreRequest UpdatePet contentType res 
PUT /pet

Update an existing pet

AuthMethod: petstore_auth

Note: Has Produces instances, but no response schema

data UpdatePet Source #

Instances

Produces UpdatePet MimeXML Source #
application/xml
Produces UpdatePet MimeJSON Source #
application/json
Consumes UpdatePet MimeXML Source #
application/xml
Consumes UpdatePet MimeJSON Source #
application/json
HasBodyParam UpdatePet Pet Source #

Body Param "body" - Pet object that needs to be added to the store

Methods

setBodyParam :: (Consumes UpdatePet contentType, MimeRender contentType Pet) => SwaggerPetstoreRequest UpdatePet contentType res -> Pet -> SwaggerPetstoreRequest UpdatePet contentType res Source #

updatePetWithForm

updatePetWithForm Source #

Arguments

:: Consumes UpdatePetWithForm contentType 
=> contentType

request content-type (MimeType)

-> Integer

"petId" - ID of pet that needs to be updated

-> SwaggerPetstoreRequest UpdatePetWithForm contentType res 
POST /pet/{petId}

Updates a pet in the store with form data

AuthMethod: petstore_auth

Note: Has Produces instances, but no response schema

uploadFile

uploadFile Source #

Arguments

:: Consumes UploadFile contentType 
=> contentType

request content-type (MimeType)

-> Integer

"petId" - ID of pet to update

-> SwaggerPetstoreRequest UploadFile contentType ApiResponse 
POST /pet/{petId}/uploadImage

uploads an image

AuthMethod: petstore_auth

data UploadFile Source #

Instances

Produces UploadFile MimeJSON Source #
application/json
Consumes UploadFile MimeMultipartFormData Source #
multipart/form-data
HasOptionalParam UploadFile File Source #

Optional Param "file" - file to upload

HasOptionalParam UploadFile AdditionalMetadata Source #

Optional Param "additionalMetadata" - Additional data to pass to server

Store

deleteOrder

deleteOrder Source #

Arguments

:: Text

"orderId" - ID of the order that needs to be deleted

-> SwaggerPetstoreRequest DeleteOrder MimeNoContent res 
DELETE /store/order/{orderId}

Delete purchase order by ID

For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors

Note: Has Produces instances, but no response schema

data DeleteOrder Source #

Instances

getInventory

getInventory :: SwaggerPetstoreRequest GetInventory MimeNoContent (Map String Int) Source #

GET /store/inventory

Returns pet inventories by status

Returns a map of status codes to quantities

AuthMethod: api_key

data GetInventory Source #

Instances

getOrderById

getOrderById Source #

Arguments

:: Integer

"orderId" - ID of pet that needs to be fetched

-> SwaggerPetstoreRequest GetOrderById MimeNoContent Order 
GET /store/order/{orderId}

Find purchase order by ID

For valid response try integer IDs with value 5 or 10. Other values will generated exceptions

placeOrder

placeOrder Source #

Arguments

:: (Consumes PlaceOrder contentType, MimeRender contentType Order) 
=> contentType

request content-type (MimeType)

-> Order

"body" - order placed for purchasing the pet

-> SwaggerPetstoreRequest PlaceOrder contentType Order 
POST /store/order

Place an order for a pet

data PlaceOrder Source #

Instances

Produces PlaceOrder MimeXML Source #
application/xml
Produces PlaceOrder MimeJSON Source #
application/json
HasBodyParam PlaceOrder Order Source #

Body Param "body" - order placed for purchasing the pet

Methods

setBodyParam :: (Consumes PlaceOrder contentType, MimeRender contentType Order) => SwaggerPetstoreRequest PlaceOrder contentType res -> Order -> SwaggerPetstoreRequest PlaceOrder contentType res Source #

User

createUser

createUser Source #

Arguments

:: (Consumes CreateUser contentType, MimeRender contentType User) 
=> contentType

request content-type (MimeType)

-> User

"body" - Created user object

-> SwaggerPetstoreRequest CreateUser contentType res 
POST /user

Create user

This can only be done by the logged in user.

Note: Has Produces instances, but no response schema

data CreateUser Source #

Instances

Produces CreateUser MimeXML Source #
application/xml
Produces CreateUser MimeJSON Source #
application/json
HasBodyParam CreateUser User Source #

Body Param "body" - Created user object

Methods

setBodyParam :: (Consumes CreateUser contentType, MimeRender contentType User) => SwaggerPetstoreRequest CreateUser contentType res -> User -> SwaggerPetstoreRequest CreateUser contentType res Source #

createUsersWithArrayInput

createUsersWithArrayInput Source #

Arguments

:: (Consumes CreateUsersWithArrayInput contentType, MimeRender contentType [User]) 
=> contentType

request content-type (MimeType)

-> [User]

"body" - List of user object

-> SwaggerPetstoreRequest CreateUsersWithArrayInput contentType res 
POST /user/createWithArray

Creates list of users with given input array

Note: Has Produces instances, but no response schema

createUsersWithListInput

createUsersWithListInput Source #

Arguments

:: (Consumes CreateUsersWithListInput contentType, MimeRender contentType [User]) 
=> contentType

request content-type (MimeType)

-> [User]

"body" - List of user object

-> SwaggerPetstoreRequest CreateUsersWithListInput contentType res 
POST /user/createWithList

Creates list of users with given input array

Note: Has Produces instances, but no response schema

deleteUser

deleteUser Source #

Arguments

:: Text

"username" - The name that needs to be deleted

-> SwaggerPetstoreRequest DeleteUser MimeNoContent res 
DELETE /user/{username}

Delete user

This can only be done by the logged in user.

Note: Has Produces instances, but no response schema

data DeleteUser Source #

Instances

getUserByName

getUserByName Source #

Arguments

:: Text

"username" - The name that needs to be fetched. Use user1 for testing.

-> SwaggerPetstoreRequest GetUserByName MimeNoContent User 
GET /user/{username}

Get user by user name

loginUser

loginUser Source #

Arguments

:: Text

"username" - The user name for login

-> Text

"password" - The password for login in clear text

-> SwaggerPetstoreRequest LoginUser MimeNoContent Text 
GET /user/login

Logs user into the system

data LoginUser Source #

Instances

logoutUser

logoutUser :: SwaggerPetstoreRequest LogoutUser MimeNoContent res Source #

GET /user/logout

Logs out current logged in user session

Note: Has Produces instances, but no response schema

data LogoutUser Source #

Instances

updateUser

updateUser Source #

Arguments

:: (Consumes UpdateUser contentType, MimeRender contentType User) 
=> contentType

request content-type (MimeType)

-> Text

"username" - name that need to be deleted

-> User

"body" - Updated user object

-> SwaggerPetstoreRequest UpdateUser contentType res 
PUT /user/{username}

Updated user

This can only be done by the logged in user.

Note: Has Produces instances, but no response schema

data UpdateUser Source #

Instances

Produces UpdateUser MimeXML Source #
application/xml
Produces UpdateUser MimeJSON Source #
application/json
HasBodyParam UpdateUser User Source #

Body Param "body" - Updated user object

Methods

setBodyParam :: (Consumes UpdateUser contentType, MimeRender contentType User) => SwaggerPetstoreRequest UpdateUser contentType res -> User -> SwaggerPetstoreRequest UpdateUser contentType res Source #

HasBodyParam

class HasBodyParam req param where Source #

Designates the body parameter of a request

Methods

setBodyParam :: forall contentType res. (Consumes req contentType, MimeRender contentType param) => SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res Source #

Instances

HasBodyParam UpdateUser User Source #

Body Param "body" - Updated user object

Methods

setBodyParam :: (Consumes UpdateUser contentType, MimeRender contentType User) => SwaggerPetstoreRequest UpdateUser contentType res -> User -> SwaggerPetstoreRequest UpdateUser contentType res Source #

HasBodyParam CreateUser User Source #

Body Param "body" - Created user object

Methods

setBodyParam :: (Consumes CreateUser contentType, MimeRender contentType User) => SwaggerPetstoreRequest CreateUser contentType res -> User -> SwaggerPetstoreRequest CreateUser contentType res Source #

HasBodyParam PlaceOrder Order Source #

Body Param "body" - order placed for purchasing the pet

Methods

setBodyParam :: (Consumes PlaceOrder contentType, MimeRender contentType Order) => SwaggerPetstoreRequest PlaceOrder contentType res -> Order -> SwaggerPetstoreRequest PlaceOrder contentType res Source #

HasBodyParam UpdatePet Pet Source #

Body Param "body" - Pet object that needs to be added to the store

Methods

setBodyParam :: (Consumes UpdatePet contentType, MimeRender contentType Pet) => SwaggerPetstoreRequest UpdatePet contentType res -> Pet -> SwaggerPetstoreRequest UpdatePet contentType res Source #

HasBodyParam AddPet Pet Source #

Body Param "body" - Pet object that needs to be added to the store

Methods

setBodyParam :: (Consumes AddPet contentType, MimeRender contentType Pet) => SwaggerPetstoreRequest AddPet contentType res -> Pet -> SwaggerPetstoreRequest AddPet contentType res Source #

HasBodyParam CreateUsersWithListInput [User] Source #

Body Param "body" - List of user object

HasBodyParam CreateUsersWithArrayInput [User] Source #

Body Param "body" - List of user object

HasOptionalParam

class HasOptionalParam req param where Source #

Designates the optional parameters of a request

Minimal complete definition

applyOptionalParam | (-&-)

Methods

applyOptionalParam :: SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res Source #

Apply an optional parameter to a request

(-&-) :: SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res infixl 2 Source #

infix operator / alias for addOptionalParam

Instances

HasOptionalParam UploadFile File Source #

Optional Param "file" - file to upload

HasOptionalParam UploadFile AdditionalMetadata Source #

Optional Param "additionalMetadata" - Additional data to pass to server

HasOptionalParam UpdatePetWithForm Status Source #

Optional Param "status" - Updated status of the pet

HasOptionalParam UpdatePetWithForm Name Source #

Optional Param "name" - Updated name of the pet

HasOptionalParam DeletePet ApiUnderscorekey Source # 

Optional Request Parameter Types

newtype Name Source #

Constructors

Name 

Fields

Instances

newtype Status Source #

Constructors

Status 

Fields

newtype File Source #

Constructors

File 

Fields

Instances

Eq File Source # 

Methods

(==) :: File -> File -> Bool #

(/=) :: File -> File -> Bool #

Show File Source # 

Methods

showsPrec :: Int -> File -> ShowS #

show :: File -> String #

showList :: [File] -> ShowS #

HasOptionalParam UploadFile File Source #

Optional Param "file" - file to upload

SwaggerPetstoreRequest

data SwaggerPetstoreRequest req contentType res Source #

Represents a request. The "req" type variable is the request type. The "res" type variable is the response type.

Constructors

SwaggerPetstoreRequest 

Fields

Instances

Show (SwaggerPetstoreRequest req contentType res) Source # 

Methods

showsPrec :: Int -> SwaggerPetstoreRequest req contentType res -> ShowS #

show :: SwaggerPetstoreRequest req contentType res -> String #

showList :: [SwaggerPetstoreRequest req contentType res] -> ShowS #

data Params Source #

Request Params

Instances

SwaggerPetstoreRequest Utils

_mkRequest Source #

Arguments

:: Method

Method

-> [ByteString]

Endpoint

-> SwaggerPetstoreRequest req contentType res

req: Request Type, res: Response Type

setHeader :: SwaggerPetstoreRequest req contentType res -> [Header] -> SwaggerPetstoreRequest req contentType res Source #

removeHeader :: SwaggerPetstoreRequest req contentType res -> [HeaderName] -> SwaggerPetstoreRequest req contentType res Source #

_setContentTypeHeader :: forall req contentType res. MimeType contentType => SwaggerPetstoreRequest req contentType res -> SwaggerPetstoreRequest req contentType res Source #

_setAcceptHeader :: forall req contentType res accept. MimeType accept => SwaggerPetstoreRequest req contentType res -> accept -> SwaggerPetstoreRequest req contentType res Source #

_setQuery :: SwaggerPetstoreRequest req contentType res -> [QueryItem] -> SwaggerPetstoreRequest req contentType res Source #

_addForm :: SwaggerPetstoreRequest req contentType res -> Form -> SwaggerPetstoreRequest req contentType res Source #

_addMultiFormPart :: SwaggerPetstoreRequest req contentType res -> Part -> SwaggerPetstoreRequest req contentType res Source #

_setBodyBS :: SwaggerPetstoreRequest req contentType res -> ByteString -> SwaggerPetstoreRequest req contentType res Source #

_setBodyLBS :: SwaggerPetstoreRequest req contentType res -> ByteString -> SwaggerPetstoreRequest req contentType res Source #

Params Utils

Swagger CollectionFormat Utils

data CollectionFormat Source #

Determines the format of the array if type array is used.

Constructors

CommaSeparated

CSV format for multiple parameters.

SpaceSeparated

Also called SSV

TabSeparated

Also called TSV

PipeSeparated

`value1|value2|value2`

MultiParamArray

Using multiple GET parameters, e.g. `foo=bar&foo=baz`. This is valid only for parameters in "query" (Query) or "formData" (Form)

_toColl :: Traversable f => CollectionFormat -> (f a -> [(b, ByteString)]) -> f [a] -> [(b, ByteString)] Source #

_toCollA :: (Traversable f, Traversable t, Alternative t) => CollectionFormat -> (f (t a) -> [(b, t ByteString)]) -> f (t [a]) -> [(b, t ByteString)] Source #

_toCollA' :: (Monoid c, Traversable f, Traversable t, Alternative t) => CollectionFormat -> (f (t a) -> [(b, t c)]) -> (Char -> c) -> f (t [a]) -> [(b, t c)] Source #

\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Client.html b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Client.html new file mode 100644 index 00000000000..5be560eab09 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Client.html @@ -0,0 +1,4 @@ +SwaggerPetstore.Client

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Safe HaskellNone
LanguageHaskell2010

SwaggerPetstore.Client

Description

 

Synopsis

Config

data SwaggerPetstoreConfig Source #

Constructors

SwaggerPetstoreConfig 

Fields

newConfig :: SwaggerPetstoreConfig Source #

constructs a default SwaggerPetstoreConfig

configHost:

http://petstore.swagger.io/v2

configUserAgent:

"swagger-haskell-http-client/1.0.0"

configExecLoggingT: runNullLoggingT

configLoggingFilter: infoLevelFilter

withStdoutLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig Source #

updates the config to use a MonadLogger instance which prints to stdout.

withStderrLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig Source #

updates the config to use a MonadLogger instance which prints to stderr.

withNoLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig Source #

updates the config to disable logging

Dispatch

Lbs

dispatchLbs Source #

Arguments

:: (Produces req accept, MimeType contentType) 
=> Manager

http-client Connection manager

-> SwaggerPetstoreConfig

config

-> SwaggerPetstoreRequest req contentType res

request

-> accept

"accept" MimeType

-> IO (Response ByteString)

response

send a request returning the raw http response

Mime

data MimeResult res Source #

pair of decoded http body and http response

Constructors

MimeResult 

Fields

Instances

Functor MimeResult Source # 

Methods

fmap :: (a -> b) -> MimeResult a -> MimeResult b #

(<$) :: a -> MimeResult b -> MimeResult a #

Foldable MimeResult Source # 

Methods

fold :: Monoid m => MimeResult m -> m #

foldMap :: Monoid m => (a -> m) -> MimeResult a -> m #

foldr :: (a -> b -> b) -> b -> MimeResult a -> b #

foldr' :: (a -> b -> b) -> b -> MimeResult a -> b #

foldl :: (b -> a -> b) -> b -> MimeResult a -> b #

foldl' :: (b -> a -> b) -> b -> MimeResult a -> b #

foldr1 :: (a -> a -> a) -> MimeResult a -> a #

foldl1 :: (a -> a -> a) -> MimeResult a -> a #

toList :: MimeResult a -> [a] #

null :: MimeResult a -> Bool #

length :: MimeResult a -> Int #

elem :: Eq a => a -> MimeResult a -> Bool #

maximum :: Ord a => MimeResult a -> a #

minimum :: Ord a => MimeResult a -> a #

sum :: Num a => MimeResult a -> a #

product :: Num a => MimeResult a -> a #

Traversable MimeResult Source # 

Methods

traverse :: Applicative f => (a -> f b) -> MimeResult a -> f (MimeResult b) #

sequenceA :: Applicative f => MimeResult (f a) -> f (MimeResult a) #

mapM :: Monad m => (a -> m b) -> MimeResult a -> m (MimeResult b) #

sequence :: Monad m => MimeResult (m a) -> m (MimeResult a) #

Show res => Show (MimeResult res) Source # 

Methods

showsPrec :: Int -> MimeResult res -> ShowS #

show :: MimeResult res -> String #

showList :: [MimeResult res] -> ShowS #

data MimeError Source #

pair of unrender/parser error and http response

Constructors

MimeError 

Fields

dispatchMime Source #

Arguments

:: (Produces req accept, MimeUnrender accept res, MimeType contentType) 
=> Manager

http-client Connection manager

-> SwaggerPetstoreConfig

config

-> SwaggerPetstoreRequest req contentType res

request

-> accept

"accept" MimeType

-> IO (MimeResult res)

response

send a request returning the MimeResult

dispatchMime' Source #

Arguments

:: (Produces req accept, MimeUnrender accept res, MimeType contentType) 
=> Manager

http-client Connection manager

-> SwaggerPetstoreConfig

config

-> SwaggerPetstoreRequest req contentType res

request

-> accept

"accept" MimeType

-> IO (Either MimeError res)

response

like dispatchMime, but only returns the decoded http body

Unsafe

dispatchLbsUnsafe Source #

Arguments

:: (MimeType accept, MimeType contentType) 
=> Manager

http-client Connection manager

-> SwaggerPetstoreConfig

config

-> SwaggerPetstoreRequest req contentType res

request

-> accept

"accept" MimeType

-> IO (Response ByteString)

response

like dispatchReqLbs, but does not validate the operation is a Producer of the "accept" MimeType. (Useful if the server's response is undocumented)

dispatchInitUnsafe Source #

Arguments

:: Manager

http-client Connection manager

-> SwaggerPetstoreConfig

config

-> InitRequest req contentType res accept

init request

-> IO (Response ByteString)

response

dispatch an InitRequest

InitRequest

newtype InitRequest req contentType res accept Source #

wraps an http-client Request with request/response type parameters

Constructors

InitRequest 

Instances

Show (InitRequest req contentType res accept) Source # 

Methods

showsPrec :: Int -> InitRequest req contentType res accept -> ShowS #

show :: InitRequest req contentType res accept -> String #

showList :: [InitRequest req contentType res accept] -> ShowS #

_toInitRequest Source #

Arguments

:: (MimeType accept, MimeType contentType) 
=> SwaggerPetstoreConfig

config

-> SwaggerPetstoreRequest req contentType res

request

-> accept

"accept" MimeType

-> IO (InitRequest req contentType res accept)

initialized request

Build an http-client Request record from the supplied config and request

modifyInitRequest :: InitRequest req contentType res accept -> (Request -> Request) -> InitRequest req contentType res accept Source #

modify the underlying Request

modifyInitRequestM :: Monad m => InitRequest req contentType res accept -> (Request -> m Request) -> m (InitRequest req contentType res accept) Source #

modify the underlying Request (monadic)

Logging

type ExecLoggingT = forall m. MonadIO m => forall a. LoggingT m a -> m a Source #

A block using a MonadLogger instance

Null Logger

nullLogger :: Loc -> LogSource -> LogLevel -> LogStr -> IO () Source #

a logger which disables logging

runNullLoggingT :: LoggingT m a -> m a Source #

run the monad transformer that disables logging

Logging Filters

errorLevelFilter :: LogSource -> LogLevel -> Bool Source #

a log filter that uses LevelError as the minimum logging level

infoLevelFilter :: LogSource -> LogLevel -> Bool Source #

a log filter that uses LevelInfo as the minimum logging level

debugLevelFilter :: LogSource -> LogLevel -> Bool Source #

a log filter that uses LevelDebug as the minimum logging level

Logging

logNST :: (MonadIO m, MonadLogger m) => LogLevel -> Text -> Text -> m () Source #

Log a message using the current time

logExceptions :: (MonadLogger m, MonadCatch m, MonadIO m) => Text -> m a -> m a Source #

re-throws exceptions after logging them

runLoggingT :: SwaggerPetstoreConfig -> ExecLoggingT Source #

Run a block using the configured MonadLogger instance

runExceptionLoggingT :: (MonadCatch m, MonadIO m) => Text -> SwaggerPetstoreConfig -> LoggingT m a -> m a Source #

Run a block using the configured MonadLogger instance (logs exceptions)

\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Lens.html b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Lens.html new file mode 100644 index 00000000000..483f5a824b7 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Lens.html @@ -0,0 +1,4 @@ +SwaggerPetstore.Lens

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Safe HaskellNone
LanguageHaskell2010

SwaggerPetstore.Lens

Description

 

Type Aliases

type Traversal_' s a = Traversal_ s s a a Source #

type Traversal_ s t a b = forall f. Applicative f => (a -> f b) -> s -> f t Source #

type Lens_' s a = Lens_ s s a a Source #

type Lens_ s t a b = forall f. Functor f => (a -> f b) -> s -> f t Source #

ApiResponse

Category

Order

Pet

Tag

User

Helpers

_mtraversal :: Applicative f => (b -> Maybe t) -> (a -> b) -> (t -> f a) -> b -> f b Source #

\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-MimeTypes.html b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-MimeTypes.html new file mode 100644 index 00000000000..d34081fce73 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-MimeTypes.html @@ -0,0 +1,4 @@ +SwaggerPetstore.MimeTypes

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Safe HaskellNone
LanguageHaskell2010

SwaggerPetstore.MimeTypes

Description

 

Synopsis

Content Negotiation

Mime Types

data MimeJSON Source #

Constructors

MimeJSON 

Instances

MimeType MimeJSON Source #
application/json
Produces UpdateUser MimeJSON Source #
application/json
Produces LogoutUser MimeJSON Source #
application/json
Produces LoginUser MimeJSON Source #
application/json
Produces GetUserByName MimeJSON Source #
application/json
Produces DeleteUser MimeJSON Source #
application/json
Produces CreateUsersWithListInput MimeJSON Source #
application/json
Produces CreateUsersWithArrayInput MimeJSON Source #
application/json
Produces CreateUser MimeJSON Source #
application/json
Produces PlaceOrder MimeJSON Source #
application/json
Produces GetOrderById MimeJSON Source #
application/json
Produces GetInventory MimeJSON Source #
application/json
Produces DeleteOrder MimeJSON Source #
application/json
Produces UploadFile MimeJSON Source #
application/json
Produces UpdatePetWithForm MimeJSON Source #
application/json
Produces UpdatePet MimeJSON Source #
application/json
Produces GetPetById MimeJSON Source #
application/json
Produces FindPetsByTags MimeJSON Source #
application/json
Produces FindPetsByStatus MimeJSON Source #
application/json
Produces DeletePet MimeJSON Source #
application/json
Produces AddPet MimeJSON Source #
application/json
Consumes UpdatePet MimeJSON Source #
application/json
Consumes AddPet MimeJSON Source #
application/json
FromJSON a => MimeUnrender MimeJSON a Source #
A.eitherDecode
ToJSON a => MimeRender MimeJSON a Source #

encode

data MimePlainText Source #

Constructors

MimePlainText 

Instances

MimeType MimePlainText Source #
text/plain;charset=utf-8
MimeUnrender MimePlainText ByteString Source #
P.Right . P.id
MimeUnrender MimePlainText String Source #
P.Right . BCL.unpack
MimeUnrender MimePlainText Text Source #
P.left P.show . TL.decodeUtf8'
MimeRender MimePlainText ByteString Source #
P.id
MimeRender MimePlainText String Source #
BCL.pack
MimeRender MimePlainText Text Source #
BL.fromStrict . T.encodeUtf8

data MimeOctetStream Source #

Constructors

MimeOctetStream 

Instances

MimeType MimeOctetStream Source # 
MimeUnrender MimeOctetStream ByteString Source #
P.Right . P.id
MimeUnrender MimeOctetStream String Source #
P.Right . BCL.unpack
MimeUnrender MimeOctetStream Text Source #
P.left P.show . T.decodeUtf8' . BL.toStrict
MimeRender MimeOctetStream ByteString Source #
P.id
MimeRender MimeOctetStream String Source #
BCL.pack
MimeRender MimeOctetStream Text Source #
BL.fromStrict . T.encodeUtf8

MimeType Class

class Typeable mtype => MimeType mtype where Source #

Minimal complete definition

mimeType | mimeTypes

Instances

MimeType MimeNoContent Source # 
MimeType MimeOctetStream Source # 
MimeType MimeMultipartFormData Source #
multipart/form-data
MimeType MimeFormUrlEncoded Source #
application/x-www-form-urlencoded
MimeType MimePlainText Source #
text/plain;charset=utf-8
MimeType MimeXML Source #
application/xml
MimeType MimeJSON Source #
application/json

MimeType Instances

MimeRender Class

class MimeType mtype => MimeRender mtype x where Source #

Minimal complete definition

mimeRender

Methods

mimeRender :: Proxy mtype -> x -> ByteString Source #

mimeRender' :: mtype -> x -> ByteString Source #

Instances

MimeRender MimeNoContent NoContent Source #
P.Right . P.const NoContent
MimeRender MimeOctetStream ByteString Source #
P.id
MimeRender MimeOctetStream String Source #
BCL.pack
MimeRender MimeOctetStream Text Source #
BL.fromStrict . T.encodeUtf8
MimeRender MimeMultipartFormData ByteString Source #
P.id
MimeRender MimeMultipartFormData String Source #
BCL.pack
MimeRender MimeMultipartFormData Text Source #
BL.fromStrict . T.encodeUtf8
ToForm a => MimeRender MimeFormUrlEncoded a Source #
WH.urlEncodeAsForm
MimeRender MimePlainText ByteString Source #
P.id
MimeRender MimePlainText String Source #
BCL.pack
MimeRender MimePlainText Text Source #
BL.fromStrict . T.encodeUtf8
ToJSON a => MimeRender MimeJSON a Source #

encode

MimeRender Instances

MimeUnrender Class

class MimeType mtype => MimeUnrender mtype o where Source #

Minimal complete definition

mimeUnrender

Instances

MimeUnrender MimeNoContent NoContent Source #
P.Right . P.const NoContent
MimeUnrender MimeOctetStream ByteString Source #
P.Right . P.id
MimeUnrender MimeOctetStream String Source #
P.Right . BCL.unpack
MimeUnrender MimeOctetStream Text Source #
P.left P.show . T.decodeUtf8' . BL.toStrict
FromForm a => MimeUnrender MimeFormUrlEncoded a Source #
P.left T.unpack . WH.urlDecodeAsForm
MimeUnrender MimePlainText ByteString Source #
P.Right . P.id
MimeUnrender MimePlainText String Source #
P.Right . BCL.unpack
MimeUnrender MimePlainText Text Source #
P.left P.show . TL.decodeUtf8'
FromJSON a => MimeUnrender MimeJSON a Source #
A.eitherDecode

MimeUnrender Instances

Request Consumes

class MimeType mtype => Consumes req mtype Source #

Instances

Consumes UploadFile MimeMultipartFormData Source #
multipart/form-data
Consumes UpdatePetWithForm MimeFormUrlEncoded Source #
application/x-www-form-urlencoded
Consumes UpdatePet MimeXML Source #
application/xml
Consumes UpdatePet MimeJSON Source #
application/json
Consumes AddPet MimeXML Source #
application/xml
Consumes AddPet MimeJSON Source #
application/json

Request Produces

class MimeType mtype => Produces req mtype Source #

Instances

Produces UpdateUser MimeXML Source #
application/xml
Produces UpdateUser MimeJSON Source #
application/json
Produces LogoutUser MimeXML Source #
application/xml
Produces LogoutUser MimeJSON Source #
application/json
Produces LoginUser MimeXML Source #
application/xml
Produces LoginUser MimeJSON Source #
application/json
Produces GetUserByName MimeXML Source #
application/xml
Produces GetUserByName MimeJSON Source #
application/json
Produces DeleteUser MimeXML Source #
application/xml
Produces DeleteUser MimeJSON Source #
application/json
Produces CreateUsersWithListInput MimeXML Source #
application/xml
Produces CreateUsersWithListInput MimeJSON Source #
application/json
Produces CreateUsersWithArrayInput MimeXML Source #
application/xml
Produces CreateUsersWithArrayInput MimeJSON Source #
application/json
Produces CreateUser MimeXML Source #
application/xml
Produces CreateUser MimeJSON Source #
application/json
Produces PlaceOrder MimeXML Source #
application/xml
Produces PlaceOrder MimeJSON Source #
application/json
Produces GetOrderById MimeXML Source #
application/xml
Produces GetOrderById MimeJSON Source #
application/json
Produces GetInventory MimeJSON Source #
application/json
Produces DeleteOrder MimeXML Source #
application/xml
Produces DeleteOrder MimeJSON Source #
application/json
Produces UploadFile MimeJSON Source #
application/json
Produces UpdatePetWithForm MimeXML Source #
application/xml
Produces UpdatePetWithForm MimeJSON Source #
application/json
Produces UpdatePet MimeXML Source #
application/xml
Produces UpdatePet MimeJSON Source #
application/json
Produces GetPetById MimeXML Source #
application/xml
Produces GetPetById MimeJSON Source #
application/json
Produces FindPetsByTags MimeXML Source #
application/xml
Produces FindPetsByTags MimeJSON Source #
application/json
Produces FindPetsByStatus MimeXML Source #
application/xml
Produces FindPetsByStatus MimeJSON Source #
application/json
Produces DeletePet MimeXML Source #
application/xml
Produces DeletePet MimeJSON Source #
application/json
Produces AddPet MimeXML Source #
application/xml
Produces AddPet MimeJSON Source #
application/json
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Model.html b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Model.html new file mode 100644 index 00000000000..2a177e5595d --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore-Model.html @@ -0,0 +1,4 @@ +SwaggerPetstore.Model

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Safe HaskellNone
LanguageHaskell2010

SwaggerPetstore.Model

Description

 

Models

ApiResponse

mkApiResponse :: ApiResponse Source #

Construct a value of type ApiResponse (by applying it's required fields, if any)

Category

mkCategory :: Category Source #

Construct a value of type Category (by applying it's required fields, if any)

Order

data Order Source #

Pet Order

An order for a pets from the pet store

Constructors

Order 

Fields

Instances

Eq Order Source # 

Methods

(==) :: Order -> Order -> Bool #

(/=) :: Order -> Order -> Bool #

Show Order Source # 

Methods

showsPrec :: Int -> Order -> ShowS #

show :: Order -> String #

showList :: [Order] -> ShowS #

ToJSON Order Source # 
FromJSON Order Source # 
HasBodyParam PlaceOrder Order Source #

Body Param "body" - order placed for purchasing the pet

Methods

setBodyParam :: (Consumes PlaceOrder contentType, MimeRender contentType Order) => SwaggerPetstoreRequest PlaceOrder contentType res -> Order -> SwaggerPetstoreRequest PlaceOrder contentType res Source #

mkOrder :: Order Source #

Construct a value of type Order (by applying it's required fields, if any)

Pet

data Pet Source #

a Pet

A pet for sale in the pet store

Constructors

Pet 

Fields

Instances

Eq Pet Source # 

Methods

(==) :: Pet -> Pet -> Bool #

(/=) :: Pet -> Pet -> Bool #

Show Pet Source # 

Methods

showsPrec :: Int -> Pet -> ShowS #

show :: Pet -> String #

showList :: [Pet] -> ShowS #

ToJSON Pet Source # 
FromJSON Pet Source # 
HasBodyParam UpdatePet Pet Source #

Body Param "body" - Pet object that needs to be added to the store

Methods

setBodyParam :: (Consumes UpdatePet contentType, MimeRender contentType Pet) => SwaggerPetstoreRequest UpdatePet contentType res -> Pet -> SwaggerPetstoreRequest UpdatePet contentType res Source #

HasBodyParam AddPet Pet Source #

Body Param "body" - Pet object that needs to be added to the store

Methods

setBodyParam :: (Consumes AddPet contentType, MimeRender contentType Pet) => SwaggerPetstoreRequest AddPet contentType res -> Pet -> SwaggerPetstoreRequest AddPet contentType res Source #

mkPet Source #

Arguments

:: Text

petName

-> [Text]

petPhotoUrls

-> Pet 

Construct a value of type Pet (by applying it's required fields, if any)

Tag

data Tag Source #

Pet Tag

A tag for a pet

Constructors

Tag 

Fields

mkTag :: Tag Source #

Construct a value of type Tag (by applying it's required fields, if any)

User

data User Source #

a User

A User who is purchasing from the pet store

Constructors

User 

Fields

Instances

Eq User Source # 

Methods

(==) :: User -> User -> Bool #

(/=) :: User -> User -> Bool #

Show User Source # 

Methods

showsPrec :: Int -> User -> ShowS #

show :: User -> String #

showList :: [User] -> ShowS #

ToJSON User Source # 
FromJSON User Source # 
HasBodyParam UpdateUser User Source #

Body Param "body" - Updated user object

Methods

setBodyParam :: (Consumes UpdateUser contentType, MimeRender contentType User) => SwaggerPetstoreRequest UpdateUser contentType res -> User -> SwaggerPetstoreRequest UpdateUser contentType res Source #

HasBodyParam CreateUser User Source #

Body Param "body" - Created user object

Methods

setBodyParam :: (Consumes CreateUser contentType, MimeRender contentType User) => SwaggerPetstoreRequest CreateUser contentType res -> User -> SwaggerPetstoreRequest CreateUser contentType res Source #

HasBodyParam CreateUsersWithListInput [User] Source #

Body Param "body" - List of user object

HasBodyParam CreateUsersWithArrayInput [User] Source #

Body Param "body" - List of user object

mkUser :: User Source #

Construct a value of type User (by applying it's required fields, if any)

Utils

_omitNulls :: [(Text, Value)] -> Value Source #

Removes Null fields. (OpenAPI-Specification 2.0 does not allow Null in JSON)

_toFormItem :: (ToHttpApiData a, Functor f) => t -> f a -> f (t, [Text]) Source #

DateTime Formatting

_readDateTime :: (ParseTime t, Monad m, Alternative m) => String -> m t Source #

_parseISO8601

_showDateTime :: (t ~ UTCTime, FormatTime t) => t -> String Source #

TI.formatISO8601Millis

Date Formatting

_readDate :: (ParseTime t, Monad m) => String -> m t Source #

TI.parseTimeM True TI.defaultTimeLocale ""

_showDate :: FormatTime t => t -> String Source #

TI.formatTime TI.defaultTimeLocale ""
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore.html b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore.html new file mode 100644 index 00000000000..6ae120a6311 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/SwaggerPetstore.html @@ -0,0 +1,4 @@ +SwaggerPetstore

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Safe HaskellNone
LanguageHaskell2010

SwaggerPetstore

Description

 
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-45.html b/samples/client/petstore/haskell-http-client/docs/doc-index-45.html new file mode 100644 index 00000000000..bc2e69901ea --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-45.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - -)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - -

-&-SwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-95.html b/samples/client/petstore/haskell-http-client/docs/doc-index-95.html new file mode 100644 index 00000000000..33974e19019 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-95.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - _)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - _

_addFormSwaggerPetstore.API, SwaggerPetstore
_addMultiFormPartSwaggerPetstore.API, SwaggerPetstore
_emptyToNothingSwaggerPetstore.Model, SwaggerPetstore
_memptyToNothingSwaggerPetstore.Model, SwaggerPetstore
_mkParamsSwaggerPetstore.API, SwaggerPetstore
_mkRequestSwaggerPetstore.API, SwaggerPetstore
_mtraversalSwaggerPetstore.Lens, SwaggerPetstore
_omitNullsSwaggerPetstore.Model, SwaggerPetstore
_parseISO8601SwaggerPetstore.Model, SwaggerPetstore
_readDateSwaggerPetstore.Model, SwaggerPetstore
_readDateTimeSwaggerPetstore.Model, SwaggerPetstore
_setAcceptHeaderSwaggerPetstore.API, SwaggerPetstore
_setBodyBSSwaggerPetstore.API, SwaggerPetstore
_setBodyLBSSwaggerPetstore.API, SwaggerPetstore
_setContentTypeHeaderSwaggerPetstore.API, SwaggerPetstore
_setQuerySwaggerPetstore.API, SwaggerPetstore
_showDateSwaggerPetstore.Model, SwaggerPetstore
_showDateTimeSwaggerPetstore.Model, SwaggerPetstore
_toCollSwaggerPetstore.API, SwaggerPetstore
_toCollASwaggerPetstore.API, SwaggerPetstore
_toCollA'SwaggerPetstore.API, SwaggerPetstore
_toFormItemSwaggerPetstore.Model, SwaggerPetstore
_toInitRequestSwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-A.html b/samples/client/petstore/haskell-http-client/docs/doc-index-A.html new file mode 100644 index 00000000000..8787e590900 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-A.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - A)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - A

AdditionalMetadata 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
AddPetSwaggerPetstore.API, SwaggerPetstore
addPetSwaggerPetstore.API, SwaggerPetstore
ApiResponse 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
apiResponseCodeSwaggerPetstore.Model, SwaggerPetstore
apiResponseCodeTSwaggerPetstore.Lens, SwaggerPetstore
apiResponseMessageSwaggerPetstore.Model, SwaggerPetstore
apiResponseMessageTSwaggerPetstore.Lens, SwaggerPetstore
apiResponseTypeSwaggerPetstore.Model, SwaggerPetstore
apiResponseTypeTSwaggerPetstore.Lens, SwaggerPetstore
ApiUnderscorekey 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
applyOptionalParamSwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-All.html b/samples/client/petstore/haskell-http-client/docs/doc-index-All.html new file mode 100644 index 00000000000..cce57dec8d6 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-All.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index

-&-SwaggerPetstore.API, SwaggerPetstore
AdditionalMetadata 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
AddPetSwaggerPetstore.API, SwaggerPetstore
addPetSwaggerPetstore.API, SwaggerPetstore
ApiResponse 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
apiResponseCodeSwaggerPetstore.Model, SwaggerPetstore
apiResponseCodeTSwaggerPetstore.Lens, SwaggerPetstore
apiResponseMessageSwaggerPetstore.Model, SwaggerPetstore
apiResponseMessageTSwaggerPetstore.Lens, SwaggerPetstore
apiResponseTypeSwaggerPetstore.Model, SwaggerPetstore
apiResponseTypeTSwaggerPetstore.Lens, SwaggerPetstore
ApiUnderscorekey 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
applyOptionalParamSwaggerPetstore.API, SwaggerPetstore
Category 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
categoryIdSwaggerPetstore.Model, SwaggerPetstore
categoryIdTSwaggerPetstore.Lens, SwaggerPetstore
categoryNameSwaggerPetstore.Model, SwaggerPetstore
categoryNameTSwaggerPetstore.Lens, SwaggerPetstore
CollectionFormatSwaggerPetstore.API, SwaggerPetstore
CommaSeparatedSwaggerPetstore.API, SwaggerPetstore
configExecLoggingTSwaggerPetstore.Client, SwaggerPetstore
configHostSwaggerPetstore.Client, SwaggerPetstore
configLoggingFilterSwaggerPetstore.Client, SwaggerPetstore
configUserAgentSwaggerPetstore.Client, SwaggerPetstore
ConsumesSwaggerPetstore.MimeTypes, SwaggerPetstore
CreateUserSwaggerPetstore.API, SwaggerPetstore
createUserSwaggerPetstore.API, SwaggerPetstore
CreateUsersWithArrayInputSwaggerPetstore.API, SwaggerPetstore
createUsersWithArrayInputSwaggerPetstore.API, SwaggerPetstore
CreateUsersWithListInputSwaggerPetstore.API, SwaggerPetstore
createUsersWithListInputSwaggerPetstore.API, SwaggerPetstore
debugLevelFilterSwaggerPetstore.Client, SwaggerPetstore
DeleteOrderSwaggerPetstore.API, SwaggerPetstore
deleteOrderSwaggerPetstore.API, SwaggerPetstore
DeletePetSwaggerPetstore.API, SwaggerPetstore
deletePetSwaggerPetstore.API, SwaggerPetstore
DeleteUserSwaggerPetstore.API, SwaggerPetstore
deleteUserSwaggerPetstore.API, SwaggerPetstore
dispatchInitUnsafeSwaggerPetstore.Client, SwaggerPetstore
dispatchLbsSwaggerPetstore.Client, SwaggerPetstore
dispatchLbsUnsafeSwaggerPetstore.Client, SwaggerPetstore
dispatchMimeSwaggerPetstore.Client, SwaggerPetstore
dispatchMime'SwaggerPetstore.Client, SwaggerPetstore
errorLevelFilterSwaggerPetstore.Client, SwaggerPetstore
ExecLoggingTSwaggerPetstore.Client, SwaggerPetstore
File 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
FindPetsByStatusSwaggerPetstore.API, SwaggerPetstore
findPetsByStatusSwaggerPetstore.API, SwaggerPetstore
FindPetsByTagsSwaggerPetstore.API, SwaggerPetstore
findPetsByTagsSwaggerPetstore.API, SwaggerPetstore
GetInventorySwaggerPetstore.API, SwaggerPetstore
getInventorySwaggerPetstore.API, SwaggerPetstore
GetOrderByIdSwaggerPetstore.API, SwaggerPetstore
getOrderByIdSwaggerPetstore.API, SwaggerPetstore
GetPetByIdSwaggerPetstore.API, SwaggerPetstore
getPetByIdSwaggerPetstore.API, SwaggerPetstore
GetUserByNameSwaggerPetstore.API, SwaggerPetstore
getUserByNameSwaggerPetstore.API, SwaggerPetstore
HasBodyParamSwaggerPetstore.API, SwaggerPetstore
HasOptionalParamSwaggerPetstore.API, SwaggerPetstore
infoLevelFilterSwaggerPetstore.Client, SwaggerPetstore
InitRequest 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
Lens_SwaggerPetstore.Lens, SwaggerPetstore
Lens_'SwaggerPetstore.Lens, SwaggerPetstore
logExceptionsSwaggerPetstore.Client, SwaggerPetstore
LoginUserSwaggerPetstore.API, SwaggerPetstore
loginUserSwaggerPetstore.API, SwaggerPetstore
logNSTSwaggerPetstore.Client, SwaggerPetstore
LogoutUserSwaggerPetstore.API, SwaggerPetstore
logoutUserSwaggerPetstore.API, SwaggerPetstore
MimeError 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
mimeErrorSwaggerPetstore.Client, SwaggerPetstore
mimeErrorResponseSwaggerPetstore.Client, SwaggerPetstore
MimeFormUrlEncoded 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeJSON 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeMultipartFormData 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeNoContent 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeOctetStream 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimePlainText 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeRenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeRenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeRender'SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeResult 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
mimeResultSwaggerPetstore.Client, SwaggerPetstore
mimeResultResponseSwaggerPetstore.Client, SwaggerPetstore
MimeTypeSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeTypeSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeType'SwaggerPetstore.MimeTypes, SwaggerPetstore
mimeTypesSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeTypes'SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeUnrenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeUnrenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeUnrender'SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeXML 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
minLevelFilterSwaggerPetstore.Client, SwaggerPetstore
mkApiResponseSwaggerPetstore.Model, SwaggerPetstore
mkCategorySwaggerPetstore.Model, SwaggerPetstore
mkOrderSwaggerPetstore.Model, SwaggerPetstore
mkPetSwaggerPetstore.Model, SwaggerPetstore
mkTagSwaggerPetstore.Model, SwaggerPetstore
mkUserSwaggerPetstore.Model, SwaggerPetstore
modifyInitRequestSwaggerPetstore.Client, SwaggerPetstore
modifyInitRequestMSwaggerPetstore.Client, SwaggerPetstore
MultiParamArraySwaggerPetstore.API, SwaggerPetstore
Name 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
newConfigSwaggerPetstore.Client, SwaggerPetstore
NoContent 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
nullLoggerSwaggerPetstore.Client, SwaggerPetstore
Order 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
orderCompleteSwaggerPetstore.Model, SwaggerPetstore
orderCompleteTSwaggerPetstore.Lens, SwaggerPetstore
orderIdSwaggerPetstore.Model, SwaggerPetstore
orderIdTSwaggerPetstore.Lens, SwaggerPetstore
orderPetIdSwaggerPetstore.Model, SwaggerPetstore
orderPetIdTSwaggerPetstore.Lens, SwaggerPetstore
orderQuantitySwaggerPetstore.Model, SwaggerPetstore
orderQuantityTSwaggerPetstore.Lens, SwaggerPetstore
orderShipDateSwaggerPetstore.Model, SwaggerPetstore
orderShipDateTSwaggerPetstore.Lens, SwaggerPetstore
orderStatusSwaggerPetstore.Model, SwaggerPetstore
orderStatusTSwaggerPetstore.Lens, SwaggerPetstore
ParamBodySwaggerPetstore.API, SwaggerPetstore
ParamBodyBSwaggerPetstore.API, SwaggerPetstore
ParamBodyBLSwaggerPetstore.API, SwaggerPetstore
ParamBodyFormUrlEncodedSwaggerPetstore.API, SwaggerPetstore
ParamBodyMultipartFormDataSwaggerPetstore.API, SwaggerPetstore
ParamBodyNoneSwaggerPetstore.API, SwaggerPetstore
Params 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
paramsSwaggerPetstore.API, SwaggerPetstore
paramsBodySwaggerPetstore.API, SwaggerPetstore
paramsHeadersSwaggerPetstore.API, SwaggerPetstore
paramsQuerySwaggerPetstore.API, SwaggerPetstore
Pet 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
petCategorySwaggerPetstore.Model, SwaggerPetstore
petCategoryTSwaggerPetstore.Lens, SwaggerPetstore
petIdSwaggerPetstore.Model, SwaggerPetstore
petIdTSwaggerPetstore.Lens, SwaggerPetstore
petNameSwaggerPetstore.Model, SwaggerPetstore
petNameLSwaggerPetstore.Lens, SwaggerPetstore
petPhotoUrlsSwaggerPetstore.Model, SwaggerPetstore
petPhotoUrlsLSwaggerPetstore.Lens, SwaggerPetstore
petStatusSwaggerPetstore.Model, SwaggerPetstore
petStatusTSwaggerPetstore.Lens, SwaggerPetstore
petTagsSwaggerPetstore.Model, SwaggerPetstore
petTagsTSwaggerPetstore.Lens, SwaggerPetstore
PipeSeparatedSwaggerPetstore.API, SwaggerPetstore
PlaceOrderSwaggerPetstore.API, SwaggerPetstore
placeOrderSwaggerPetstore.API, SwaggerPetstore
ProducesSwaggerPetstore.MimeTypes, SwaggerPetstore
removeHeaderSwaggerPetstore.API, SwaggerPetstore
rMethodSwaggerPetstore.API, SwaggerPetstore
runExceptionLoggingTSwaggerPetstore.Client, SwaggerPetstore
runLoggingTSwaggerPetstore.Client, SwaggerPetstore
runNullLoggingTSwaggerPetstore.Client, SwaggerPetstore
setBodyParamSwaggerPetstore.API, SwaggerPetstore
setHeaderSwaggerPetstore.API, SwaggerPetstore
SpaceSeparatedSwaggerPetstore.API, SwaggerPetstore
Status 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
SwaggerPetstoreConfig 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
SwaggerPetstoreRequest 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
TabSeparatedSwaggerPetstore.API, SwaggerPetstore
Tag 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
tagIdSwaggerPetstore.Model, SwaggerPetstore
tagIdTSwaggerPetstore.Lens, SwaggerPetstore
tagNameSwaggerPetstore.Model, SwaggerPetstore
tagNameTSwaggerPetstore.Lens, SwaggerPetstore
toFormSwaggerPetstore.API, SwaggerPetstore
toFormCollSwaggerPetstore.API, SwaggerPetstore
toHeaderSwaggerPetstore.API, SwaggerPetstore
toHeaderCollSwaggerPetstore.API, SwaggerPetstore
toPathSwaggerPetstore.API, SwaggerPetstore
toQuerySwaggerPetstore.API, SwaggerPetstore
toQueryCollSwaggerPetstore.API, SwaggerPetstore
Traversal_SwaggerPetstore.Lens, SwaggerPetstore
Traversal_'SwaggerPetstore.Lens, SwaggerPetstore
unAdditionalMetadataSwaggerPetstore.API, SwaggerPetstore
unApiUnderscorekeySwaggerPetstore.API, SwaggerPetstore
unFileSwaggerPetstore.API, SwaggerPetstore
unInitRequestSwaggerPetstore.Client, SwaggerPetstore
unNameSwaggerPetstore.API, SwaggerPetstore
unStatusSwaggerPetstore.API, SwaggerPetstore
UpdatePetSwaggerPetstore.API, SwaggerPetstore
updatePetSwaggerPetstore.API, SwaggerPetstore
UpdatePetWithFormSwaggerPetstore.API, SwaggerPetstore
updatePetWithFormSwaggerPetstore.API, SwaggerPetstore
UpdateUserSwaggerPetstore.API, SwaggerPetstore
updateUserSwaggerPetstore.API, SwaggerPetstore
UploadFileSwaggerPetstore.API, SwaggerPetstore
uploadFileSwaggerPetstore.API, SwaggerPetstore
urlPathSwaggerPetstore.API, SwaggerPetstore
User 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
userEmailSwaggerPetstore.Model, SwaggerPetstore
userEmailTSwaggerPetstore.Lens, SwaggerPetstore
userFirstNameSwaggerPetstore.Model, SwaggerPetstore
userFirstNameTSwaggerPetstore.Lens, SwaggerPetstore
userIdSwaggerPetstore.Model, SwaggerPetstore
userIdTSwaggerPetstore.Lens, SwaggerPetstore
userLastNameSwaggerPetstore.Model, SwaggerPetstore
userLastNameTSwaggerPetstore.Lens, SwaggerPetstore
userPasswordSwaggerPetstore.Model, SwaggerPetstore
userPasswordTSwaggerPetstore.Lens, SwaggerPetstore
userPhoneSwaggerPetstore.Model, SwaggerPetstore
userPhoneTSwaggerPetstore.Lens, SwaggerPetstore
userUsernameSwaggerPetstore.Model, SwaggerPetstore
userUsernameTSwaggerPetstore.Lens, SwaggerPetstore
userUserStatusSwaggerPetstore.Model, SwaggerPetstore
userUserStatusTSwaggerPetstore.Lens, SwaggerPetstore
withNoLoggingSwaggerPetstore.Client, SwaggerPetstore
withStderrLoggingSwaggerPetstore.Client, SwaggerPetstore
withStdoutLoggingSwaggerPetstore.Client, SwaggerPetstore
_addFormSwaggerPetstore.API, SwaggerPetstore
_addMultiFormPartSwaggerPetstore.API, SwaggerPetstore
_emptyToNothingSwaggerPetstore.Model, SwaggerPetstore
_memptyToNothingSwaggerPetstore.Model, SwaggerPetstore
_mkParamsSwaggerPetstore.API, SwaggerPetstore
_mkRequestSwaggerPetstore.API, SwaggerPetstore
_mtraversalSwaggerPetstore.Lens, SwaggerPetstore
_omitNullsSwaggerPetstore.Model, SwaggerPetstore
_parseISO8601SwaggerPetstore.Model, SwaggerPetstore
_readDateSwaggerPetstore.Model, SwaggerPetstore
_readDateTimeSwaggerPetstore.Model, SwaggerPetstore
_setAcceptHeaderSwaggerPetstore.API, SwaggerPetstore
_setBodyBSSwaggerPetstore.API, SwaggerPetstore
_setBodyLBSSwaggerPetstore.API, SwaggerPetstore
_setContentTypeHeaderSwaggerPetstore.API, SwaggerPetstore
_setQuerySwaggerPetstore.API, SwaggerPetstore
_showDateSwaggerPetstore.Model, SwaggerPetstore
_showDateTimeSwaggerPetstore.Model, SwaggerPetstore
_toCollSwaggerPetstore.API, SwaggerPetstore
_toCollASwaggerPetstore.API, SwaggerPetstore
_toCollA'SwaggerPetstore.API, SwaggerPetstore
_toFormItemSwaggerPetstore.Model, SwaggerPetstore
_toInitRequestSwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-C.html b/samples/client/petstore/haskell-http-client/docs/doc-index-C.html new file mode 100644 index 00000000000..e9a866aaaba --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-C.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - C)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - C

Category 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
categoryIdSwaggerPetstore.Model, SwaggerPetstore
categoryIdTSwaggerPetstore.Lens, SwaggerPetstore
categoryNameSwaggerPetstore.Model, SwaggerPetstore
categoryNameTSwaggerPetstore.Lens, SwaggerPetstore
CollectionFormatSwaggerPetstore.API, SwaggerPetstore
CommaSeparatedSwaggerPetstore.API, SwaggerPetstore
configExecLoggingTSwaggerPetstore.Client, SwaggerPetstore
configHostSwaggerPetstore.Client, SwaggerPetstore
configLoggingFilterSwaggerPetstore.Client, SwaggerPetstore
configUserAgentSwaggerPetstore.Client, SwaggerPetstore
ConsumesSwaggerPetstore.MimeTypes, SwaggerPetstore
CreateUserSwaggerPetstore.API, SwaggerPetstore
createUserSwaggerPetstore.API, SwaggerPetstore
CreateUsersWithArrayInputSwaggerPetstore.API, SwaggerPetstore
createUsersWithArrayInputSwaggerPetstore.API, SwaggerPetstore
CreateUsersWithListInputSwaggerPetstore.API, SwaggerPetstore
createUsersWithListInputSwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-D.html b/samples/client/petstore/haskell-http-client/docs/doc-index-D.html new file mode 100644 index 00000000000..b2d4af4309e --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-D.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - D)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - D

debugLevelFilterSwaggerPetstore.Client, SwaggerPetstore
DeleteOrderSwaggerPetstore.API, SwaggerPetstore
deleteOrderSwaggerPetstore.API, SwaggerPetstore
DeletePetSwaggerPetstore.API, SwaggerPetstore
deletePetSwaggerPetstore.API, SwaggerPetstore
DeleteUserSwaggerPetstore.API, SwaggerPetstore
deleteUserSwaggerPetstore.API, SwaggerPetstore
dispatchInitUnsafeSwaggerPetstore.Client, SwaggerPetstore
dispatchLbsSwaggerPetstore.Client, SwaggerPetstore
dispatchLbsUnsafeSwaggerPetstore.Client, SwaggerPetstore
dispatchMimeSwaggerPetstore.Client, SwaggerPetstore
dispatchMime'SwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-E.html b/samples/client/petstore/haskell-http-client/docs/doc-index-E.html new file mode 100644 index 00000000000..a656d616cba --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-E.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - E)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - E

errorLevelFilterSwaggerPetstore.Client, SwaggerPetstore
ExecLoggingTSwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-F.html b/samples/client/petstore/haskell-http-client/docs/doc-index-F.html new file mode 100644 index 00000000000..41aed3abf04 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-F.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - F)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - F

File 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
FindPetsByStatusSwaggerPetstore.API, SwaggerPetstore
findPetsByStatusSwaggerPetstore.API, SwaggerPetstore
FindPetsByTagsSwaggerPetstore.API, SwaggerPetstore
findPetsByTagsSwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-G.html b/samples/client/petstore/haskell-http-client/docs/doc-index-G.html new file mode 100644 index 00000000000..ba44a64e37d --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-G.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - G)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - G

GetInventorySwaggerPetstore.API, SwaggerPetstore
getInventorySwaggerPetstore.API, SwaggerPetstore
GetOrderByIdSwaggerPetstore.API, SwaggerPetstore
getOrderByIdSwaggerPetstore.API, SwaggerPetstore
GetPetByIdSwaggerPetstore.API, SwaggerPetstore
getPetByIdSwaggerPetstore.API, SwaggerPetstore
GetUserByNameSwaggerPetstore.API, SwaggerPetstore
getUserByNameSwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-H.html b/samples/client/petstore/haskell-http-client/docs/doc-index-H.html new file mode 100644 index 00000000000..907c42532e2 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-H.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - H)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - H

HasBodyParamSwaggerPetstore.API, SwaggerPetstore
HasOptionalParamSwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-I.html b/samples/client/petstore/haskell-http-client/docs/doc-index-I.html new file mode 100644 index 00000000000..cda6ec29fe0 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-I.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - I)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - I

infoLevelFilterSwaggerPetstore.Client, SwaggerPetstore
InitRequest 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-L.html b/samples/client/petstore/haskell-http-client/docs/doc-index-L.html new file mode 100644 index 00000000000..800469ab06e --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-L.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - L)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - L

Lens_SwaggerPetstore.Lens, SwaggerPetstore
Lens_'SwaggerPetstore.Lens, SwaggerPetstore
logExceptionsSwaggerPetstore.Client, SwaggerPetstore
LoginUserSwaggerPetstore.API, SwaggerPetstore
loginUserSwaggerPetstore.API, SwaggerPetstore
logNSTSwaggerPetstore.Client, SwaggerPetstore
LogoutUserSwaggerPetstore.API, SwaggerPetstore
logoutUserSwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-M.html b/samples/client/petstore/haskell-http-client/docs/doc-index-M.html new file mode 100644 index 00000000000..d1f062a7a9a --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-M.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - M)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - M

MimeError 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
mimeErrorSwaggerPetstore.Client, SwaggerPetstore
mimeErrorResponseSwaggerPetstore.Client, SwaggerPetstore
MimeFormUrlEncoded 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeJSON 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeMultipartFormData 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeNoContent 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeOctetStream 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimePlainText 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeRenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeRenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeRender'SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeResult 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
mimeResultSwaggerPetstore.Client, SwaggerPetstore
mimeResultResponseSwaggerPetstore.Client, SwaggerPetstore
MimeTypeSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeTypeSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeType'SwaggerPetstore.MimeTypes, SwaggerPetstore
mimeTypesSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeTypes'SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeUnrenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeUnrenderSwaggerPetstore.MimeTypes, SwaggerPetstore
mimeUnrender'SwaggerPetstore.MimeTypes, SwaggerPetstore
MimeXML 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
minLevelFilterSwaggerPetstore.Client, SwaggerPetstore
mkApiResponseSwaggerPetstore.Model, SwaggerPetstore
mkCategorySwaggerPetstore.Model, SwaggerPetstore
mkOrderSwaggerPetstore.Model, SwaggerPetstore
mkPetSwaggerPetstore.Model, SwaggerPetstore
mkTagSwaggerPetstore.Model, SwaggerPetstore
mkUserSwaggerPetstore.Model, SwaggerPetstore
modifyInitRequestSwaggerPetstore.Client, SwaggerPetstore
modifyInitRequestMSwaggerPetstore.Client, SwaggerPetstore
MultiParamArraySwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-N.html b/samples/client/petstore/haskell-http-client/docs/doc-index-N.html new file mode 100644 index 00000000000..46e938dcc57 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-N.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - N)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - N

Name 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
newConfigSwaggerPetstore.Client, SwaggerPetstore
NoContent 
1 (Type/Class)SwaggerPetstore.MimeTypes, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.MimeTypes, SwaggerPetstore
nullLoggerSwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-O.html b/samples/client/petstore/haskell-http-client/docs/doc-index-O.html new file mode 100644 index 00000000000..3376ab88ac7 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-O.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - O)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - O

Order 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
orderCompleteSwaggerPetstore.Model, SwaggerPetstore
orderCompleteTSwaggerPetstore.Lens, SwaggerPetstore
orderIdSwaggerPetstore.Model, SwaggerPetstore
orderIdTSwaggerPetstore.Lens, SwaggerPetstore
orderPetIdSwaggerPetstore.Model, SwaggerPetstore
orderPetIdTSwaggerPetstore.Lens, SwaggerPetstore
orderQuantitySwaggerPetstore.Model, SwaggerPetstore
orderQuantityTSwaggerPetstore.Lens, SwaggerPetstore
orderShipDateSwaggerPetstore.Model, SwaggerPetstore
orderShipDateTSwaggerPetstore.Lens, SwaggerPetstore
orderStatusSwaggerPetstore.Model, SwaggerPetstore
orderStatusTSwaggerPetstore.Lens, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-P.html b/samples/client/petstore/haskell-http-client/docs/doc-index-P.html new file mode 100644 index 00000000000..5b53cdf63d2 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-P.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - P)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - P

ParamBodySwaggerPetstore.API, SwaggerPetstore
ParamBodyBSwaggerPetstore.API, SwaggerPetstore
ParamBodyBLSwaggerPetstore.API, SwaggerPetstore
ParamBodyFormUrlEncodedSwaggerPetstore.API, SwaggerPetstore
ParamBodyMultipartFormDataSwaggerPetstore.API, SwaggerPetstore
ParamBodyNoneSwaggerPetstore.API, SwaggerPetstore
Params 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
paramsSwaggerPetstore.API, SwaggerPetstore
paramsBodySwaggerPetstore.API, SwaggerPetstore
paramsHeadersSwaggerPetstore.API, SwaggerPetstore
paramsQuerySwaggerPetstore.API, SwaggerPetstore
Pet 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
petCategorySwaggerPetstore.Model, SwaggerPetstore
petCategoryTSwaggerPetstore.Lens, SwaggerPetstore
petIdSwaggerPetstore.Model, SwaggerPetstore
petIdTSwaggerPetstore.Lens, SwaggerPetstore
petNameSwaggerPetstore.Model, SwaggerPetstore
petNameLSwaggerPetstore.Lens, SwaggerPetstore
petPhotoUrlsSwaggerPetstore.Model, SwaggerPetstore
petPhotoUrlsLSwaggerPetstore.Lens, SwaggerPetstore
petStatusSwaggerPetstore.Model, SwaggerPetstore
petStatusTSwaggerPetstore.Lens, SwaggerPetstore
petTagsSwaggerPetstore.Model, SwaggerPetstore
petTagsTSwaggerPetstore.Lens, SwaggerPetstore
PipeSeparatedSwaggerPetstore.API, SwaggerPetstore
PlaceOrderSwaggerPetstore.API, SwaggerPetstore
placeOrderSwaggerPetstore.API, SwaggerPetstore
ProducesSwaggerPetstore.MimeTypes, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-R.html b/samples/client/petstore/haskell-http-client/docs/doc-index-R.html new file mode 100644 index 00000000000..68b8401467b --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-R.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - R)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - R

removeHeaderSwaggerPetstore.API, SwaggerPetstore
rMethodSwaggerPetstore.API, SwaggerPetstore
runExceptionLoggingTSwaggerPetstore.Client, SwaggerPetstore
runLoggingTSwaggerPetstore.Client, SwaggerPetstore
runNullLoggingTSwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-S.html b/samples/client/petstore/haskell-http-client/docs/doc-index-S.html new file mode 100644 index 00000000000..64ec100e604 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-S.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - S)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - S

setBodyParamSwaggerPetstore.API, SwaggerPetstore
setHeaderSwaggerPetstore.API, SwaggerPetstore
SpaceSeparatedSwaggerPetstore.API, SwaggerPetstore
Status 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
SwaggerPetstoreConfig 
1 (Type/Class)SwaggerPetstore.Client, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Client, SwaggerPetstore
SwaggerPetstoreRequest 
1 (Type/Class)SwaggerPetstore.API, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.API, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-T.html b/samples/client/petstore/haskell-http-client/docs/doc-index-T.html new file mode 100644 index 00000000000..87f05f58042 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-T.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - T)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - T

TabSeparatedSwaggerPetstore.API, SwaggerPetstore
Tag 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
tagIdSwaggerPetstore.Model, SwaggerPetstore
tagIdTSwaggerPetstore.Lens, SwaggerPetstore
tagNameSwaggerPetstore.Model, SwaggerPetstore
tagNameTSwaggerPetstore.Lens, SwaggerPetstore
toFormSwaggerPetstore.API, SwaggerPetstore
toFormCollSwaggerPetstore.API, SwaggerPetstore
toHeaderSwaggerPetstore.API, SwaggerPetstore
toHeaderCollSwaggerPetstore.API, SwaggerPetstore
toPathSwaggerPetstore.API, SwaggerPetstore
toQuerySwaggerPetstore.API, SwaggerPetstore
toQueryCollSwaggerPetstore.API, SwaggerPetstore
Traversal_SwaggerPetstore.Lens, SwaggerPetstore
Traversal_'SwaggerPetstore.Lens, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-U.html b/samples/client/petstore/haskell-http-client/docs/doc-index-U.html new file mode 100644 index 00000000000..0bb882935f4 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-U.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - U)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - U

unAdditionalMetadataSwaggerPetstore.API, SwaggerPetstore
unApiUnderscorekeySwaggerPetstore.API, SwaggerPetstore
unFileSwaggerPetstore.API, SwaggerPetstore
unInitRequestSwaggerPetstore.Client, SwaggerPetstore
unNameSwaggerPetstore.API, SwaggerPetstore
unStatusSwaggerPetstore.API, SwaggerPetstore
UpdatePetSwaggerPetstore.API, SwaggerPetstore
updatePetSwaggerPetstore.API, SwaggerPetstore
UpdatePetWithFormSwaggerPetstore.API, SwaggerPetstore
updatePetWithFormSwaggerPetstore.API, SwaggerPetstore
UpdateUserSwaggerPetstore.API, SwaggerPetstore
updateUserSwaggerPetstore.API, SwaggerPetstore
UploadFileSwaggerPetstore.API, SwaggerPetstore
uploadFileSwaggerPetstore.API, SwaggerPetstore
urlPathSwaggerPetstore.API, SwaggerPetstore
User 
1 (Type/Class)SwaggerPetstore.Model, SwaggerPetstore
2 (Data Constructor)SwaggerPetstore.Model, SwaggerPetstore
userEmailSwaggerPetstore.Model, SwaggerPetstore
userEmailTSwaggerPetstore.Lens, SwaggerPetstore
userFirstNameSwaggerPetstore.Model, SwaggerPetstore
userFirstNameTSwaggerPetstore.Lens, SwaggerPetstore
userIdSwaggerPetstore.Model, SwaggerPetstore
userIdTSwaggerPetstore.Lens, SwaggerPetstore
userLastNameSwaggerPetstore.Model, SwaggerPetstore
userLastNameTSwaggerPetstore.Lens, SwaggerPetstore
userPasswordSwaggerPetstore.Model, SwaggerPetstore
userPasswordTSwaggerPetstore.Lens, SwaggerPetstore
userPhoneSwaggerPetstore.Model, SwaggerPetstore
userPhoneTSwaggerPetstore.Lens, SwaggerPetstore
userUsernameSwaggerPetstore.Model, SwaggerPetstore
userUsernameTSwaggerPetstore.Lens, SwaggerPetstore
userUserStatusSwaggerPetstore.Model, SwaggerPetstore
userUserStatusTSwaggerPetstore.Lens, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index-W.html b/samples/client/petstore/haskell-http-client/docs/doc-index-W.html new file mode 100644 index 00000000000..b30049c4ec8 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index-W.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index - W)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

Index - W

withNoLoggingSwaggerPetstore.Client, SwaggerPetstore
withStderrLoggingSwaggerPetstore.Client, SwaggerPetstore
withStdoutLoggingSwaggerPetstore.Client, SwaggerPetstore
\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/doc-index.html b/samples/client/petstore/haskell-http-client/docs/doc-index.html new file mode 100644 index 00000000000..93b48705f11 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/doc-index.html @@ -0,0 +1,4 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client (Index)

swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

\ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/haddock-util.js b/samples/client/petstore/haskell-http-client/docs/haddock-util.js new file mode 100644 index 00000000000..92d07d2a54e --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/haddock-util.js @@ -0,0 +1,316 @@ +// Haddock JavaScript utilities + +var rspace = /\s\s+/g, + rtrim = /^\s+|\s+$/g; + +function spaced(s) { return (" " + s + " ").replace(rspace, " "); } +function trim(s) { return s.replace(rtrim, ""); } + +function hasClass(elem, value) { + var className = spaced(elem.className || ""); + return className.indexOf( " " + value + " " ) >= 0; +} + +function addClass(elem, value) { + var className = spaced(elem.className || ""); + if ( className.indexOf( " " + value + " " ) < 0 ) { + elem.className = trim(className + " " + value); + } +} + +function removeClass(elem, value) { + var className = spaced(elem.className || ""); + className = className.replace(" " + value + " ", " "); + elem.className = trim(className); +} + +function toggleClass(elem, valueOn, valueOff, bool) { + if (bool == null) { bool = ! hasClass(elem, valueOn); } + if (bool) { + removeClass(elem, valueOff); + addClass(elem, valueOn); + } + else { + removeClass(elem, valueOn); + addClass(elem, valueOff); + } + return bool; +} + + +function makeClassToggle(valueOn, valueOff) +{ + return function(elem, bool) { + return toggleClass(elem, valueOn, valueOff, bool); + } +} + +toggleShow = makeClassToggle("show", "hide"); +toggleCollapser = makeClassToggle("collapser", "expander"); + +function toggleSection(id) +{ + var b = toggleShow(document.getElementById("section." + id)); + toggleCollapser(document.getElementById("control." + id), b); + rememberCollapsed(id, b); + return b; +} + +var collapsed = {}; +function rememberCollapsed(id, b) +{ + if(b) + delete collapsed[id] + else + collapsed[id] = null; + + var sections = []; + for(var i in collapsed) + { + if(collapsed.hasOwnProperty(i)) + sections.push(i); + } + // cookie specific to this page; don't use setCookie which sets path=/ + document.cookie = "collapsed=" + escape(sections.join('+')); +} + +function restoreCollapsed() +{ + var cookie = getCookie("collapsed"); + if(!cookie) + return; + + var ids = cookie.split('+'); + for(var i in ids) + { + if(document.getElementById("section." + ids[i])) + toggleSection(ids[i]); + } +} + +function setCookie(name, value) { + document.cookie = name + "=" + escape(value) + ";path=/;"; +} + +function clearCookie(name) { + document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;"; +} + +function getCookie(name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for(var i=0;i < ca.length;i++) { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) { + return unescape(c.substring(nameEQ.length,c.length)); + } + } + return null; +} + + + +var max_results = 75; // 50 is not enough to search for map in the base libraries +var shown_range = null; +var last_search = null; + +function quick_search() +{ + perform_search(false); +} + +function full_search() +{ + perform_search(true); +} + + +function perform_search(full) +{ + var text = document.getElementById("searchbox").value.toLowerCase(); + if (text == last_search && !full) return; + last_search = text; + + var table = document.getElementById("indexlist"); + var status = document.getElementById("searchmsg"); + var children = table.firstChild.childNodes; + + // first figure out the first node with the prefix + var first = bisect(-1); + var last = (first == -1 ? -1 : bisect(1)); + + if (first == -1) + { + table.className = ""; + status.innerHTML = "No results found, displaying all"; + } + else if (first == 0 && last == children.length - 1) + { + table.className = ""; + status.innerHTML = ""; + } + else if (last - first >= max_results && !full) + { + table.className = ""; + status.innerHTML = "More than " + max_results + ", press Search to display"; + } + else + { + // decide what you need to clear/show + if (shown_range) + setclass(shown_range[0], shown_range[1], "indexrow"); + setclass(first, last, "indexshow"); + shown_range = [first, last]; + table.className = "indexsearch"; + status.innerHTML = ""; + } + + + function setclass(first, last, status) + { + for (var i = first; i <= last; i++) + { + children[i].className = status; + } + } + + + // do a binary search, treating 0 as ... + // return either -1 (no 0's found) or location of most far match + function bisect(dir) + { + var first = 0, finish = children.length - 1; + var mid, success = false; + + while (finish - first > 3) + { + mid = Math.floor((finish + first) / 2); + + var i = checkitem(mid); + if (i == 0) i = dir; + if (i == -1) + finish = mid; + else + first = mid; + } + var a = (dir == 1 ? first : finish); + var b = (dir == 1 ? finish : first); + for (var i = b; i != a - dir; i -= dir) + { + if (checkitem(i) == 0) return i; + } + return -1; + } + + + // from an index, decide what the result is + // 0 = match, -1 is lower, 1 is higher + function checkitem(i) + { + var s = getitem(i).toLowerCase().substr(0, text.length); + if (s == text) return 0; + else return (s > text ? -1 : 1); + } + + + // from an index, get its string + // this abstracts over alternates + function getitem(i) + { + for ( ; i >= 0; i--) + { + var s = children[i].firstChild.firstChild.data; + if (s.indexOf(' ') == -1) + return s; + } + return ""; // should never be reached + } +} + +function setSynopsis(filename) { + if (parent.window.synopsis && parent.window.synopsis.location) { + if (parent.window.synopsis.location.replace) { + // In Firefox this avoids adding the change to the history. + parent.window.synopsis.location.replace(filename); + } else { + parent.window.synopsis.location = filename; + } + } +} + +function addMenuItem(html) { + var menu = document.getElementById("page-menu"); + if (menu) { + var btn = menu.firstChild.cloneNode(false); + btn.innerHTML = html; + menu.appendChild(btn); + } +} + +function styles() { + var i, a, es = document.getElementsByTagName("link"), rs = []; + for (i = 0; a = es[i]; i++) { + if(a.rel.indexOf("style") != -1 && a.title) { + rs.push(a); + } + } + return rs; +} + +function addStyleMenu() { + var as = styles(); + var i, a, btns = ""; + for(i=0; a = as[i]; i++) { + btns += "
  • " + + a.title + "
  • " + } + if (as.length > 1) { + var h = "
    " + + "Style ▾" + + "
      " + btns + "
    " + + "
    "; + addMenuItem(h); + } +} + +function setActiveStyleSheet(title) { + var as = styles(); + var i, a, found; + for(i=0; a = as[i]; i++) { + a.disabled = true; + // need to do this always, some browsers are edge triggered + if(a.title == title) { + found = a; + } + } + if (found) { + found.disabled = false; + setCookie("haddock-style", title); + } + else { + as[0].disabled = false; + clearCookie("haddock-style"); + } + styleMenu(false); +} + +function resetStyle() { + var s = getCookie("haddock-style"); + if (s) setActiveStyleSheet(s); +} + + +function styleMenu(show) { + var m = document.getElementById('style-menu'); + if (m) toggleShow(m, show); +} + + +function pageLoad() { + addStyleMenu(); + resetStyle(); + restoreCollapsed(); +} + diff --git a/samples/client/petstore/haskell-http-client/docs/hslogo-16.png b/samples/client/petstore/haskell-http-client/docs/hslogo-16.png new file mode 100644 index 00000000000..0ff8579fbd8 Binary files /dev/null and b/samples/client/petstore/haskell-http-client/docs/hslogo-16.png differ diff --git a/samples/client/petstore/haskell-http-client/docs/index.html b/samples/client/petstore/haskell-http-client/docs/index.html new file mode 100644 index 00000000000..07839448e85 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/index.html @@ -0,0 +1,6 @@ +swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

    swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

    swagger-petstore-0.1.0.0: Auto-generated swagger-petstore API Client

    . +Client library for calling the swagger-petstore API based on http-client. +host: petstore.swagger.io

    base path: http://petstore.swagger.io/v2

    apiVersion: 0.0.1

    swagger version: 2.0

    OpenAPI-Specification: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md

    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-API.html b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-API.html new file mode 100644 index 00000000000..a18ac070a29 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-API.html @@ -0,0 +1,4 @@ +SwaggerPetstore.API

    SwaggerPetstore.API

    Operations

    Pet

    addPet

    data AddPet

    deletePet

    findPetsByStatus

    findPetsByTags

    getPetById

    updatePet

    updatePetWithForm

    uploadFile

    Store

    deleteOrder

    getInventory

    getOrderById

    placeOrder

    User

    createUser

    createUsersWithArrayInput

    createUsersWithListInput

    deleteUser

    getUserByName

    loginUser

    logoutUser

    updateUser

    HasBodyParam

    class HasBodyParam req param

    HasOptionalParam

    class HasOptionalParam req param

    Optional Request Parameter Types

    data Name

    data Status

    data File

    SwaggerPetstoreRequest

    data SwaggerPetstoreRequest req contentType res

    data Params

    SwaggerPetstoreRequest Utils

    Params Utils

    Swagger CollectionFormat Utils

    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Client.html b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Client.html new file mode 100644 index 00000000000..9f32380e5d4 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Client.html @@ -0,0 +1,4 @@ +SwaggerPetstore.Client

    SwaggerPetstore.Client

    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Lens.html b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Lens.html new file mode 100644 index 00000000000..32e4b2770c4 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Lens.html @@ -0,0 +1,4 @@ +SwaggerPetstore.Lens

    SwaggerPetstore.Lens

    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-MimeTypes.html b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-MimeTypes.html new file mode 100644 index 00000000000..2e03b6a10c5 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-MimeTypes.html @@ -0,0 +1,4 @@ +SwaggerPetstore.MimeTypes

    SwaggerPetstore.MimeTypes

    Content Negotiation

    Mime Types

    data MimeXML

    MimeType Class

    class MimeType mtype

    MimeType Instances

    MimeRender Class

    class MimeRender mtype x

    MimeRender Instances

    MimeUnrender Class

    class MimeUnrender mtype o

    MimeUnrender Instances

    Request Consumes

    class Consumes req mtype

    Request Produces

    class Produces req mtype

    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Model.html b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Model.html new file mode 100644 index 00000000000..afc8c09022d --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore-Model.html @@ -0,0 +1,4 @@ +SwaggerPetstore.Model

    SwaggerPetstore.Model

    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore.html b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore.html new file mode 100644 index 00000000000..6e7be995860 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/mini_SwaggerPetstore.html @@ -0,0 +1,4 @@ +SwaggerPetstore

    SwaggerPetstore

    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/minus.gif b/samples/client/petstore/haskell-http-client/docs/minus.gif new file mode 100644 index 00000000000..1deac2fe1a4 Binary files /dev/null and b/samples/client/petstore/haskell-http-client/docs/minus.gif differ diff --git a/samples/client/petstore/haskell-http-client/docs/ocean.css b/samples/client/petstore/haskell-http-client/docs/ocean.css new file mode 100644 index 00000000000..e8e4d705491 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/ocean.css @@ -0,0 +1,612 @@ +/* @group Fundamentals */ + +* { margin: 0; padding: 0 } + +/* Is this portable? */ +html { + background-color: white; + width: 100%; + height: 100%; +} + +body { + background: white; + color: black; + text-align: left; + min-height: 100%; + position: relative; +} + +p { + margin: 0.8em 0; +} + +ul, ol { + margin: 0.8em 0 0.8em 2em; +} + +dl { + margin: 0.8em 0; +} + +dt { + font-weight: bold; +} +dd { + margin-left: 2em; +} + +a { text-decoration: none; } +a[href]:link { color: rgb(196,69,29); } +a[href]:visited { color: rgb(171,105,84); } +a[href]:hover { text-decoration:underline; } + +a[href].def:link, a[href].def:visited { color: black; } +a[href].def:hover { color: rgb(78, 98, 114); } + +/* @end */ + +/* @group Fonts & Sizes */ + +/* Basic technique & IE workarounds from YUI 3 + For reasons, see: + http://yui.yahooapis.com/3.1.1/build/cssfonts/fonts.css + */ + +body { + font:13px/1.4 sans-serif; + *font-size:small; /* for IE */ + *font:x-small; /* for IE in quirks mode */ +} + +h1 { font-size: 146.5%; /* 19pt */ } +h2 { font-size: 131%; /* 17pt */ } +h3 { font-size: 116%; /* 15pt */ } +h4 { font-size: 100%; /* 13pt */ } +h5 { font-size: 100%; /* 13pt */ } + +select, input, button, textarea { + font:99% sans-serif; +} + +table { + font-size:inherit; + font:100%; +} + +pre, code, kbd, samp, tt, .src { + font-family:monospace; + *font-size:108%; + line-height: 124%; +} + +.links, .link { + font-size: 85%; /* 11pt */ +} + +#module-header .caption { + font-size: 182%; /* 24pt */ +} + +.info { + font-size: 85%; /* 11pt */ +} + +#table-of-contents, #synopsis { + /* font-size: 85%; /* 11pt */ +} + + +/* @end */ + +/* @group Common */ + +.caption, h1, h2, h3, h4, h5, h6 { + font-weight: bold; + color: rgb(78,98,114); + margin: 0.8em 0 0.4em; +} + +* + h1, * + h2, * + h3, * + h4, * + h5, * + h6 { + margin-top: 2em; +} + +h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6 { + margin-top: inherit; +} + +ul.links { + list-style: none; + text-align: left; + float: right; + display: inline-table; + margin: 0 0 0 1em; +} + +ul.links li { + display: inline; + border-left: 1px solid #d5d5d5; + white-space: nowrap; + padding: 0; +} + +ul.links li a { + padding: 0.2em 0.5em; +} + +.hide { display: none; } +.show { display: inherit; } +.clear { clear: both; } + +.collapser { + background-image: url(minus.gif); + background-repeat: no-repeat; +} +.expander { + background-image: url(plus.gif); + background-repeat: no-repeat; +} +.collapser, .expander { + padding-left: 14px; + margin-left: -14px; + cursor: pointer; +} +p.caption.collapser, +p.caption.expander { + background-position: 0 0.4em; +} + +.instance.collapser, .instance.expander { + margin-left: 0px; + background-position: left center; + min-width: 9px; + min-height: 9px; +} + + +pre { + padding: 0.25em; + margin: 0.8em 0; + background: rgb(229,237,244); + overflow: auto; + border-bottom: 0.25em solid white; + /* white border adds some space below the box to compensate + for visual extra space that paragraphs have between baseline + and the bounding box */ +} + +.src { + background: #f0f0f0; + padding: 0.2em 0.5em; +} + +.keyword { font-weight: normal; } +.def { font-weight: bold; } + +@media print { + #footer { display: none; } +} + +/* @end */ + +/* @group Page Structure */ + +#content { + margin: 0 auto; + padding: 0 2em 6em; +} + +#package-header { + background: rgb(41,56,69); + border-top: 5px solid rgb(78,98,114); + color: #ddd; + padding: 0.2em; + position: relative; + text-align: left; +} + +#package-header .caption { + background: url(hslogo-16.png) no-repeat 0em; + color: white; + margin: 0 2em; + font-weight: normal; + font-style: normal; + padding-left: 2em; +} + +#package-header a:link, #package-header a:visited { color: white; } +#package-header a:hover { background: rgb(78,98,114); } + +#module-header .caption { + color: rgb(78,98,114); + font-weight: bold; + border-bottom: 1px solid #ddd; +} + +table.info { + float: right; + padding: 0.5em 1em; + border: 1px solid #ddd; + color: rgb(78,98,114); + background-color: #fff; + max-width: 40%; + border-spacing: 0; + position: relative; + top: -0.5em; + margin: 0 0 0 2em; +} + +.info th { + padding: 0 1em 0 0; +} + +div#style-menu-holder { + position: relative; + z-index: 2; + display: inline; +} + +#style-menu { + position: absolute; + z-index: 1; + overflow: visible; + background: #374c5e; + margin: 0; + text-align: center; + right: 0; + padding: 0; + top: 1.25em; +} + +#style-menu li { + display: list-item; + border-style: none; + margin: 0; + padding: 0; + color: #000; + list-style-type: none; +} + +#style-menu li + li { + border-top: 1px solid #919191; +} + +#style-menu a { + width: 6em; + padding: 3px; + display: block; +} + +#footer { + background: #ddd; + border-top: 1px solid #aaa; + padding: 0.5em 0; + color: #666; + text-align: center; + position: absolute; + bottom: 0; + width: 100%; + height: 3em; +} + +/* @end */ + +/* @group Front Matter */ + +#table-of-contents { + float: right; + clear: right; + background: #faf9dc; + border: 1px solid #d8d7ad; + padding: 0.5em 1em; + max-width: 20em; + margin: 0.5em 0 1em 1em; +} + +#table-of-contents .caption { + text-align: center; + margin: 0; +} + +#table-of-contents ul { + list-style: none; + margin: 0; +} + +#table-of-contents ul ul { + margin-left: 2em; +} + +#description .caption { + display: none; +} + +#synopsis { + display: none; +} + +.no-frame #synopsis { + display: block; + position: fixed; + right: 0; + height: 80%; + top: 10%; + padding: 0; + max-width: 75%; + /* Ensure that synopsis covers everything (including MathJAX markup) */ + z-index: 1; +} + +#synopsis .caption { + float: left; + width: 29px; + color: rgba(255,255,255,0); + height: 110px; + margin: 0; + font-size: 1px; + padding: 0; +} + +#synopsis p.caption.collapser { + background: url(synopsis.png) no-repeat -64px -8px; +} + +#synopsis p.caption.expander { + background: url(synopsis.png) no-repeat 0px -8px; +} + +#synopsis ul { + height: 100%; + overflow: auto; + padding: 0.5em; + margin: 0; +} + +#synopsis ul ul { + overflow: hidden; +} + +#synopsis ul, +#synopsis ul li.src { + background-color: #faf9dc; + white-space: nowrap; + list-style: none; + margin-left: 0; +} + +/* @end */ + +/* @group Main Content */ + +#interface div.top { margin: 2em 0; } +#interface h1 + div.top, +#interface h2 + div.top, +#interface h3 + div.top, +#interface h4 + div.top, +#interface h5 + div.top { + margin-top: 1em; +} +#interface .src .selflink, +#interface .src .link { + float: right; + color: #919191; + background: #f0f0f0; + padding: 0 0.5em 0.2em; + margin: 0 -0.5em 0 0; +} +#interface .src .selflink { + border-left: 1px solid #919191; + margin: 0 -0.5em 0 0.5em; +} + +#interface span.fixity { + color: #919191; + border-left: 1px solid #919191; + padding: 0.2em 0.5em 0.2em 0.5em; + margin: 0 -1em 0 1em; +} + +#interface span.rightedge { + border-left: 1px solid #919191; + padding: 0.2em 0 0.2em 0; + margin: 0 0 0 1em; +} + +#interface table { border-spacing: 2px; } +#interface td { + vertical-align: top; + padding-left: 0.5em; +} +#interface td.src { + white-space: nowrap; +} +#interface td.doc p { + margin: 0; +} +#interface td.doc p + p { + margin-top: 0.8em; +} + +.clearfix:after { + clear: both; + content: " "; + display: block; + height: 0; + visibility: hidden; +} + +.subs ul { + list-style: none; + display: table; + margin: 0; +} + +.subs ul li { + display: table-row; +} + +.subs ul li dfn { + display: table-cell; + font-style: normal; + font-weight: bold; + margin: 1px 0; + white-space: nowrap; +} + +.subs ul li > .doc { + display: table-cell; + padding-left: 0.5em; + margin-bottom: 0.5em; +} + +.subs ul li > .doc p { + margin: 0; +} + +/* Render short-style data instances */ +.inst ul { + height: 100%; + padding: 0.5em; + margin: 0; +} + +.inst, .inst li { + list-style: none; + margin-left: 1em; +} + +/* Workaround for bug in Firefox (issue #384) */ +.inst-left { + float: left; +} + +.top p.src { + border-top: 1px solid #ccc; +} + +.subs, .doc { + /* use this selector for one level of indent */ + padding-left: 2em; +} + +.warning { + color: red; +} + +.arguments { + margin-top: -0.4em; +} +.arguments .caption { + display: none; +} + +.fields { padding-left: 1em; } + +.fields .caption { display: none; } + +.fields p { margin: 0 0; } + +/* this seems bulky to me +.methods, .constructors { + background: #f8f8f8; + border: 1px solid #eee; +} +*/ + +/* @end */ + +/* @group Auxillary Pages */ + + +.extension-list { + list-style-type: none; + margin-left: 0; +} + +#mini { + margin: 0 auto; + padding: 0 1em 1em; +} + +#mini > * { + font-size: 93%; /* 12pt */ +} + +#mini #module-list .caption, +#mini #module-header .caption { + font-size: 125%; /* 15pt */ +} + +#mini #interface h1, +#mini #interface h2, +#mini #interface h3, +#mini #interface h4 { + font-size: 109%; /* 13pt */ + margin: 1em 0 0; +} + +#mini #interface .top, +#mini #interface .src { + margin: 0; +} + +#mini #module-list ul { + list-style: none; + margin: 0; +} + +#alphabet ul { + list-style: none; + padding: 0; + margin: 0.5em 0 0; + text-align: center; +} + +#alphabet li { + display: inline; + margin: 0 0.25em; +} + +#alphabet a { + font-weight: bold; +} + +#index .caption, +#module-list .caption { font-size: 131%; /* 17pt */ } + +#index table { + margin-left: 2em; +} + +#index .src { + font-weight: bold; +} +#index .alt { + font-size: 77%; /* 10pt */ + font-style: italic; + padding-left: 2em; +} + +#index td + td { + padding-left: 1em; +} + +#module-list ul { + list-style: none; + margin: 0 0 0 2em; +} + +#module-list li { + clear: right; +} + +#module-list span.collapser, +#module-list span.expander { + background-position: 0 0.3em; +} + +#module-list .package { + float: right; +} + +/* @end */ diff --git a/samples/client/petstore/haskell-http-client/docs/plus.gif b/samples/client/petstore/haskell-http-client/docs/plus.gif new file mode 100644 index 00000000000..2d15c14173d Binary files /dev/null and b/samples/client/petstore/haskell-http-client/docs/plus.gif differ diff --git a/samples/client/petstore/haskell-http-client/docs/src/Paths_swagger_petstore.html b/samples/client/petstore/haskell-http-client/docs/src/Paths_swagger_petstore.html new file mode 100644 index 00000000000..3cd3b9c5cca --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/Paths_swagger_petstore.html @@ -0,0 +1,51 @@ +
    {-# LANGUAGE CPP #-}
    +{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}
    +{-# OPTIONS_GHC -fno-warn-implicit-prelude #-}
    +module Paths_swagger_petstore (
    +    version,
    +    getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir,
    +    getDataFileName, getSysconfDir
    +  ) where
    +
    +import qualified Control.Exception as Exception
    +import Data.Version (Version(..))
    +import System.Environment (getEnv)
    +import Prelude
    +
    +#if defined(VERSION_base)
    +
    +#if MIN_VERSION_base(4,0,0)
    +catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
    +#else
    +catchIO :: IO a -> (Exception.Exception -> IO a) -> IO a
    +#endif
    +
    +#else
    +catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
    +#endif
    +catchIO = Exception.catch
    +
    +version :: Version
    +version = Version [0,1,0,0] []
    +bindir, libdir, dynlibdir, datadir, libexecdir, sysconfdir :: FilePath
    +
    +bindir     = "/home/jon/fs/git/swagger-codegen/samples/client/petstore/haskell-http-client/.stack-work/install/x86_64-linux-nopie/lts-9.0/8.0.2/bin"
    +libdir     = "/home/jon/fs/git/swagger-codegen/samples/client/petstore/haskell-http-client/.stack-work/install/x86_64-linux-nopie/lts-9.0/8.0.2/lib/x86_64-linux-ghc-8.0.2/swagger-petstore-0.1.0.0-FhAGC7YzWguJAT2YJ3ggeI"
    +dynlibdir  = "/home/jon/fs/git/swagger-codegen/samples/client/petstore/haskell-http-client/.stack-work/install/x86_64-linux-nopie/lts-9.0/8.0.2/lib/x86_64-linux-ghc-8.0.2"
    +datadir    = "/home/jon/fs/git/swagger-codegen/samples/client/petstore/haskell-http-client/.stack-work/install/x86_64-linux-nopie/lts-9.0/8.0.2/share/x86_64-linux-ghc-8.0.2/swagger-petstore-0.1.0.0"
    +libexecdir = "/home/jon/fs/git/swagger-codegen/samples/client/petstore/haskell-http-client/.stack-work/install/x86_64-linux-nopie/lts-9.0/8.0.2/libexec"
    +sysconfdir = "/home/jon/fs/git/swagger-codegen/samples/client/petstore/haskell-http-client/.stack-work/install/x86_64-linux-nopie/lts-9.0/8.0.2/etc"
    +
    +getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir, getSysconfDir :: IO FilePath
    +getBinDir = catchIO (getEnv "swagger_petstore_bindir") (\_ -> return bindir)
    +getLibDir = catchIO (getEnv "swagger_petstore_libdir") (\_ -> return libdir)
    +getDynLibDir = catchIO (getEnv "swagger_petstore_dynlibdir") (\_ -> return dynlibdir)
    +getDataDir = catchIO (getEnv "swagger_petstore_datadir") (\_ -> return datadir)
    +getLibexecDir = catchIO (getEnv "swagger_petstore_libexecdir") (\_ -> return libexecdir)
    +getSysconfDir = catchIO (getEnv "swagger_petstore_sysconfdir") (\_ -> return sysconfdir)
    +
    +getDataFileName :: FilePath -> IO FilePath
    +getDataFileName name = do
    +  dir <- getDataDir
    +  return (dir ++ "/" ++ name)
    +
    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.API.html b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.API.html new file mode 100644 index 00000000000..e7113e60a2f --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.API.html @@ -0,0 +1,831 @@ +
    {-|
    +Module : SwaggerPetstore.API
    +-}
    +
    +{-# LANGUAGE RecordWildCards #-}
    +
    +{-# LANGUAGE MultiParamTypeClasses #-}
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# LANGUAGE ScopedTypeVariables #-}
    +{-# LANGUAGE FlexibleInstances #-}
    +{-# LANGUAGE FlexibleContexts #-}
    +{-# LANGUAGE ConstraintKinds #-}
    +{-# LANGUAGE InstanceSigs #-}
    +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-}
    +
    +module SwaggerPetstore.API where
    +
    +
    +import SwaggerPetstore.Model as M
    +import SwaggerPetstore.MimeTypes
    +
    +import qualified Data.Aeson as A
    +import Data.Aeson (Value)
    +
    +import qualified Data.Time as TI
    +import Data.Time (UTCTime)
    +
    +import qualified Data.ByteString as B
    +import qualified Data.ByteString.Lazy as BL
    +import Data.ByteString.Lazy (ByteString)
    +import qualified Data.ByteString.Builder as BB
    +import qualified Data.ByteString.Char8 as BC
    +import qualified Data.ByteString.Lazy.Char8 as BCL
    +
    +import qualified Network.HTTP.Client.MultipartFormData as NH
    +import qualified Network.HTTP.Media as ME
    +import qualified Network.HTTP.Types as NH
    +
    +import qualified Web.HttpApiData as WH
    +import qualified Web.FormUrlEncoded as WH
    +
    +import qualified Data.CaseInsensitive as CI
    +import qualified Data.Data as P (Typeable)
    +import qualified Data.Foldable as P
    +import qualified Data.Map as Map
    +import qualified Data.Maybe as P
    +import qualified Data.Proxy as P (Proxy(..))
    +import qualified Data.Text as T
    +import qualified Data.Text.Encoding as T
    +import qualified Data.Text.Lazy as TL
    +import qualified Data.Text.Lazy.Encoding as TL
    +import qualified GHC.Base as P (Alternative)
    +import qualified Control.Arrow as P (left)
    +
    +import Data.Monoid ((<>))
    +import Data.Function ((&))
    +import Data.Set (Set)
    +import Data.Text (Text)
    +import GHC.Base ((<|>))
    +
    +import Prelude ((==),(/=),($), (.),(<$>),(<*>),(>>=),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor)
    +import qualified Prelude as P
    +
    +-- * Operations
    +
    +
    +-- ** Pet
    +
    +-- *** addPet
    +
    +-- | @POST \/pet@
    +-- 
    +-- Add a new pet to the store
    +-- 
    +-- 
    +-- 
    +-- AuthMethod: petstore_auth
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +addPet 
    +  :: (Consumes AddPet contentType, MimeRender contentType Pet)
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> Pet -- ^ "body" -  Pet object that needs to be added to the store
    +  -> SwaggerPetstoreRequest AddPet contentType res
    +addPet _ body =
    +  _mkRequest "POST" ["/pet"]
    +    `setBodyParam` body
    +
    +data AddPet 
    +
    +-- | /Body Param/ "body" - Pet object that needs to be added to the store
    +instance HasBodyParam AddPet Pet 
    +
    +-- | @application/json@
    +instance Consumes AddPet MimeJSON
    +-- | @application/xml@
    +instance Consumes AddPet MimeXML
    +
    +-- | @application/xml@
    +instance Produces AddPet MimeXML
    +-- | @application/json@
    +instance Produces AddPet MimeJSON
    +
    +
    +-- *** deletePet
    +
    +-- | @DELETE \/pet\/{petId}@
    +-- 
    +-- Deletes a pet
    +-- 
    +-- 
    +-- 
    +-- AuthMethod: petstore_auth
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +deletePet 
    +  :: Integer -- ^ "petId" -  Pet id to delete
    +  -> SwaggerPetstoreRequest DeletePet MimeNoContent res
    +deletePet petId =
    +  _mkRequest "DELETE" ["/pet/",toPath petId]
    +    
    +
    +data DeletePet  
    +instance HasOptionalParam DeletePet ApiUnderscorekey where
    +  applyOptionalParam req (ApiUnderscorekey xs) =
    +    req `setHeader` toHeader ("api_key", xs)
    +-- | @application/xml@
    +instance Produces DeletePet MimeXML
    +-- | @application/json@
    +instance Produces DeletePet MimeJSON
    +
    +
    +-- *** findPetsByStatus
    +
    +-- | @GET \/pet\/findByStatus@
    +-- 
    +-- Finds Pets by status
    +-- 
    +-- Multiple status values can be provided with comma separated strings
    +-- 
    +-- AuthMethod: petstore_auth
    +-- 
    +findPetsByStatus 
    +  :: [Text] -- ^ "status" -  Status values that need to be considered for filter
    +  -> SwaggerPetstoreRequest FindPetsByStatus MimeNoContent [Pet]
    +findPetsByStatus status =
    +  _mkRequest "GET" ["/pet/findByStatus"]
    +    `_setQuery` toQueryColl CommaSeparated ("status", Just status)
    +
    +data FindPetsByStatus  
    +-- | @application/xml@
    +instance Produces FindPetsByStatus MimeXML
    +-- | @application/json@
    +instance Produces FindPetsByStatus MimeJSON
    +
    +
    +-- *** findPetsByTags
    +
    +-- | @GET \/pet\/findByTags@
    +-- 
    +-- Finds Pets by tags
    +-- 
    +-- Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
    +-- 
    +-- AuthMethod: petstore_auth
    +-- 
    +findPetsByTags 
    +  :: [Text] -- ^ "tags" -  Tags to filter by
    +  -> SwaggerPetstoreRequest FindPetsByTags MimeNoContent [Pet]
    +findPetsByTags tags =
    +  _mkRequest "GET" ["/pet/findByTags"]
    +    `_setQuery` toQueryColl CommaSeparated ("tags", Just tags)
    +
    +{-# DEPRECATED findPetsByTags "" #-}
    +
    +data FindPetsByTags  
    +-- | @application/xml@
    +instance Produces FindPetsByTags MimeXML
    +-- | @application/json@
    +instance Produces FindPetsByTags MimeJSON
    +
    +
    +-- *** getPetById
    +
    +-- | @GET \/pet\/{petId}@
    +-- 
    +-- Find pet by ID
    +-- 
    +-- Returns a single pet
    +-- 
    +-- AuthMethod: api_key
    +-- 
    +getPetById 
    +  :: Integer -- ^ "petId" -  ID of pet to return
    +  -> SwaggerPetstoreRequest GetPetById MimeNoContent Pet
    +getPetById petId =
    +  _mkRequest "GET" ["/pet/",toPath petId]
    +    
    +
    +data GetPetById  
    +-- | @application/xml@
    +instance Produces GetPetById MimeXML
    +-- | @application/json@
    +instance Produces GetPetById MimeJSON
    +
    +
    +-- *** updatePet
    +
    +-- | @PUT \/pet@
    +-- 
    +-- Update an existing pet
    +-- 
    +-- 
    +-- 
    +-- AuthMethod: petstore_auth
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +updatePet 
    +  :: (Consumes UpdatePet contentType, MimeRender contentType Pet)
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> Pet -- ^ "body" -  Pet object that needs to be added to the store
    +  -> SwaggerPetstoreRequest UpdatePet contentType res
    +updatePet _ body =
    +  _mkRequest "PUT" ["/pet"]
    +    `setBodyParam` body
    +
    +data UpdatePet 
    +
    +-- | /Body Param/ "body" - Pet object that needs to be added to the store
    +instance HasBodyParam UpdatePet Pet 
    +
    +-- | @application/json@
    +instance Consumes UpdatePet MimeJSON
    +-- | @application/xml@
    +instance Consumes UpdatePet MimeXML
    +
    +-- | @application/xml@
    +instance Produces UpdatePet MimeXML
    +-- | @application/json@
    +instance Produces UpdatePet MimeJSON
    +
    +
    +-- *** updatePetWithForm
    +
    +-- | @POST \/pet\/{petId}@
    +-- 
    +-- Updates a pet in the store with form data
    +-- 
    +-- 
    +-- 
    +-- AuthMethod: petstore_auth
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +updatePetWithForm 
    +  :: (Consumes UpdatePetWithForm contentType)
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> Integer -- ^ "petId" -  ID of pet that needs to be updated
    +  -> SwaggerPetstoreRequest UpdatePetWithForm contentType res
    +updatePetWithForm _ petId =
    +  _mkRequest "POST" ["/pet/",toPath petId]
    +    
    +
    +data UpdatePetWithForm  
    +
    +-- | /Optional Param/ "name" - Updated name of the pet
    +instance HasOptionalParam UpdatePetWithForm Name where
    +  applyOptionalParam req (Name xs) =
    +    req `_addForm` toForm ("name", xs)
    +
    +-- | /Optional Param/ "status" - Updated status of the pet
    +instance HasOptionalParam UpdatePetWithForm Status where
    +  applyOptionalParam req (Status xs) =
    +    req `_addForm` toForm ("status", xs)
    +
    +-- | @application/x-www-form-urlencoded@
    +instance Consumes UpdatePetWithForm MimeFormUrlEncoded
    +
    +-- | @application/xml@
    +instance Produces UpdatePetWithForm MimeXML
    +-- | @application/json@
    +instance Produces UpdatePetWithForm MimeJSON
    +
    +
    +-- *** uploadFile
    +
    +-- | @POST \/pet\/{petId}\/uploadImage@
    +-- 
    +-- uploads an image
    +-- 
    +-- 
    +-- 
    +-- AuthMethod: petstore_auth
    +-- 
    +uploadFile 
    +  :: (Consumes UploadFile contentType)
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> Integer -- ^ "petId" -  ID of pet to update
    +  -> SwaggerPetstoreRequest UploadFile contentType ApiResponse
    +uploadFile _ petId =
    +  _mkRequest "POST" ["/pet/",toPath petId,"/uploadImage"]
    +    
    +
    +data UploadFile  
    +
    +-- | /Optional Param/ "additionalMetadata" - Additional data to pass to server
    +instance HasOptionalParam UploadFile AdditionalMetadata where
    +  applyOptionalParam req (AdditionalMetadata xs) =
    +    req `_addMultiFormPart` NH.partLBS "additionalMetadata" (mimeRender' MimeMultipartFormData xs)
    +
    +-- | /Optional Param/ "file" - file to upload
    +instance HasOptionalParam UploadFile File where
    +  applyOptionalParam req (File xs) =
    +    req `_addMultiFormPart` NH.partFileSource "file" xs
    +
    +-- | @multipart/form-data@
    +instance Consumes UploadFile MimeMultipartFormData
    +
    +-- | @application/json@
    +instance Produces UploadFile MimeJSON
    +
    +
    +-- ** Store
    +
    +-- *** deleteOrder
    +
    +-- | @DELETE \/store\/order\/{orderId}@
    +-- 
    +-- Delete purchase order by ID
    +-- 
    +-- For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +deleteOrder 
    +  :: Text -- ^ "orderId" -  ID of the order that needs to be deleted
    +  -> SwaggerPetstoreRequest DeleteOrder MimeNoContent res
    +deleteOrder orderId =
    +  _mkRequest "DELETE" ["/store/order/",toPath orderId]
    +    
    +
    +data DeleteOrder  
    +-- | @application/xml@
    +instance Produces DeleteOrder MimeXML
    +-- | @application/json@
    +instance Produces DeleteOrder MimeJSON
    +
    +
    +-- *** getInventory
    +
    +-- | @GET \/store\/inventory@
    +-- 
    +-- Returns pet inventories by status
    +-- 
    +-- Returns a map of status codes to quantities
    +-- 
    +-- AuthMethod: api_key
    +-- 
    +getInventory 
    +  :: SwaggerPetstoreRequest GetInventory MimeNoContent (Map.Map String Int)
    +getInventory =
    +  _mkRequest "GET" ["/store/inventory"]
    +
    +data GetInventory  
    +-- | @application/json@
    +instance Produces GetInventory MimeJSON
    +
    +
    +-- *** getOrderById
    +
    +-- | @GET \/store\/order\/{orderId}@
    +-- 
    +-- Find purchase order by ID
    +-- 
    +-- For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
    +-- 
    +getOrderById 
    +  :: Integer -- ^ "orderId" -  ID of pet that needs to be fetched
    +  -> SwaggerPetstoreRequest GetOrderById MimeNoContent Order
    +getOrderById orderId =
    +  _mkRequest "GET" ["/store/order/",toPath orderId]
    +    
    +
    +data GetOrderById  
    +-- | @application/xml@
    +instance Produces GetOrderById MimeXML
    +-- | @application/json@
    +instance Produces GetOrderById MimeJSON
    +
    +
    +-- *** placeOrder
    +
    +-- | @POST \/store\/order@
    +-- 
    +-- Place an order for a pet
    +-- 
    +-- 
    +-- 
    +placeOrder 
    +  :: (Consumes PlaceOrder contentType, MimeRender contentType Order)
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> Order -- ^ "body" -  order placed for purchasing the pet
    +  -> SwaggerPetstoreRequest PlaceOrder contentType Order
    +placeOrder _ body =
    +  _mkRequest "POST" ["/store/order"]
    +    `setBodyParam` body
    +
    +data PlaceOrder 
    +
    +-- | /Body Param/ "body" - order placed for purchasing the pet
    +instance HasBodyParam PlaceOrder Order 
    +-- | @application/xml@
    +instance Produces PlaceOrder MimeXML
    +-- | @application/json@
    +instance Produces PlaceOrder MimeJSON
    +
    +
    +-- ** User
    +
    +-- *** createUser
    +
    +-- | @POST \/user@
    +-- 
    +-- Create user
    +-- 
    +-- This can only be done by the logged in user.
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +createUser 
    +  :: (Consumes CreateUser contentType, MimeRender contentType User)
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> User -- ^ "body" -  Created user object
    +  -> SwaggerPetstoreRequest CreateUser contentType res
    +createUser _ body =
    +  _mkRequest "POST" ["/user"]
    +    `setBodyParam` body
    +
    +data CreateUser 
    +
    +-- | /Body Param/ "body" - Created user object
    +instance HasBodyParam CreateUser User 
    +-- | @application/xml@
    +instance Produces CreateUser MimeXML
    +-- | @application/json@
    +instance Produces CreateUser MimeJSON
    +
    +
    +-- *** createUsersWithArrayInput
    +
    +-- | @POST \/user\/createWithArray@
    +-- 
    +-- Creates list of users with given input array
    +-- 
    +-- 
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +createUsersWithArrayInput 
    +  :: (Consumes CreateUsersWithArrayInput contentType, MimeRender contentType [User])
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> [User] -- ^ "body" -  List of user object
    +  -> SwaggerPetstoreRequest CreateUsersWithArrayInput contentType res
    +createUsersWithArrayInput _ body =
    +  _mkRequest "POST" ["/user/createWithArray"]
    +    `setBodyParam` body
    +
    +data CreateUsersWithArrayInput 
    +
    +-- | /Body Param/ "body" - List of user object
    +instance HasBodyParam CreateUsersWithArrayInput [User] 
    +-- | @application/xml@
    +instance Produces CreateUsersWithArrayInput MimeXML
    +-- | @application/json@
    +instance Produces CreateUsersWithArrayInput MimeJSON
    +
    +
    +-- *** createUsersWithListInput
    +
    +-- | @POST \/user\/createWithList@
    +-- 
    +-- Creates list of users with given input array
    +-- 
    +-- 
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +createUsersWithListInput 
    +  :: (Consumes CreateUsersWithListInput contentType, MimeRender contentType [User])
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> [User] -- ^ "body" -  List of user object
    +  -> SwaggerPetstoreRequest CreateUsersWithListInput contentType res
    +createUsersWithListInput _ body =
    +  _mkRequest "POST" ["/user/createWithList"]
    +    `setBodyParam` body
    +
    +data CreateUsersWithListInput 
    +
    +-- | /Body Param/ "body" - List of user object
    +instance HasBodyParam CreateUsersWithListInput [User] 
    +-- | @application/xml@
    +instance Produces CreateUsersWithListInput MimeXML
    +-- | @application/json@
    +instance Produces CreateUsersWithListInput MimeJSON
    +
    +
    +-- *** deleteUser
    +
    +-- | @DELETE \/user\/{username}@
    +-- 
    +-- Delete user
    +-- 
    +-- This can only be done by the logged in user.
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +deleteUser 
    +  :: Text -- ^ "username" -  The name that needs to be deleted
    +  -> SwaggerPetstoreRequest DeleteUser MimeNoContent res
    +deleteUser username =
    +  _mkRequest "DELETE" ["/user/",toPath username]
    +    
    +
    +data DeleteUser  
    +-- | @application/xml@
    +instance Produces DeleteUser MimeXML
    +-- | @application/json@
    +instance Produces DeleteUser MimeJSON
    +
    +
    +-- *** getUserByName
    +
    +-- | @GET \/user\/{username}@
    +-- 
    +-- Get user by user name
    +-- 
    +-- 
    +-- 
    +getUserByName 
    +  :: Text -- ^ "username" -  The name that needs to be fetched. Use user1 for testing. 
    +  -> SwaggerPetstoreRequest GetUserByName MimeNoContent User
    +getUserByName username =
    +  _mkRequest "GET" ["/user/",toPath username]
    +    
    +
    +data GetUserByName  
    +-- | @application/xml@
    +instance Produces GetUserByName MimeXML
    +-- | @application/json@
    +instance Produces GetUserByName MimeJSON
    +
    +
    +-- *** loginUser
    +
    +-- | @GET \/user\/login@
    +-- 
    +-- Logs user into the system
    +-- 
    +-- 
    +-- 
    +loginUser 
    +  :: Text -- ^ "username" -  The user name for login
    +  -> Text -- ^ "password" -  The password for login in clear text
    +  -> SwaggerPetstoreRequest LoginUser MimeNoContent Text
    +loginUser username password =
    +  _mkRequest "GET" ["/user/login"]
    +    `_setQuery` toQuery ("username", Just username)
    +    `_setQuery` toQuery ("password", Just password)
    +
    +data LoginUser  
    +-- | @application/xml@
    +instance Produces LoginUser MimeXML
    +-- | @application/json@
    +instance Produces LoginUser MimeJSON
    +
    +
    +-- *** logoutUser
    +
    +-- | @GET \/user\/logout@
    +-- 
    +-- Logs out current logged in user session
    +-- 
    +-- 
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +logoutUser 
    +  :: SwaggerPetstoreRequest LogoutUser MimeNoContent res
    +logoutUser =
    +  _mkRequest "GET" ["/user/logout"]
    +
    +data LogoutUser  
    +-- | @application/xml@
    +instance Produces LogoutUser MimeXML
    +-- | @application/json@
    +instance Produces LogoutUser MimeJSON
    +
    +
    +-- *** updateUser
    +
    +-- | @PUT \/user\/{username}@
    +-- 
    +-- Updated user
    +-- 
    +-- This can only be done by the logged in user.
    +-- 
    +-- Note: Has 'Produces' instances, but no response schema
    +-- 
    +updateUser 
    +  :: (Consumes UpdateUser contentType, MimeRender contentType User)
    +  => contentType -- ^ request content-type ('MimeType')
    +  -> Text -- ^ "username" -  name that need to be deleted
    +  -> User -- ^ "body" -  Updated user object
    +  -> SwaggerPetstoreRequest UpdateUser contentType res
    +updateUser _ username body =
    +  _mkRequest "PUT" ["/user/",toPath username]
    +    
    +    `setBodyParam` body
    +
    +data UpdateUser 
    +
    +-- | /Body Param/ "body" - Updated user object
    +instance HasBodyParam UpdateUser User 
    +-- | @application/xml@
    +instance Produces UpdateUser MimeXML
    +-- | @application/json@
    +instance Produces UpdateUser MimeJSON
    +
    +
    +
    +-- * HasBodyParam
    +
    +-- | Designates the body parameter of a request
    +class HasBodyParam req param where
    +  setBodyParam :: forall contentType res. (Consumes req contentType, MimeRender contentType param) => SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res
    +  setBodyParam req xs =
    +    req `_setBodyLBS` mimeRender (P.Proxy :: P.Proxy contentType) xs & _setContentTypeHeader
    +
    +-- * HasOptionalParam
    +
    +-- | Designates the optional parameters of a request
    +class HasOptionalParam req param where
    +  {-# MINIMAL applyOptionalParam | (-&-) #-}
    +
    +  -- | Apply an optional parameter to a request
    +  applyOptionalParam :: SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res
    +  applyOptionalParam = (-&-)
    +  {-# INLINE applyOptionalParam #-}
    +
    +  -- | infix operator \/ alias for 'addOptionalParam'
    +  (-&-) :: SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res
    +  (-&-) = applyOptionalParam
    +  {-# INLINE (-&-) #-}
    +
    +infixl 2 -&-
    + 
    +-- * Optional Request Parameter Types
    +
    +
    +newtype ApiUnderscorekey = ApiUnderscorekey { unApiUnderscorekey :: Text } deriving (P.Eq, P.Show)
    +
    +newtype Name = Name { unName :: Text } deriving (P.Eq, P.Show)
    +
    +newtype Status = Status { unStatus :: Text } deriving (P.Eq, P.Show)
    +
    +newtype AdditionalMetadata = AdditionalMetadata { unAdditionalMetadata :: Text } deriving (P.Eq, P.Show)
    +
    +newtype File = File { unFile :: FilePath } deriving (P.Eq, P.Show)
    +
    +
    +-- * SwaggerPetstoreRequest
    +
    +-- | Represents a request. The "req" type variable is the request type. The "res" type variable is the response type.
    +data SwaggerPetstoreRequest req contentType res = SwaggerPetstoreRequest
    +  { rMethod  :: NH.Method   -- ^ Method of SwaggerPetstoreRequest
    +  , urlPath :: [BCL.ByteString] -- ^ Endpoint of SwaggerPetstoreRequest
    +  , params   :: Params -- ^ params of SwaggerPetstoreRequest
    +  }
    +  deriving (P.Show)
    +
    +-- | Request Params
    +data Params = Params
    +  { paramsQuery :: NH.Query
    +  , paramsHeaders :: NH.RequestHeaders
    +  , paramsBody :: ParamBody
    +  }
    +  deriving (P.Show)
    +
    +-- | Request Body
    +data ParamBody
    +  = ParamBodyNone
    +  | ParamBodyB B.ByteString
    +  | ParamBodyBL BL.ByteString
    +  | ParamBodyFormUrlEncoded WH.Form
    +  | ParamBodyMultipartFormData [NH.Part]
    +  deriving (P.Show)
    +
    +-- ** SwaggerPetstoreRequest Utils
    +
    +_mkRequest :: NH.Method -- ^ Method 
    +          -> [BCL.ByteString] -- ^ Endpoint
    +          -> SwaggerPetstoreRequest req contentType res -- ^ req: Request Type, res: Response Type
    +_mkRequest m u = SwaggerPetstoreRequest m u _mkParams
    +
    +_mkParams :: Params
    +_mkParams = Params [] [] ParamBodyNone
    +
    +setHeader :: SwaggerPetstoreRequest req contentType res -> [NH.Header] -> SwaggerPetstoreRequest req contentType res
    +setHeader req header = 
    +    let _params = params (req `removeHeader` P.fmap P.fst header)
    +    in req { params = _params { paramsHeaders = header P.++ paramsHeaders _params } }
    +
    +removeHeader :: SwaggerPetstoreRequest req contentType res -> [NH.HeaderName] -> SwaggerPetstoreRequest req contentType res
    +removeHeader req header = 
    +    let _params = params req
    +    in req { params = _params { paramsHeaders = [h | h <- paramsHeaders _params, cifst h `P.notElem` P.fmap CI.mk header] } }
    +  where cifst = CI.mk . P.fst
    +
    +
    +_setContentTypeHeader :: forall req contentType res. MimeType contentType => SwaggerPetstoreRequest req contentType res -> SwaggerPetstoreRequest req contentType res
    +_setContentTypeHeader req =
    +    case mimeType (P.Proxy :: P.Proxy contentType) of 
    +        Just m -> req `setHeader` [("content-type", BC.pack $ P.show m)]
    +        Nothing -> req `removeHeader` ["content-type"]
    +
    +_setAcceptHeader :: forall req contentType res accept. MimeType accept => SwaggerPetstoreRequest req contentType res -> accept -> SwaggerPetstoreRequest req contentType res
    +_setAcceptHeader req accept =
    +    case mimeType' accept of 
    +        Just m -> req `setHeader` [("accept", BC.pack $ P.show m)]
    +        Nothing -> req `removeHeader` ["accept"]
    +
    +_setQuery :: SwaggerPetstoreRequest req contentType res -> [NH.QueryItem] -> SwaggerPetstoreRequest req contentType res
    +_setQuery req query = 
    +    let _params = params req 
    +    in req { params = _params { paramsQuery = query P.++ [q | q <- paramsQuery _params, cifst q `P.notElem` P.fmap cifst query] } }
    +  where cifst = CI.mk . P.fst
    +
    +_addForm :: SwaggerPetstoreRequest req contentType res -> WH.Form -> SwaggerPetstoreRequest req contentType res
    +_addForm req newform = 
    +    let _params = params req
    +        form = case paramsBody _params of
    +            ParamBodyFormUrlEncoded _form -> _form
    +            _ -> mempty
    +    in req { params = _params { paramsBody = ParamBodyFormUrlEncoded (newform <> form) } }
    +
    +_addMultiFormPart :: SwaggerPetstoreRequest req contentType res -> NH.Part -> SwaggerPetstoreRequest req contentType res
    +_addMultiFormPart req newpart = 
    +    let _params = params req
    +        parts = case paramsBody _params of
    +            ParamBodyMultipartFormData _parts -> _parts
    +            _ -> []
    +    in req { params = _params { paramsBody = ParamBodyMultipartFormData (newpart : parts) } }
    +
    +_setBodyBS :: SwaggerPetstoreRequest req contentType res -> B.ByteString -> SwaggerPetstoreRequest req contentType res
    +_setBodyBS req body = 
    +    let _params = params req
    +    in req { params = _params { paramsBody = ParamBodyB body } }
    +
    +_setBodyLBS :: SwaggerPetstoreRequest req contentType res -> BL.ByteString -> SwaggerPetstoreRequest req contentType res
    +_setBodyLBS req body = 
    +    let _params = params req
    +    in req { params = _params { paramsBody = ParamBodyBL body } }
    +
    +
    +-- ** Params Utils
    +
    +toPath
    +  :: WH.ToHttpApiData a
    +  => a -> BCL.ByteString
    +toPath = BB.toLazyByteString . WH.toEncodedUrlPiece
    +
    +toHeader :: WH.ToHttpApiData a => (NH.HeaderName, a) -> [NH.Header]
    +toHeader x = [fmap WH.toHeader x]
    +
    +toForm :: WH.ToHttpApiData v => (BC.ByteString, v) -> WH.Form
    +toForm (k,v) = WH.toForm [(BC.unpack k,v)]
    +
    +toQuery :: WH.ToHttpApiData a => (BC.ByteString, Maybe a) -> [NH.QueryItem]
    +toQuery x = [(fmap . fmap) toQueryParam x]
    +  where toQueryParam = T.encodeUtf8 . WH.toQueryParam
    +
    +-- *** Swagger `CollectionFormat` Utils
    +
    +-- | Determines the format of the array if type array is used.
    +data CollectionFormat
    +  = CommaSeparated -- ^ CSV format for multiple parameters.
    +  | SpaceSeparated -- ^ Also called "SSV"
    +  | TabSeparated -- ^ Also called "TSV"
    +  | PipeSeparated -- ^ `value1|value2|value2`
    +  | MultiParamArray -- ^ Using multiple GET parameters, e.g. `foo=bar&foo=baz`. This is valid only for parameters in "query" ('NH.Query') or "formData" ('WH.Form')
    +
    +toHeaderColl :: WH.ToHttpApiData a => CollectionFormat -> (NH.HeaderName, [a]) -> [NH.Header]
    +toHeaderColl c xs = _toColl c toHeader xs
    +
    +toFormColl :: WH.ToHttpApiData v => CollectionFormat -> (BC.ByteString, [v]) -> WH.Form
    +toFormColl c xs = WH.toForm $ fmap unpack $ _toColl c toHeader $ pack xs
    +  where
    +    pack (k,v) = (CI.mk k, v)
    +    unpack (k,v) = (BC.unpack (CI.original k), BC.unpack v)
    +
    +toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query
    +toQueryColl c xs = _toCollA c toQuery xs
    +
    +_toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)]
    +_toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs))
    +  where fencode = fmap (fmap Just) . encode . fmap P.fromJust
    +        {-# INLINE fencode #-}
    +
    +_toCollA :: (P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t BC.ByteString)]) -> f (t [a]) -> [(b, t BC.ByteString)]
    +_toCollA c encode xs = _toCollA' c encode BC.singleton xs
    +
    +_toCollA' :: (P.Monoid c, P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t c)]) -> (Char -> c) -> f (t [a]) -> [(b, t c)]
    +_toCollA' c encode one xs = case c of
    +  CommaSeparated -> go (one ',')
    +  SpaceSeparated -> go (one ' ')
    +  TabSeparated -> go (one '\t')
    +  PipeSeparated -> go (one '|')
    +  MultiParamArray -> expandList
    +  where
    +    go sep =
    +      [P.foldl1 (\(sk, sv) (_, v) -> (sk, (combine sep <$> sv <*> v) <|> sv <|> v)) expandList]
    +    combine sep x y = x <> sep <> y
    +    expandList = (P.concatMap encode . (P.traverse . P.traverse) P.toList) xs
    +    {-# INLINE go #-}
    +    {-# INLINE expandList #-}
    +    {-# INLINE combine #-}
    +  
    +
    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Client.html b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Client.html new file mode 100644 index 00000000000..22411c07f3b --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Client.html @@ -0,0 +1,318 @@ +
    {-|
    +Module : SwaggerPetstore.Client
    +-}
    +
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# LANGUAGE RankNTypes #-}
    +{-# LANGUAGE RecordWildCards #-}
    +{-# LANGUAGE FlexibleContexts #-}
    +{-# LANGUAGE ScopedTypeVariables #-}
    +{-# LANGUAGE DeriveFunctor #-}
    +{-# LANGUAGE DeriveFoldable #-}
    +{-# LANGUAGE DeriveTraversable #-}
    +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-}
    +
    +module SwaggerPetstore.Client where
    +
    +import SwaggerPetstore.Model
    +import SwaggerPetstore.API
    +import SwaggerPetstore.MimeTypes
    +
    +import qualified Control.Monad.IO.Class as P
    +import qualified Data.Aeson as A
    +import qualified Data.Aeson.Types as A
    +import qualified Data.Proxy as P (Proxy(..))
    +import Data.Function ((&))
    +import Data.Monoid ((<>))
    +import Data.Text (Text)
    +import GHC.Exts (IsString(..))
    +import Web.FormUrlEncoded as WH
    +import Web.HttpApiData as WH
    +import Control.Monad.Catch (MonadThrow)
    +
    +import qualified Control.Monad.Logger as LG
    +
    +import qualified Data.Time as TI
    +import qualified Data.Map as Map
    +import qualified Data.Text as T
    +import qualified Data.Text.Encoding as T
    +import qualified Text.Printf as T
    +
    +import qualified Data.ByteString as B
    +import qualified Data.ByteString.Lazy as BL
    +import qualified Data.ByteString.Char8 as BC
    +import qualified Data.ByteString.Lazy.Char8 as BCL
    +import qualified Data.ByteString.Builder as BB
    +import qualified Network.HTTP.Client as NH
    +import qualified Network.HTTP.Client.TLS as NH
    +import qualified Network.HTTP.Client.MultipartFormData as NH
    +import qualified Network.HTTP.Types.Method as NH
    +import qualified Network.HTTP.Types as NH
    +import qualified Network.HTTP.Types.URI as NH
    +
    +import qualified Control.Exception.Safe as E
    +-- * Config
    +
    +-- | 
    +data SwaggerPetstoreConfig = SwaggerPetstoreConfig
    +  { configHost  :: BCL.ByteString -- ^ host supplied in the Request
    +  , configUserAgent :: Text -- ^ user-agent supplied in the Request
    +  , configExecLoggingT :: ExecLoggingT -- ^ Run a block using a MonadLogger instance
    +  , configLoggingFilter :: LG.LogSource -> LG.LogLevel -> Bool -- ^ Only log messages passing the given predicate function.
    +  }
    +
    +-- | display the config
    +instance Show SwaggerPetstoreConfig where
    +  show c =
    +    T.printf
    +      "{ configHost = %v, configUserAgent = %v, ..}"
    +      (show (configHost c))
    +      (show (configUserAgent c))
    +
    +-- | constructs a default SwaggerPetstoreConfig
    +--
    +-- configHost:
    +--
    +-- @http://petstore.swagger.io/v2@
    +--
    +-- configUserAgent:
    +--
    +-- @"swagger-haskell-http-client/1.0.0"@
    +--
    +-- configExecLoggingT: 'runNullLoggingT'
    +--
    +-- configLoggingFilter: 'infoLevelFilter'
    +newConfig :: SwaggerPetstoreConfig
    +newConfig =
    +  SwaggerPetstoreConfig
    +  { configHost = "http://petstore.swagger.io/v2"
    +  , configUserAgent = "swagger-haskell-http-client/1.0.0"
    +  , configExecLoggingT = runNullLoggingT
    +  , configLoggingFilter = infoLevelFilter
    +  }
    +
    +-- | updates the config to use a MonadLogger instance which prints to stdout.
    +withStdoutLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig
    +withStdoutLogging p = p { configExecLoggingT = LG.runStdoutLoggingT}
    +
    +-- | updates the config to use a MonadLogger instance which prints to stderr.
    +withStderrLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig
    +withStderrLogging p = p { configExecLoggingT = LG.runStderrLoggingT}
    +
    +-- | updates the config to disable logging
    +withNoLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig
    +withNoLogging p = p { configExecLoggingT = runNullLoggingT}
    +
    +-- * Dispatch
    +
    +-- ** Lbs
    +
    +-- | send a request returning the raw http response
    +dispatchLbs
    +  :: (Produces req accept, MimeType contentType)
    +  => NH.Manager -- ^ http-client Connection manager
    +  -> SwaggerPetstoreConfig -- ^ config
    +  -> SwaggerPetstoreRequest req contentType res -- ^ request
    +  -> accept -- ^ "accept" 'MimeType'
    +  -> IO (NH.Response BCL.ByteString) -- ^ response
    +dispatchLbs manager config request accept = do
    +  initReq <- _toInitRequest config request accept 
    +  dispatchInitUnsafe manager config initReq
    +
    +-- ** Mime
    +
    +-- | pair of decoded http body and http response
    +data MimeResult res =
    +  MimeResult { mimeResult :: Either MimeError res -- ^ decoded http body
    +             , mimeResultResponse :: NH.Response BCL.ByteString -- ^ http response 
    +             }
    +  deriving (Show, Functor, Foldable, Traversable)
    +
    +-- | pair of unrender/parser error and http response
    +data MimeError =
    +  MimeError {
    +    mimeError :: String -- ^ unrender/parser error
    +  , mimeErrorResponse :: NH.Response BCL.ByteString -- ^ http response 
    +  } deriving (Eq, Show)
    +
    +-- | send a request returning the 'MimeResult'
    +dispatchMime
    +  :: (Produces req accept, MimeUnrender accept res, MimeType contentType)
    +  => NH.Manager -- ^ http-client Connection manager
    +  -> SwaggerPetstoreConfig -- ^ config
    +  -> SwaggerPetstoreRequest req contentType res -- ^ request
    +  -> accept -- ^ "accept" 'MimeType'
    +  -> IO (MimeResult res) -- ^ response
    +dispatchMime manager config request accept = do
    +  httpResponse <- dispatchLbs manager config request accept
    +  parsedResult <-
    +    runExceptionLoggingT "Client" config $
    +    do case mimeUnrender' accept (NH.responseBody httpResponse) of
    +         Left s -> do
    +           logNST LG.LevelError "Client" (T.pack s)
    +           pure (Left (MimeError s httpResponse))
    +         Right r -> pure (Right r)
    +  return (MimeResult parsedResult httpResponse)
    +
    +-- | like 'dispatchMime', but only returns the decoded http body
    +dispatchMime'
    +  :: (Produces req accept, MimeUnrender accept res, MimeType contentType)
    +  => NH.Manager -- ^ http-client Connection manager
    +  -> SwaggerPetstoreConfig -- ^ config
    +  -> SwaggerPetstoreRequest req contentType res -- ^ request
    +  -> accept -- ^ "accept" 'MimeType'
    +  -> IO (Either MimeError res) -- ^ response
    +dispatchMime' manager config request accept = do
    +    MimeResult parsedResult _ <- dispatchMime manager config request accept 
    +    return parsedResult
    +
    +-- ** Unsafe
    +
    +-- | like 'dispatchReqLbs', but does not validate the operation is a 'Producer' of the "accept" 'MimeType'.  (Useful if the server's response is undocumented)
    +dispatchLbsUnsafe
    +  :: (MimeType accept, MimeType contentType)
    +  => NH.Manager -- ^ http-client Connection manager
    +  -> SwaggerPetstoreConfig -- ^ config
    +  -> SwaggerPetstoreRequest req contentType res -- ^ request
    +  -> accept -- ^ "accept" 'MimeType'
    +  -> IO (NH.Response BCL.ByteString) -- ^ response
    +dispatchLbsUnsafe manager config request accept = do
    +  initReq <- _toInitRequest config request accept
    +  dispatchInitUnsafe manager config initReq
    +
    +-- | dispatch an InitRequest
    +dispatchInitUnsafe
    +  :: NH.Manager -- ^ http-client Connection manager
    +  -> SwaggerPetstoreConfig -- ^ config
    +  -> InitRequest req contentType res accept -- ^ init request
    +  -> IO (NH.Response BCL.ByteString) -- ^ response
    +dispatchInitUnsafe manager config (InitRequest req) = do
    +  runExceptionLoggingT logSrc config $
    +    do logNST LG.LevelInfo logSrc requestLogMsg
    +       logNST LG.LevelDebug logSrc requestDbgLogMsg
    +       res <- P.liftIO $ NH.httpLbs req manager
    +       logNST LG.LevelInfo logSrc (responseLogMsg res)
    +       logNST LG.LevelDebug logSrc ((T.pack . show) res)
    +       return res
    +  where
    +    logSrc = "Client"
    +    endpoint =
    +      T.pack $
    +      BC.unpack $
    +      NH.method req <> " " <> NH.host req <> NH.path req <> NH.queryString req
    +    requestLogMsg = "REQ:" <> endpoint
    +    requestDbgLogMsg =
    +      "Headers=" <> (T.pack . show) (NH.requestHeaders req) <> " Body=" <>
    +      (case NH.requestBody req of
    +         NH.RequestBodyLBS xs -> T.decodeUtf8 (BL.toStrict xs)
    +         _ -> "<RequestBody>")
    +    responseStatusCode = (T.pack . show) . NH.statusCode . NH.responseStatus
    +    responseLogMsg res =
    +      "RES:statusCode=" <> responseStatusCode res <> " (" <> endpoint <> ")"
    +
    +-- * InitRequest
    +
    +-- | wraps an http-client 'Request' with request/response type parameters
    +newtype InitRequest req contentType res accept = InitRequest
    +  { unInitRequest :: NH.Request
    +  } deriving (Show)
    +
    +-- |  Build an http-client 'Request' record from the supplied config and request
    +_toInitRequest
    +  :: (MimeType accept, MimeType contentType)
    +  => SwaggerPetstoreConfig -- ^ config
    +  -> SwaggerPetstoreRequest req contentType res -- ^ request
    +  -> accept -- ^ "accept" 'MimeType'
    +  -> IO (InitRequest req contentType res accept) -- ^ initialized request
    +_toInitRequest config req0 accept = do
    +  parsedReq <- NH.parseRequest $ BCL.unpack $ BCL.append (configHost config) (BCL.concat (urlPath req0))
    +  let req1 = _setAcceptHeader req0 accept & _setContentTypeHeader
    +      reqHeaders = ("User-Agent", WH.toHeader (configUserAgent config)) : paramsHeaders (params req1)
    +      reqQuery = NH.renderQuery True (paramsQuery (params req1))
    +      pReq = parsedReq { NH.method = (rMethod req1)
    +                       , NH.requestHeaders = reqHeaders
    +                       , NH.queryString = reqQuery
    +                       }
    +  outReq <- case paramsBody (params req1) of
    +    ParamBodyNone -> pure (pReq { NH.requestBody = mempty })
    +    ParamBodyB bs -> pure (pReq { NH.requestBody = NH.RequestBodyBS bs })
    +    ParamBodyBL bl -> pure (pReq { NH.requestBody = NH.RequestBodyLBS bl })
    +    ParamBodyFormUrlEncoded form -> pure (pReq { NH.requestBody = NH.RequestBodyLBS (WH.urlEncodeForm form) })
    +    ParamBodyMultipartFormData parts -> NH.formDataBody parts pReq
    +
    +  pure (InitRequest outReq)
    +
    +-- | modify the underlying Request
    +modifyInitRequest :: InitRequest req contentType res accept -> (NH.Request -> NH.Request) -> InitRequest req contentType res accept 
    +modifyInitRequest (InitRequest req) f = InitRequest (f req)
    +
    +-- | modify the underlying Request (monadic)
    +modifyInitRequestM :: Monad m => InitRequest req contentType res accept -> (NH.Request -> m NH.Request) -> m (InitRequest req contentType res accept)
    +modifyInitRequestM (InitRequest req) f = fmap InitRequest (f req)
    +
    +-- * Logging
    +
    +-- | A block using a MonadLogger instance
    +type ExecLoggingT = forall m. P.MonadIO m =>
    +                              forall a. LG.LoggingT m a -> m a
    +
    +-- ** Null Logger
    +
    +-- | a logger which disables logging
    +nullLogger :: LG.Loc -> LG.LogSource -> LG.LogLevel -> LG.LogStr -> IO ()
    +nullLogger _ _ _ _ = return ()
    +
    +-- | run the monad transformer that disables logging
    +runNullLoggingT :: LG.LoggingT m a -> m a
    +runNullLoggingT = (`LG.runLoggingT` nullLogger)
    +
    +-- ** Logging Filters
    +
    +-- | a log filter that uses 'LevelError' as the minimum logging level
    +errorLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool
    +errorLevelFilter = minLevelFilter LG.LevelError
    +
    +-- | a log filter that uses 'LevelInfo' as the minimum logging level
    +infoLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool
    +infoLevelFilter = minLevelFilter LG.LevelInfo
    +
    +-- | a log filter that uses 'LevelDebug' as the minimum logging level
    +debugLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool
    +debugLevelFilter = minLevelFilter LG.LevelDebug
    +
    +minLevelFilter :: LG.LogLevel -> LG.LogSource -> LG.LogLevel -> Bool
    +minLevelFilter l _ l' = l' >= l
    +
    +-- ** Logging 
    +
    +-- | Log a message using the current time
    +logNST :: (P.MonadIO m, LG.MonadLogger m) => LG.LogLevel -> Text -> Text -> m ()
    +logNST level src msg = do
    +  now <- P.liftIO (formatTimeLog <$> TI.getCurrentTime)
    +  LG.logOtherNS sourceLog level (now <> " " <> msg)
    + where
    +  sourceLog = "SwaggerPetstore/" <> src
    +  formatTimeLog =
    +    T.pack . TI.formatTime TI.defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Z"
    +
    +-- | re-throws exceptions after logging them
    +logExceptions
    +  :: (LG.MonadLogger m, E.MonadCatch m, P.MonadIO m)
    +  => Text -> m a -> m a
    +logExceptions src =
    +  E.handle
    +    (\(e :: E.SomeException) -> do
    +       logNST LG.LevelError src ((T.pack . show) e)
    +       E.throw e)
    +
    +-- | Run a block using the configured MonadLogger instance
    +runLoggingT :: SwaggerPetstoreConfig -> ExecLoggingT
    +runLoggingT config =
    +  configExecLoggingT config . LG.filterLogger (configLoggingFilter config)
    +
    +-- | Run a block using the configured MonadLogger instance (logs exceptions)
    +runExceptionLoggingT
    +  :: (E.MonadCatch m, P.MonadIO m)
    +  => T.Text -> SwaggerPetstoreConfig -> LG.LoggingT m a -> m a
    +runExceptionLoggingT logSrc config = runLoggingT config . logExceptions logSrc
    +
    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Lens.html b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Lens.html new file mode 100644 index 00000000000..80eecd30a60 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Lens.html @@ -0,0 +1,203 @@ +
    {-|
    +Module : SwaggerPetstore.Lens
    +-}
    +
    +{-# LANGUAGE KindSignatures #-}
    +{-# LANGUAGE NamedFieldPuns #-}
    +{-# LANGUAGE RankNTypes #-}
    +{-# LANGUAGE RecordWildCards #-}
    +{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-unused-imports #-}
    +
    +module SwaggerPetstore.Lens where
    +
    +import Data.Text (Text)
    +
    +import qualified Data.Aeson as A
    +import Data.Aeson (Value)
    +import qualified Data.ByteString as B
    +import Data.ByteString.Lazy (ByteString)
    +import qualified Data.Data as P (Data, Typeable)
    +import qualified Data.Map as Map
    +
    +import qualified Data.Time as TI
    +import Data.Time (UTCTime)
    +
    +import Prelude (($), (.),(<$>),(<*>),(=<<),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor)
    +import qualified Prelude as P
    +
    +import SwaggerPetstore.Model
    +
    +-- * Type Aliases
    +
    +type Traversal_' s a = Traversal_ s s a a
    +type Traversal_ s t a b = forall (f :: * -> *). Applicative f => (a -> f b) -> s -> f t
    +type Lens_' s a = Lens_ s s a a
    +type Lens_ s t a b = forall (f :: * -> *). Functor f => (a -> f b) -> s -> f t
    +
    +
    +-- * ApiResponse
    +
    +-- | 'apiResponseCode' Traversal
    +apiResponseCodeT :: Traversal_' ApiResponse Int
    +apiResponseCodeT f s = _mtraversal apiResponseCode (\b -> s { apiResponseCode = Just b}) f s
    +{-# INLINE apiResponseCodeT #-}
    +
    +-- | 'apiResponseType' Traversal
    +apiResponseTypeT :: Traversal_' ApiResponse Text
    +apiResponseTypeT f s = _mtraversal apiResponseType (\b -> s { apiResponseType = Just b}) f s
    +{-# INLINE apiResponseTypeT #-}
    +
    +-- | 'apiResponseMessage' Traversal
    +apiResponseMessageT :: Traversal_' ApiResponse Text
    +apiResponseMessageT f s = _mtraversal apiResponseMessage (\b -> s { apiResponseMessage = Just b}) f s
    +{-# INLINE apiResponseMessageT #-}
    +
    +
    +
    +-- * Category
    +
    +-- | 'categoryId' Traversal
    +categoryIdT :: Traversal_' Category Integer
    +categoryIdT f s = _mtraversal categoryId (\b -> s { categoryId = Just b}) f s
    +{-# INLINE categoryIdT #-}
    +
    +-- | 'categoryName' Traversal
    +categoryNameT :: Traversal_' Category Text
    +categoryNameT f s = _mtraversal categoryName (\b -> s { categoryName = Just b}) f s
    +{-# INLINE categoryNameT #-}
    +
    +
    +
    +-- * Order
    +
    +-- | 'orderId' Traversal
    +orderIdT :: Traversal_' Order Integer
    +orderIdT f s = _mtraversal orderId (\b -> s { orderId = Just b}) f s
    +{-# INLINE orderIdT #-}
    +
    +-- | 'orderPetId' Traversal
    +orderPetIdT :: Traversal_' Order Integer
    +orderPetIdT f s = _mtraversal orderPetId (\b -> s { orderPetId = Just b}) f s
    +{-# INLINE orderPetIdT #-}
    +
    +-- | 'orderQuantity' Traversal
    +orderQuantityT :: Traversal_' Order Int
    +orderQuantityT f s = _mtraversal orderQuantity (\b -> s { orderQuantity = Just b}) f s
    +{-# INLINE orderQuantityT #-}
    +
    +-- | 'orderShipDate' Traversal
    +orderShipDateT :: Traversal_' Order UTCTime
    +orderShipDateT f s = _mtraversal orderShipDate (\b -> s { orderShipDate = Just b}) f s
    +{-# INLINE orderShipDateT #-}
    +
    +-- | 'orderStatus' Traversal
    +orderStatusT :: Traversal_' Order Text
    +orderStatusT f s = _mtraversal orderStatus (\b -> s { orderStatus = Just b}) f s
    +{-# INLINE orderStatusT #-}
    +
    +-- | 'orderComplete' Traversal
    +orderCompleteT :: Traversal_' Order Bool
    +orderCompleteT f s = _mtraversal orderComplete (\b -> s { orderComplete = Just b}) f s
    +{-# INLINE orderCompleteT #-}
    +
    +
    +
    +-- * Pet
    +
    +-- | 'petId' Traversal
    +petIdT :: Traversal_' Pet Integer
    +petIdT f s = _mtraversal petId (\b -> s { petId = Just b}) f s
    +{-# INLINE petIdT #-}
    +
    +-- | 'petCategory' Traversal
    +petCategoryT :: Traversal_' Pet Category
    +petCategoryT f s = _mtraversal petCategory (\b -> s { petCategory = Just b}) f s
    +{-# INLINE petCategoryT #-}
    +
    +-- | 'petName' Lens
    +petNameL :: Lens_' Pet Text
    +petNameL f Pet{..} = (\petName -> Pet { petName, ..} ) <$> f petName
    +{-# INLINE petNameL #-}
    +
    +-- | 'petPhotoUrls' Lens
    +petPhotoUrlsL :: Lens_' Pet [Text]
    +petPhotoUrlsL f Pet{..} = (\petPhotoUrls -> Pet { petPhotoUrls, ..} ) <$> f petPhotoUrls
    +{-# INLINE petPhotoUrlsL #-}
    +
    +-- | 'petTags' Traversal
    +petTagsT :: Traversal_' Pet [Tag]
    +petTagsT f s = _mtraversal petTags (\b -> s { petTags = Just b}) f s
    +{-# INLINE petTagsT #-}
    +
    +-- | 'petStatus' Traversal
    +petStatusT :: Traversal_' Pet Text
    +petStatusT f s = _mtraversal petStatus (\b -> s { petStatus = Just b}) f s
    +{-# INLINE petStatusT #-}
    +
    +
    +
    +-- * Tag
    +
    +-- | 'tagId' Traversal
    +tagIdT :: Traversal_' Tag Integer
    +tagIdT f s = _mtraversal tagId (\b -> s { tagId = Just b}) f s
    +{-# INLINE tagIdT #-}
    +
    +-- | 'tagName' Traversal
    +tagNameT :: Traversal_' Tag Text
    +tagNameT f s = _mtraversal tagName (\b -> s { tagName = Just b}) f s
    +{-# INLINE tagNameT #-}
    +
    +
    +
    +-- * User
    +
    +-- | 'userId' Traversal
    +userIdT :: Traversal_' User Integer
    +userIdT f s = _mtraversal userId (\b -> s { userId = Just b}) f s
    +{-# INLINE userIdT #-}
    +
    +-- | 'userUsername' Traversal
    +userUsernameT :: Traversal_' User Text
    +userUsernameT f s = _mtraversal userUsername (\b -> s { userUsername = Just b}) f s
    +{-# INLINE userUsernameT #-}
    +
    +-- | 'userFirstName' Traversal
    +userFirstNameT :: Traversal_' User Text
    +userFirstNameT f s = _mtraversal userFirstName (\b -> s { userFirstName = Just b}) f s
    +{-# INLINE userFirstNameT #-}
    +
    +-- | 'userLastName' Traversal
    +userLastNameT :: Traversal_' User Text
    +userLastNameT f s = _mtraversal userLastName (\b -> s { userLastName = Just b}) f s
    +{-# INLINE userLastNameT #-}
    +
    +-- | 'userEmail' Traversal
    +userEmailT :: Traversal_' User Text
    +userEmailT f s = _mtraversal userEmail (\b -> s { userEmail = Just b}) f s
    +{-# INLINE userEmailT #-}
    +
    +-- | 'userPassword' Traversal
    +userPasswordT :: Traversal_' User Text
    +userPasswordT f s = _mtraversal userPassword (\b -> s { userPassword = Just b}) f s
    +{-# INLINE userPasswordT #-}
    +
    +-- | 'userPhone' Traversal
    +userPhoneT :: Traversal_' User Text
    +userPhoneT f s = _mtraversal userPhone (\b -> s { userPhone = Just b}) f s
    +{-# INLINE userPhoneT #-}
    +
    +-- | 'userUserStatus' Traversal
    +userUserStatusT :: Traversal_' User Int
    +userUserStatusT f s = _mtraversal userUserStatus (\b -> s { userUserStatus = Just b}) f s
    +{-# INLINE userUserStatusT #-}
    +
    +
    +
    +
    +-- * Helpers
    +
    +_mtraversal :: Applicative f => (b -> Maybe t) -> (a -> b) -> (t -> f a) -> b -> f b
    +_mtraversal x fsb f s = maybe (pure s) (\a -> fsb <$> f a) (x s)
    +{-# INLINE _mtraversal #-}
    +
    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.MimeTypes.html b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.MimeTypes.html new file mode 100644 index 00000000000..fa8a6de4131 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.MimeTypes.html @@ -0,0 +1,191 @@ +
    
    +{-|
    +Module : SwaggerPetstore.MimeTypes
    +-}
    +
    +{-# LANGUAGE ConstraintKinds #-}
    +{-# LANGUAGE FlexibleContexts #-}
    +{-# LANGUAGE FlexibleInstances #-}
    +{-# LANGUAGE MultiParamTypeClasses #-}
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# LANGUAGE ScopedTypeVariables #-}
    +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-}
    +
    +module SwaggerPetstore.MimeTypes where
    +
    +
    +import qualified Data.Aeson as A
    +
    +import qualified Data.ByteString as B
    +import qualified Data.ByteString.Lazy as BL
    +import qualified Data.ByteString.Builder as BB
    +import qualified Data.ByteString.Char8 as BC
    +import qualified Data.ByteString.Lazy.Char8 as BCL
    +
    +import qualified Network.HTTP.Media as ME
    +
    +import qualified Web.FormUrlEncoded as WH
    +
    +import qualified Data.Data as P (Typeable)
    +import qualified Data.Proxy as P (Proxy(..))
    +import qualified Data.Text as T
    +import qualified Data.Text.Encoding as T
    +import qualified Control.Arrow as P (left)
    +
    +import Prelude (($), (.),(<$>),(<*>),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty)
    +import qualified Prelude as P
    +
    +-- * Content Negotiation
    +
    +-- | A type for responses without content-body.
    +data NoContent = NoContent
    +  deriving (P.Show, P.Eq)
    +
    +-- ** Mime Types
    +
    +data MimeJSON = MimeJSON deriving (P.Typeable)
    +data MimeXML = MimeXML deriving (P.Typeable)
    +data MimePlainText = MimePlainText deriving (P.Typeable)
    +data MimeFormUrlEncoded = MimeFormUrlEncoded deriving (P.Typeable)
    +data MimeMultipartFormData = MimeMultipartFormData deriving (P.Typeable)
    +data MimeOctetStream = MimeOctetStream deriving (P.Typeable)
    +data MimeNoContent = MimeNoContent deriving (P.Typeable)
    +
    +
    +-- ** MimeType Class
    +
    +class P.Typeable mtype => MimeType mtype  where
    +  {-# MINIMAL mimeType | mimeTypes #-}
    +
    +  mimeTypes :: P.Proxy mtype -> [ME.MediaType]
    +  mimeTypes p =
    +    case mimeType p of
    +      Just x -> [x]
    +      Nothing -> []
    +
    +  mimeType :: P.Proxy mtype -> Maybe ME.MediaType
    +  mimeType p =
    +    case mimeTypes p of
    +      [] -> Nothing
    +      (x:_) -> Just x
    +
    +  mimeType' :: mtype -> Maybe ME.MediaType
    +  mimeType' _ = mimeType (P.Proxy :: P.Proxy mtype)
    +  mimeTypes' :: mtype -> [ME.MediaType]
    +  mimeTypes' _ = mimeTypes (P.Proxy :: P.Proxy mtype)
    +
    +-- ** MimeType Instances
    +
    +-- | @application/json@
    +instance MimeType MimeJSON where
    +  mimeTypes _ =
    +    [ "application" ME.// "json" ME./: ("charset", "utf-8")
    +    , "application" ME.// "json"
    +    ]
    +
    +-- | @application/xml@
    +instance MimeType MimeXML where
    +  mimeType _ = Just $ "application" ME.// "xml"
    +
    +-- | @application/x-www-form-urlencoded@
    +instance MimeType MimeFormUrlEncoded where
    +  mimeType _ = Just $ "application" ME.// "x-www-form-urlencoded"
    +
    +-- | @multipart/form-data@
    +instance MimeType MimeMultipartFormData where
    +  mimeType _ = Just $ "multipart" ME.// "form-data"
    +
    +-- | @text/plain;charset=utf-8@
    +instance MimeType MimePlainText where
    +  mimeType _ = Just $ "text" ME.// "plain" ME./: ("charset", "utf-8")
    +instance MimeType MimeOctetStream where
    +  mimeType _ = Just $ "application" ME.// "octet-stream"
    +instance MimeType MimeNoContent where
    +  mimeType _ = Nothing
    +
    +
    +-- ** MimeRender Class
    +
    +class MimeType mtype => MimeRender mtype x where
    +    mimeRender  :: P.Proxy mtype -> x -> BL.ByteString
    +    mimeRender' :: mtype -> x -> BL.ByteString
    +    mimeRender' _ x = mimeRender (P.Proxy :: P.Proxy mtype) x
    +
    +
    +-- ** MimeRender Instances
    +
    +-- | `A.encode`
    +instance A.ToJSON a => MimeRender MimeJSON a where mimeRender _ = A.encode
    +-- | @WH.urlEncodeAsForm@
    +instance WH.ToForm a => MimeRender MimeFormUrlEncoded a where mimeRender _ = WH.urlEncodeAsForm
    +
    +-- | @P.id@
    +instance MimeRender MimePlainText BL.ByteString where mimeRender _ = P.id
    +-- | @BL.fromStrict . T.encodeUtf8@
    +instance MimeRender MimePlainText T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8
    +-- | @BCL.pack@
    +instance MimeRender MimePlainText String where mimeRender _ = BCL.pack
    +
    +-- | @P.id@
    +instance MimeRender MimeOctetStream BL.ByteString where mimeRender _ = P.id
    +-- | @BL.fromStrict . T.encodeUtf8@
    +instance MimeRender MimeOctetStream T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8
    +-- | @BCL.pack@
    +instance MimeRender MimeOctetStream String where mimeRender _ = BCL.pack
    +
    +-- | @P.id@
    +instance MimeRender MimeMultipartFormData BL.ByteString where mimeRender _ = P.id
    +-- | @BL.fromStrict . T.encodeUtf8@
    +instance MimeRender MimeMultipartFormData T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8
    +-- | @BCL.pack@
    +instance MimeRender MimeMultipartFormData String where mimeRender _ = BCL.pack
    +
    +-- | @P.Right . P.const NoContent@
    +instance MimeRender MimeNoContent NoContent where mimeRender _ = P.const BCL.empty
    +
    +-- instance MimeRender MimeOctetStream Double where mimeRender _ = BB.toLazyByteString . BB.doubleDec
    +-- instance MimeRender MimeOctetStream Float where mimeRender _ = BB.toLazyByteString . BB.floatDec
    +-- instance MimeRender MimeOctetStream Int where mimeRender _ = BB.toLazyByteString . BB.intDec
    +-- instance MimeRender MimeOctetStream Integer where mimeRender _ = BB.toLazyByteString . BB.integerDec
    +
    +
    +-- ** MimeUnrender Class
    +
    +class MimeType mtype => MimeUnrender mtype o where
    +    mimeUnrender :: P.Proxy mtype -> BL.ByteString -> P.Either String o
    +    mimeUnrender' :: mtype -> BL.ByteString -> P.Either String o
    +    mimeUnrender' _ x = mimeUnrender (P.Proxy :: P.Proxy mtype) x
    +
    +-- ** MimeUnrender Instances
    +
    +-- | @A.eitherDecode@
    +instance A.FromJSON a => MimeUnrender MimeJSON a where mimeUnrender _ = A.eitherDecode
    +-- | @P.left T.unpack . WH.urlDecodeAsForm@
    +instance WH.FromForm a => MimeUnrender MimeFormUrlEncoded a where mimeUnrender _ = P.left T.unpack . WH.urlDecodeAsForm
    +-- | @P.Right . P.id@
    +
    +instance MimeUnrender MimePlainText BL.ByteString where mimeUnrender _ = P.Right . P.id
    +-- | @P.left P.show . TL.decodeUtf8'@
    +instance MimeUnrender MimePlainText T.Text where mimeUnrender _ = P.left P.show . T.decodeUtf8' . BL.toStrict
    +-- | @P.Right . BCL.unpack@
    +instance MimeUnrender MimePlainText String where mimeUnrender _ = P.Right . BCL.unpack
    +
    +-- | @P.Right . P.id@
    +instance MimeUnrender MimeOctetStream BL.ByteString where mimeUnrender _ = P.Right . P.id
    +-- | @P.left P.show . T.decodeUtf8' . BL.toStrict@
    +instance MimeUnrender MimeOctetStream T.Text where mimeUnrender _ = P.left P.show . T.decodeUtf8' . BL.toStrict
    +-- | @P.Right . BCL.unpack@
    +instance MimeUnrender MimeOctetStream String where mimeUnrender _ = P.Right . BCL.unpack
    +
    +-- | @P.Right . P.const NoContent@
    +instance MimeUnrender MimeNoContent NoContent where mimeUnrender _ = P.Right . P.const NoContent
    +
    +
    +-- ** Request Consumes
    +
    +class MimeType mtype => Consumes req mtype where
    +
    +-- ** Request Produces
    +
    +class MimeType mtype => Produces req mtype where
    +
    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Model.html b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Model.html new file mode 100644 index 00000000000..3d644d6fe5c --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.Model.html @@ -0,0 +1,378 @@ +
    {-|
    +Module : SwaggerPetstore.Model
    +-}
    +
    +{-# LANGUAGE DeriveAnyClass #-}
    +{-# LANGUAGE DeriveDataTypeable #-}
    +{-# LANGUAGE DeriveFoldable #-}
    +{-# LANGUAGE DeriveGeneric #-}
    +{-# LANGUAGE DeriveTraversable #-}
    +{-# LANGUAGE GeneralizedNewtypeDeriving #-}
    +{-# LANGUAGE NamedFieldPuns #-}
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# LANGUAGE RecordWildCards #-}
    +{-# LANGUAGE TupleSections #-}
    +{-# LANGUAGE TypeFamilies #-}
    +{-# OPTIONS_GHC -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-unused-imports #-}
    +
    +module SwaggerPetstore.Model where
    +
    +import Data.Aeson ((.:),(.:!),(.:?),(.=))
    +import Data.Text (Text)
    +
    +import Data.Aeson (Value)
    +import Data.ByteString.Lazy (ByteString)
    +
    +import qualified Data.Aeson as A
    +import qualified Data.ByteString as B
    +import qualified Data.Data as P (Data, Typeable)
    +import qualified Data.HashMap.Lazy as HM
    +import qualified Data.Map as Map
    +import qualified Data.Maybe as P
    +import qualified Data.Foldable as P
    +import qualified Web.FormUrlEncoded as WH
    +import qualified Web.HttpApiData as WH
    +
    +import qualified Data.Time as TI
    +import qualified Data.Time.ISO8601 as TI
    +import Data.Time (UTCTime)
    +
    +import Control.Applicative ((<|>))
    +import Control.Applicative (Alternative)
    +import Prelude (($), (.),(<$>),(<*>),(>>=),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor)
    +import qualified Prelude as P
    +
    +
    +
    +-- * Models
    +
    +
    +-- ** ApiResponse
    +-- |
    +-- An uploaded response
    +-- 
    +-- Describes the result of uploading an image resource
    +data ApiResponse = ApiResponse
    +  { apiResponseCode :: Maybe Int -- ^ "code"
    +  , apiResponseType :: Maybe Text -- ^ "type"
    +  , apiResponseMessage :: Maybe Text -- ^ "message"
    +  } deriving (P.Show,P.Eq,P.Typeable)
    +
    +instance A.FromJSON ApiResponse where
    +  parseJSON = A.withObject "ApiResponse" $ \o ->
    +    ApiResponse
    +      <$> (o .:? "code")
    +      <*> (o .:? "type")
    +      <*> (o .:? "message")
    +
    +instance A.ToJSON ApiResponse where
    +  toJSON ApiResponse {..} =
    +   _omitNulls
    +      [ "code" .=  apiResponseCode
    +      , "type" .=  apiResponseType
    +      , "message" .=  apiResponseMessage
    +      ]
    +
    +
    +-- | Construct a value of type 'ApiResponse' (by applying it's required fields, if any)
    +mkApiResponse
    +  :: ApiResponse
    +mkApiResponse =
    +  ApiResponse
    +  { apiResponseCode = Nothing
    +  , apiResponseType = Nothing
    +  , apiResponseMessage = Nothing
    +  }
    +  
    +
    +
    +-- ** Category
    +-- |
    +-- Pet catehgry
    +-- 
    +-- A category for a pet
    +data Category = Category
    +  { categoryId :: Maybe Integer -- ^ "id"
    +  , categoryName :: Maybe Text -- ^ "name"
    +  } deriving (P.Show,P.Eq,P.Typeable)
    +
    +instance A.FromJSON Category where
    +  parseJSON = A.withObject "Category" $ \o ->
    +    Category
    +      <$> (o .:? "id")
    +      <*> (o .:? "name")
    +
    +instance A.ToJSON Category where
    +  toJSON Category {..} =
    +   _omitNulls
    +      [ "id" .=  categoryId
    +      , "name" .=  categoryName
    +      ]
    +
    +
    +-- | Construct a value of type 'Category' (by applying it's required fields, if any)
    +mkCategory
    +  :: Category
    +mkCategory =
    +  Category
    +  { categoryId = Nothing
    +  , categoryName = Nothing
    +  }
    +  
    +
    +
    +-- ** Order
    +-- |
    +-- Pet Order
    +-- 
    +-- An order for a pets from the pet store
    +data Order = Order
    +  { orderId :: Maybe Integer -- ^ "id"
    +  , orderPetId :: Maybe Integer -- ^ "petId"
    +  , orderQuantity :: Maybe Int -- ^ "quantity"
    +  , orderShipDate :: Maybe UTCTime -- ^ "shipDate"
    +  , orderStatus :: Maybe Text -- ^ "status" - Order Status
    +  , orderComplete :: Maybe Bool -- ^ "complete"
    +  } deriving (P.Show,P.Eq,P.Typeable)
    +
    +instance A.FromJSON Order where
    +  parseJSON = A.withObject "Order" $ \o ->
    +    Order
    +      <$> (o .:? "id")
    +      <*> (o .:? "petId")
    +      <*> (o .:? "quantity")
    +      <*> (o .:? "shipDate" >>= P.mapM _readDateTime)
    +      <*> (o .:? "status")
    +      <*> (o .:? "complete")
    +
    +instance A.ToJSON Order where
    +  toJSON Order {..} =
    +   _omitNulls
    +      [ "id" .=  orderId
    +      , "petId" .=  orderPetId
    +      , "quantity" .=  orderQuantity
    +      , "shipDate" .= P.fmap _showDateTime orderShipDate
    +      , "status" .=  orderStatus
    +      , "complete" .=  orderComplete
    +      ]
    +
    +
    +-- | Construct a value of type 'Order' (by applying it's required fields, if any)
    +mkOrder
    +  :: Order
    +mkOrder =
    +  Order
    +  { orderId = Nothing
    +  , orderPetId = Nothing
    +  , orderQuantity = Nothing
    +  , orderShipDate = Nothing
    +  , orderStatus = Nothing
    +  , orderComplete = Nothing
    +  }
    +  
    +
    +
    +-- ** Pet
    +-- |
    +-- a Pet
    +-- 
    +-- A pet for sale in the pet store
    +data Pet = Pet
    +  { petId :: Maybe Integer -- ^ "id"
    +  , petCategory :: Maybe Category -- ^ "category"
    +  , petName :: Text -- ^ /Required/ "name"
    +  , petPhotoUrls :: [Text] -- ^ /Required/ "photoUrls"
    +  , petTags :: Maybe [Tag] -- ^ "tags"
    +  , petStatus :: Maybe Text -- ^ "status" - pet status in the store
    +  } deriving (P.Show,P.Eq,P.Typeable)
    +
    +instance A.FromJSON Pet where
    +  parseJSON = A.withObject "Pet" $ \o ->
    +    Pet
    +      <$> (o .:? "id")
    +      <*> (o .:? "category")
    +      <*> (o .:  "name")
    +      <*> (o .:  "photoUrls")
    +      <*> (o .:? "tags")
    +      <*> (o .:? "status")
    +
    +instance A.ToJSON Pet where
    +  toJSON Pet {..} =
    +   _omitNulls
    +      [ "id" .=  petId
    +      , "category" .=  petCategory
    +      , "name" .=  petName
    +      , "photoUrls" .=  petPhotoUrls
    +      , "tags" .=  petTags
    +      , "status" .=  petStatus
    +      ]
    +
    +
    +-- | Construct a value of type 'Pet' (by applying it's required fields, if any)
    +mkPet
    +  :: Text -- ^ 'petName' 
    +  -> [Text] -- ^ 'petPhotoUrls' 
    +  -> Pet
    +mkPet petName petPhotoUrls =
    +  Pet
    +  { petId = Nothing
    +  , petCategory = Nothing
    +  , petName
    +  , petPhotoUrls
    +  , petTags = Nothing
    +  , petStatus = Nothing
    +  }
    +  
    +
    +
    +-- ** Tag
    +-- |
    +-- Pet Tag
    +-- 
    +-- A tag for a pet
    +data Tag = Tag
    +  { tagId :: Maybe Integer -- ^ "id"
    +  , tagName :: Maybe Text -- ^ "name"
    +  } deriving (P.Show,P.Eq,P.Typeable)
    +
    +instance A.FromJSON Tag where
    +  parseJSON = A.withObject "Tag" $ \o ->
    +    Tag
    +      <$> (o .:? "id")
    +      <*> (o .:? "name")
    +
    +instance A.ToJSON Tag where
    +  toJSON Tag {..} =
    +   _omitNulls
    +      [ "id" .=  tagId
    +      , "name" .=  tagName
    +      ]
    +
    +
    +-- | Construct a value of type 'Tag' (by applying it's required fields, if any)
    +mkTag
    +  :: Tag
    +mkTag =
    +  Tag
    +  { tagId = Nothing
    +  , tagName = Nothing
    +  }
    +  
    +
    +
    +-- ** User
    +-- |
    +-- a User
    +-- 
    +-- A User who is purchasing from the pet store
    +data User = User
    +  { userId :: Maybe Integer -- ^ "id"
    +  , userUsername :: Maybe Text -- ^ "username"
    +  , userFirstName :: Maybe Text -- ^ "firstName"
    +  , userLastName :: Maybe Text -- ^ "lastName"
    +  , userEmail :: Maybe Text -- ^ "email"
    +  , userPassword :: Maybe Text -- ^ "password"
    +  , userPhone :: Maybe Text -- ^ "phone"
    +  , userUserStatus :: Maybe Int -- ^ "userStatus" - User Status
    +  } deriving (P.Show,P.Eq,P.Typeable)
    +
    +instance A.FromJSON User where
    +  parseJSON = A.withObject "User" $ \o ->
    +    User
    +      <$> (o .:? "id")
    +      <*> (o .:? "username")
    +      <*> (o .:? "firstName")
    +      <*> (o .:? "lastName")
    +      <*> (o .:? "email")
    +      <*> (o .:? "password")
    +      <*> (o .:? "phone")
    +      <*> (o .:? "userStatus")
    +
    +instance A.ToJSON User where
    +  toJSON User {..} =
    +   _omitNulls
    +      [ "id" .=  userId
    +      , "username" .=  userUsername
    +      , "firstName" .=  userFirstName
    +      , "lastName" .=  userLastName
    +      , "email" .=  userEmail
    +      , "password" .=  userPassword
    +      , "phone" .=  userPhone
    +      , "userStatus" .=  userUserStatus
    +      ]
    +
    +
    +-- | Construct a value of type 'User' (by applying it's required fields, if any)
    +mkUser
    +  :: User
    +mkUser =
    +  User
    +  { userId = Nothing
    +  , userUsername = Nothing
    +  , userFirstName = Nothing
    +  , userLastName = Nothing
    +  , userEmail = Nothing
    +  , userPassword = Nothing
    +  , userPhone = Nothing
    +  , userUserStatus = Nothing
    +  }
    +  
    +
    +
    +-- * Utils
    +
    +-- | Removes Null fields.  (OpenAPI-Specification 2.0 does not allow Null in JSON)
    +
    +_omitNulls :: [(Text, A.Value)] -> A.Value
    +_omitNulls = A.object . P.filter notNull
    +  where
    +    notNull (_, A.Null) = False
    +    notNull _ = True
    +
    +_toFormItem :: (WH.ToHttpApiData a, Functor f) => t -> f a -> f (t, [Text])
    +_toFormItem name x = (name,) . (:[]) . WH.toQueryParam <$> x
    +
    +_emptyToNothing :: Maybe String -> Maybe String
    +_emptyToNothing (Just "") = Nothing
    +_emptyToNothing x = x
    +{-# INLINE _emptyToNothing #-}
    +
    +_memptyToNothing :: (P.Monoid a, P.Eq a) => Maybe a -> Maybe a
    +_memptyToNothing (Just x) | x P.== P.mempty = Nothing
    +_memptyToNothing x = x
    +{-# INLINE _memptyToNothing #-}
    +
    +-- * DateTime Formatting
    +
    +-- | @_parseISO8601@
    +_readDateTime :: (TI.ParseTime t, Monad m, Alternative m) => String -> m t
    +_readDateTime =
    +  _parseISO8601
    +{-# INLINE _readDateTime #-}
    +
    +-- | @TI.formatISO8601Millis@
    +_showDateTime :: (t ~ UTCTime, TI.FormatTime t) => t -> String
    +_showDateTime =
    +  TI.formatISO8601Millis
    +{-# INLINE _showDateTime #-}
    +
    +_parseISO8601 :: (TI.ParseTime t, Monad m, Alternative m) => String -> m t
    +_parseISO8601 t =
    +  P.asum $
    +  P.flip (TI.parseTimeM True TI.defaultTimeLocale) t <$>
    +  ["%FT%T%QZ", "%FT%T%Q%z", "%FT%T%Q%Z"]
    +{-# INLINE _parseISO8601 #-}
    +
    +-- * Date Formatting
    +
    +-- | @TI.parseTimeM True TI.defaultTimeLocale ""@
    +_readDate :: (TI.ParseTime t, Monad m) => String -> m t
    +_readDate =
    +  TI.parseTimeM True TI.defaultTimeLocale ""
    +{-# INLINE _readDate #-}
    +
    +-- | @TI.formatTime TI.defaultTimeLocale ""@
    +_showDate :: TI.FormatTime t => t -> String
    +_showDate =
    +  TI.formatTime TI.defaultTimeLocale ""
    +{-# INLINE _showDate #-}
    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.html b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.html new file mode 100644 index 00000000000..2a5910ad33e --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/SwaggerPetstore.html @@ -0,0 +1,18 @@ +
    {-|
    +Module : SwaggerPetstore
    +-}
    +
    +module SwaggerPetstore
    +  ( module SwaggerPetstore.Client
    +  , module SwaggerPetstore.API
    +  , module SwaggerPetstore.Model
    +  , module SwaggerPetstore.MimeTypes
    +  , module SwaggerPetstore.Lens
    +  ) where
    +
    +import SwaggerPetstore.API
    +import SwaggerPetstore.Client
    +import SwaggerPetstore.Model
    +import SwaggerPetstore.MimeTypes
    +import SwaggerPetstore.Lens
    +
    \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/docs/src/highlight.js b/samples/client/petstore/haskell-http-client/docs/src/highlight.js new file mode 100644 index 00000000000..1e903bd0c59 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/highlight.js @@ -0,0 +1,27 @@ + +var highlight = function (on) { + return function () { + var links = document.getElementsByTagName('a'); + for (var i = 0; i < links.length; i++) { + var that = links[i]; + + if (this.href != that.href) { + continue; + } + + if (on) { + that.classList.add("hover-highlight"); + } else { + that.classList.remove("hover-highlight"); + } + } + } +}; + +window.onload = function () { + var links = document.getElementsByTagName('a'); + for (var i = 0; i < links.length; i++) { + links[i].onmouseover = highlight(true); + links[i].onmouseout = highlight(false); + } +}; diff --git a/samples/client/petstore/haskell-http-client/docs/src/style.css b/samples/client/petstore/haskell-http-client/docs/src/style.css new file mode 100644 index 00000000000..e83dc5ec702 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/docs/src/style.css @@ -0,0 +1,55 @@ +body { + background-color: #fdf6e3; +} + +.hs-identifier { + color: #073642; +} + +.hs-identifier.hs-var { +} + +.hs-identifier.hs-type { + color: #5f5faf; +} + +.hs-keyword { + color: #af005f; +} + +.hs-string, .hs-char { + color: #cb4b16; +} + +.hs-number { + color: #268bd2; +} + +.hs-operator { + color: #d33682; +} + +.hs-glyph, .hs-special { + color: #dc322f; +} + +.hs-comment { + color: #8a8a8a; +} + +.hs-pragma { + color: #2aa198; +} + +.hs-cpp { + color: #859900; +} + +a:link, a:visited { + text-decoration: none; + border-bottom: 1px solid #eee8d5; +} + +a:hover, a.hover-highlight { + background-color: #eee8d5; +} diff --git a/samples/client/petstore/haskell-http-client/docs/synopsis.png b/samples/client/petstore/haskell-http-client/docs/synopsis.png new file mode 100644 index 00000000000..85fb86ec849 Binary files /dev/null and b/samples/client/petstore/haskell-http-client/docs/synopsis.png differ diff --git a/samples/client/petstore/haskell-http-client/example-app/Main.hs b/samples/client/petstore/haskell-http-client/example-app/Main.hs new file mode 100644 index 00000000000..ff9900c31ce --- /dev/null +++ b/samples/client/petstore/haskell-http-client/example-app/Main.hs @@ -0,0 +1,233 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# OPTIONS_GHC -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-orphans #-} + +import qualified Data.Aeson as A +import qualified Data.ByteString.Lazy.Char8 as BCL +import qualified Data.Text as T +import qualified Data.Time as TI +import qualified Lens.Micro as L +import qualified Network.HTTP.Client as NH + +import qualified SwaggerPetstore as S + +import Data.Monoid ((<>)) + +-- * MAIN + +main :: IO () +main = do + + mgr <- NH.newManager NH.defaultManagerSettings + + -- print log messages to sdtout + let config = + S.withStdoutLogging + S.newConfig { S.configHost = "http://0.0.0.0/v2" + -- , S.configLoggingFilter = S.debugLevelFilter + } + + putStrLn "******** CONFIG ********" + putStrLn (show config) + + putStrLn "******** Pet operations ********" + runPet mgr config + + putStrLn "******** Store operations ********" + runStore mgr config + + putStrLn "******** User operations ********" + runUser mgr config + + putStrLn "******** END ********" + + return () + + +-- * PET + +runPet :: NH.Manager -> S.SwaggerPetstoreConfig -> IO () +runPet mgr config = do + + -- create the request for addPet, encoded with content-type application/json + let addPetRequest = S.addPet S.MimeJSON (S.mkPet "name" ["url1", "url2"]) + + -- send the rquest with accept header application/json + -- dispatchLbs simply returns the raw Network.HTTP.Client.Response ByteString + addPetResponse <- S.dispatchLbs mgr config addPetRequest S.MimeJSON + + -- the Consumes & Produces typeclasses control which 'content-type' + -- and 'accept' encodings are allowed for each operation + -- -- No instance for (S.Produces S.AddPet S.MimePlainText) + -- addPetResponse <- S.dispatchLbs mgr config addPetRequest S.MimePlainText + + -- inspect the AddPet type to see typeclasses indicating wihch + -- content-type and accept types (mimeTypes) are valid + + -- :i S.AddPet + -- data S.AddPet -- Defined in ‘SwaggerPetstore.API’ + -- instance S.Produces S.AddPet S.MimeXML + -- -- Defined in ‘SwaggerPetstore.API’ + -- instance S.Produces S.AddPet S.MimeJSON + -- -- Defined in ‘SwaggerPetstore.API’ + -- instance S.Consumes S.AddPet S.MimeXML + -- -- Defined in ‘SwaggerPetstore.API’ + -- instance S.Consumes S.AddPet S.MimeJSON + -- -- Defined in ‘SwaggerPetstore.API’ + -- instance S.HasBodyParam S.AddPet S.Pet + -- -- Defined in ‘SwaggerPetstore.API’ + + + -- since this swagger definition has no response schema defined for + -- the 'addPet' response, we decode the response bytestring manually + case A.eitherDecode (NH.responseBody addPetResponse) of + Right pet@S.Pet { S.petId = Just pid } -> do + + -- create the request for getPetById + let getPetByIdRequest = S.getPetById pid + + -- dispatchMime returns MimeResult, which includes the + -- expected decoded model object 'Pet', or a parse failure + getPetByIdRequestResult <- S.dispatchMime mgr config getPetByIdRequest S.MimeJSON + case S.mimeResult getPetByIdRequestResult of + Left (S.MimeError _ _) -> return () -- parse error, already displayed in the log + Right r -> putStrLn $ "getPetById: found pet: " <> show r -- display 'Pet' model object, r + + -- findPetsByStatus + let findPetsByStatusRequest = S.findPetsByStatus ["available","pending","sold"] + findPetsByStatusResult <- S.dispatchMime mgr config findPetsByStatusRequest S.MimeJSON + mapM_ (\r -> putStrLn $ "findPetsByStatus: found " <> (show . length) r <> " pets") findPetsByStatusResult + + -- findPetsByTags + let findPetsByTagsRequest = S.findPetsByTags ["name","tag1"] + findPetsByTagsResult <- S.dispatchMime mgr config findPetsByTagsRequest S.MimeJSON + mapM_ (\r -> putStrLn $ "findPetsByTags: found " <> (show . length) r <> " pets") findPetsByTagsResult + + -- updatePet + let updatePetRequest = S.updatePet S.MimeJSON $ pet + { S.petStatus = Just "available" + , S.petCategory = Just (S.Category (Just 3) (Just "catname")) + } + _ <- S.dispatchLbs mgr config updatePetRequest S.MimeXML + + -- requred parameters are included as function arguments, optional parameters are included with applyOptionalParam + -- inspect the UpdatePetWithForm type to see typeclasses indicating optional paramteters (:i S.UpdatePetWithForm) + -- instance S.HasOptionalParam S.UpdatePetWithForm S.Name + -- -- Defined in ‘SwaggerPetstore.API’ + -- instance S.HasOptionalParam S.UpdatePetWithForm S.Status + -- -- Defined in ‘SwaggerPetstore.API’ + let updatePetWithFormRequest = S.updatePetWithForm S.MimeFormUrlEncoded pid + `S.applyOptionalParam` S.Name "petName" + `S.applyOptionalParam` S.Status "pending" + _ <- S.dispatchLbs mgr config updatePetWithFormRequest S.MimeJSON + + -- multipart/form-data file uploads are just a different content-type + let uploadFileRequest = S.uploadFile S.MimeMultipartFormData pid + `S.applyOptionalParam` S.File "package.yaml" -- the file contents of the path are read when dispatched + `S.applyOptionalParam` S.AdditionalMetadata "a package.yaml file" + uploadFileRequestResult <- S.dispatchMime mgr config uploadFileRequest S.MimeJSON + mapM_ (\r -> putStrLn $ "uploadFile: " <> show r) uploadFileRequestResult + + -- deletePet + let deletePetRequest = S.deletePet pid + `S.applyOptionalParam` S.ApiUnderscorekey "api key" + _ <- S.dispatchLbs mgr config deletePetRequest S.MimeJSON + + return () + + Left e -> putStrLn e + _ -> putStrLn "no Pet id returned" + + return () + + + +-- * STORE + +-- declare that 'placeOrder' can recieve a JSON content-type request +instance S.Consumes S.PlaceOrder S.MimeJSON + +runStore :: NH.Manager -> S.SwaggerPetstoreConfig -> IO () +runStore mgr config = do + + -- we can set arbitrary headers with setHeader + let getInventoryRequest = S.getInventory + `S.setHeader` [("api_key","special-key")] + getInventoryRequestRequestResult <- S.dispatchMime mgr config getInventoryRequest S.MimeJSON + mapM_ (\r -> putStrLn $ "getInventoryRequest: found " <> (show . length) r <> " results") getInventoryRequestRequestResult + + -- placeOrder + now <- TI.getCurrentTime + let placeOrderRequest = S.placeOrder S.MimeJSON (S.mkOrder { S.orderId = Just 21, S.orderQuantity = Just 210, S.orderShipDate = Just now}) + placeOrderResult <- S.dispatchMime mgr config placeOrderRequest S.MimeJSON + mapM_ (\r -> putStrLn $ "placeOrderResult: " <> show r) placeOrderResult + + let orderId = maybe 10 id $ either (const Nothing) (S.orderId) (S.mimeResult placeOrderResult) + + -- getOrderByid + let getOrderByIdRequest = S.getOrderById orderId + getOrderByIdRequestResult <- S.dispatchMime mgr config getOrderByIdRequest S.MimeJSON + mapM_ (\r -> putStrLn $ "getOrderById: found order: " <> show r) getOrderByIdRequestResult + + -- deleteOrder + let deleteOrderRequest = S.deleteOrder "21" + _ <- S.dispatchLbs mgr config deleteOrderRequest S.MimeJSON + + return () + + + +-- * USER + +-- this swagger definition doesn't declare what content-type the +-- server actually expects for these operations, so delcare it here +instance S.Consumes S.CreateUser S.MimeJSON +instance S.Consumes S.UpdateUser S.MimeJSON +instance S.Consumes S.CreateUsersWithArrayInput S.MimeJSON +instance S.Consumes S.CreateUsersWithListInput S.MimeJSON + +-- similarly we declare these operations are allowed to omit the +-- accept header despite what the swagger definition says +instance S.Produces S.CreateUsersWithArrayInput S.MimeNoContent +instance S.Produces S.CreateUsersWithListInput S.MimeNoContent + +runUser :: NH.Manager -> S.SwaggerPetstoreConfig -> IO () +runUser mgr config = do + + let username = "hsusername" + -- createUser + let user = S.mkUser { S.userId = Just 21, S.userUsername = Just username } + let createUserRequest = S.createUser S.MimeJSON user + _ <- S.dispatchLbs mgr config createUserRequest S.MimeJSON + + -- can use traversals or lenses (model record names are appended with T or L) to view or modify records + let users = take 8 $ drop 1 $ iterate (L.over S.userUsernameT (<> "*") . L.over S.userIdT (+1)) user + let createUsersWithArrayInputRequest = S.createUsersWithArrayInput S.MimeJSON users + _ <- S.dispatchLbs mgr config createUsersWithArrayInputRequest S.MimeNoContent + + -- createUsersWithArrayInput + let createUsersWithListInputRequest = S.createUsersWithListInput S.MimeJSON users + _ <- S.dispatchLbs mgr config createUsersWithListInputRequest S.MimeNoContent + + -- getUserByName + let getUserByNameRequest = S.getUserByName username + getUserByNameResult <- S.dispatchMime mgr config getUserByNameRequest S.MimeJSON + mapM_ (\r -> putStrLn $ "getUserByName: found user: " <> show r) getUserByNameResult + + -- loginUser + let loginUserRequest = S.loginUser username "password1" + loginUserResult <- S.dispatchLbs mgr config loginUserRequest S.MimeJSON + BCL.putStrLn $ "loginUser: " <> (NH.responseBody loginUserResult) + + -- updateUser + let updateUserRequest = S.updateUser S.MimeJSON username (user { S.userEmail = Just "xyz@example.com" }) + _ <- S.dispatchLbs mgr config updateUserRequest S.MimeJSON + + -- logoutUser + _ <- S.dispatchLbs mgr config S.logoutUser S.MimeJSON + + -- deleteUser + let deleteUserRequest = S.deleteUser username + _ <- S.dispatchLbs mgr config deleteUserRequest S.MimeJSON + + return () diff --git a/samples/client/petstore/haskell-http-client/example-app/README.md b/samples/client/petstore/haskell-http-client/example-app/README.md new file mode 100644 index 00000000000..a3383a9c6c2 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/example-app/README.md @@ -0,0 +1,45 @@ +# swagger-petstore-app + +This contains an example application which uses the auto-generated +swagger-petstore API Client: `haskell-http-client` + +This module is not auto-generated. + +The application requires a swagger petstore server running at +`http://0.0.0.0/v2`, or the value of the `HOST` environment variable. + +To compile this application, the api client library bindings generated for swagger-petstore are expected to live in the parent folder. + +### Petstore Server + +The petstore server can be obtained at: + +https://github.com/wing328/swagger-samples/tree/docker/java/java-jersey-jaxrs + +Follow the instructions in the readme to install and run the petstore +server (the docker branch is used here, but docker is not required) + +### Usage + +1. Install the [Haskell `stack` tool](http://docs.haskellstack.org/en/stable/README). +2. Start the petstore server (described above) +3. To run the application: +``` +stack --install-ghc exec swagger-petstore-app +``` +4. After stack installs ghc on the first run, `--install-ghc` can be omitted + +### Optional Environment Variables + +* `HOST` - the root url of the petstore server +* `http_proxy` - the address of the http proxy + +Example: + +``` +HOST=http://0.0.0.0/v2 http_proxy=http://0.0.0.0:8080 stack --install-ghc exec swagger-petstore-app +``` + +### Source Documentation + +The application code lives in `Main.hs`, which is commented with additional implementation notes diff --git a/samples/client/petstore/haskell-http-client/example-app/debugLog.txt b/samples/client/petstore/haskell-http-client/example-app/debugLog.txt new file mode 100644 index 00000000000..45de7fc52a1 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/example-app/debugLog.txt @@ -0,0 +1,95 @@ +******** CONFIG ******** +{ configHost = "http://0.0.0.0/v2", configUserAgent = "swagger-haskell-http-client/1.0.0", ..} +******** Pet operations ******** +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC REQ:POST 0.0.0.0/v2/pet +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/json;charset=utf-8"),("accept","application/json;charset=utf-8")] Body={"photoUrls":["url1","url2"],"name":"name"} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC RES:statusCode=200 (POST 0.0.0.0/v2/pet) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "{\"id\":30,\"name\":\"name\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[]}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC REQ:GET 0.0.0.0/v2/pet/30 +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC RES:statusCode=200 (GET 0.0.0.0/v2/pet/30) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "{\"id\":30,\"name\":\"name\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[]}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +getPetById: found pet: Pet {petId = Just 30, petCategory = Nothing, petName = "name", petPhotoUrls = ["url1","url2"], petTags = Just [], petStatus = Nothing} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC REQ:GET 0.0.0.0/v2/pet/findByStatus?status=available%2Cpending%2Csold +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC RES:statusCode=200 (GET 0.0.0.0/v2/pet/findByStatus?status=available%2Cpending%2Csold) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "[{\"id\":1,\"category\":{\"id\":2,\"name\":\"Cats\"},\"name\":\"Cat 1\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}],\"status\":\"available\"},{\"id\":2,\"category\":{\"id\":2,\"name\":\"Cats\"},\"name\":\"Cat 2\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag2\"},{\"id\":2,\"name\":\"tag3\"}],\"status\":\"available\"},{\"id\":3,\"category\":{\"id\":2,\"name\":\"Cats\"},\"name\":\"Cat 3\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag3\"},{\"id\":2,\"name\":\"tag4\"}],\"status\":\"pending\"},{\"id\":4,\"category\":{\"id\":1,\"name\":\"Dogs\"},\"name\":\"Dog 1\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}],\"status\":\"available\"},{\"id\":5,\"category\":{\"id\":1,\"name\":\"Dogs\"},\"name\":\"Dog 2\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag2\"},{\"id\":2,\"name\":\"tag3\"}],\"status\":\"sold\"},{\"id\":6,\"category\":{\"id\":1,\"name\":\"Dogs\"},\"name\":\"Dog 3\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag3\"},{\"id\":2,\"name\":\"tag4\"}],\"status\":\"pending\"},{\"id\":7,\"category\":{\"id\":4,\"name\":\"Lions\"},\"name\":\"Lion 1\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}],\"status\":\"available\"},{\"id\":8,\"category\":{\"id\":4,\"name\":\"Lions\"},\"name\":\"Lion 2\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag2\"},{\"id\":2,\"name\":\"tag3\"}],\"status\":\"available\"},{\"id\":9,\"category\":{\"id\":4,\"name\":\"Lions\"},\"name\":\"Lion 3\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag3\"},{\"id\":2,\"name\":\"tag4\"}],\"status\":\"available\"},{\"id\":10,\"category\":{\"id\":3,\"name\":\"Rabbits\"},\"name\":\"Rabbit 1\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag3\"},{\"id\":2,\"name\":\"tag4\"}],\"status\":\"available\"},{\"id\":25,\"category\":{\"id\":3,\"name\":\"catname\"},\"name\":\"name\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[],\"status\":\"available\"},{\"id\":26,\"category\":{\"id\":3,\"name\":\"catname\"},\"name\":\"petName\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[],\"status\":\"pending\"},{\"id\":27,\"category\":{\"id\":3,\"name\":\"catname\"},\"name\":\"petName\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[],\"status\":\"pending\"}]", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +findPetsByStatus: found 13 pets +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC REQ:GET 0.0.0.0/v2/pet/findByTags?tags=name%2Ctag1 +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC RES:statusCode=200 (GET 0.0.0.0/v2/pet/findByTags?tags=name%2Ctag1) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "[{\"id\":1,\"category\":{\"id\":2,\"name\":\"Cats\"},\"name\":\"Cat 1\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}],\"status\":\"available\"},{\"id\":4,\"category\":{\"id\":1,\"name\":\"Dogs\"},\"name\":\"Dog 1\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}],\"status\":\"available\"},{\"id\":7,\"category\":{\"id\":4,\"name\":\"Lions\"},\"name\":\"Lion 1\",\"photoUrls\":[\"url1\",\"url2\"],\"tags\":[{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}],\"status\":\"available\"}]", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +findPetsByTags: found 3 pets +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC REQ:PUT 0.0.0.0/v2/pet +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:03UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/json;charset=utf-8"),("accept","application/xml")] Body={"photoUrls":["url1","url2"],"status":"available","category":{"name":"catname","id":3},"name":"name","id":30,"tags":[]} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (PUT 0.0.0.0/v2/pet) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/xml"),("Content-Length","251"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "3catname30nameurl1url2available", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:POST 0.0.0.0/v2/pet/30 +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/x-www-form-urlencoded"),("accept","application/json;charset=utf-8")] Body=status=pending&name=petName +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (POST 0.0.0.0/v2/pet/30) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:POST 0.0.0.0/v2/pet/30/uploadImage +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("Content-Type","multipart/form-data; boundary=----WebKitFormBoundarytMtEWXPCyyC5CTsF"),("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (POST 0.0.0.0/v2/pet/30/uploadImage) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "{\"code\":200,\"type\":\"unknown\",\"message\":\"additionalMetadata: a package.yaml file\\nFile uploaded to ./package.yaml, 893 bytes\"}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +uploadFile: ApiResponse {apiResponseCode = Just 200, apiResponseType = Just "unknown", apiResponseMessage = Just "additionalMetadata: a package.yaml file\nFile uploaded to ./package.yaml, 893 bytes"} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:DELETE 0.0.0.0/v2/pet/30 +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8"),("api_key","api key")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (DELETE 0.0.0.0/v2/pet/30) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +******** Store operations ******** +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:GET 0.0.0.0/v2/store/inventory +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8"),("api_key","special-key")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (GET 0.0.0.0/v2/store/inventory) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "{\"sold\":1,\"pending\":4,\"available\":8}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +getInventoryRequest: found 3 results +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:POST 0.0.0.0/v2/store/order +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/json;charset=utf-8"),("accept","application/json;charset=utf-8")] Body={"quantity":210,"id":21,"shipDate":"2017-09-02T19:52:04.306Z"} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (POST 0.0.0.0/v2/store/order) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "{\"id\":21,\"petId\":0,\"quantity\":210,\"shipDate\":\"2017-09-02T19:52:04.306+0000\",\"complete\":false}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +placeOrderResult: Order {orderId = Just 21, orderPetId = Just 0, orderQuantity = Just 210, orderShipDate = Just 2017-09-02 19:52:04.306 UTC, orderStatus = Nothing, orderComplete = Just False} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:GET 0.0.0.0/v2/store/order/21 +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (GET 0.0.0.0/v2/store/order/21) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "{\"id\":21,\"petId\":0,\"quantity\":210,\"shipDate\":\"2017-09-02T19:52:04.306+0000\",\"complete\":false}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +getOrderById: found order: Order {orderId = Just 21, orderPetId = Just 0, orderQuantity = Just 210, orderShipDate = Just 2017-09-02 19:52:04.306 UTC, orderStatus = Nothing, orderComplete = Just False} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:DELETE 0.0.0.0/v2/store/order/21 +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (DELETE 0.0.0.0/v2/store/order/21) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +******** User operations ******** +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:POST 0.0.0.0/v2/user +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/json;charset=utf-8"),("accept","application/json;charset=utf-8")] Body={"username":"hsusername","id":21} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (POST 0.0.0.0/v2/user) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:POST 0.0.0.0/v2/user/createWithArray +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/json;charset=utf-8")] Body=[{"username":"hsusername*","id":22},{"username":"hsusername**","id":23},{"username":"hsusername***","id":24},{"username":"hsusername****","id":25},{"username":"hsusername*****","id":26},{"username":"hsusername******","id":27},{"username":"hsusername*******","id":28},{"username":"hsusername********","id":29}] +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (POST 0.0.0.0/v2/user/createWithArray) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:POST 0.0.0.0/v2/user/createWithList +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/json;charset=utf-8")] Body=[{"username":"hsusername*","id":22},{"username":"hsusername**","id":23},{"username":"hsusername***","id":24},{"username":"hsusername****","id":25},{"username":"hsusername*****","id":26},{"username":"hsusername******","id":27},{"username":"hsusername*******","id":28},{"username":"hsusername********","id":29}] +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (POST 0.0.0.0/v2/user/createWithList) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:GET 0.0.0.0/v2/user/hsusername +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (GET 0.0.0.0/v2/user/hsusername) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "{\"id\":21,\"username\":\"hsusername\",\"userStatus\":0}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +getUserByName: found user: User {userId = Just 21, userUsername = Just "hsusername", userFirstName = Nothing, userLastName = Nothing, userEmail = Nothing, userPassword = Nothing, userPhone = Nothing, userUserStatus = Just 0} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:GET 0.0.0.0/v2/user/login?password=password1&username=hsusername +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (GET 0.0.0.0/v2/user/login?password=password1&username=hsusername) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("X-Expires-After","Sat Sep 02 15:52:04 CDT 2017"),("X-Rate-Limit","5000"),("Content-Type","application/json"),("Transfer-Encoding","chunked"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "logged in user session:1504381924767", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +loginUser: logged in user session:1504381924767 +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:PUT 0.0.0.0/v2/user/hsusername +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("content-type","application/json;charset=utf-8"),("accept","application/json;charset=utf-8")] Body={"email":"xyz@example.com","username":"hsusername","id":21} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (PUT 0.0.0.0/v2/user/hsusername) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:GET 0.0.0.0/v2/user/logout +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (GET 0.0.0.0/v2/user/logout) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC REQ:DELETE 0.0.0.0/v2/user/hsusername +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Headers=[("User-Agent","swagger-haskell-http-client/1.0.0"),("accept","application/json;charset=utf-8")] Body= +[Info#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC RES:statusCode=200 (DELETE 0.0.0.0/v2/user/hsusername) +[Debug#SwaggerPetstore/Client] 2017-09-02T19:52:04UTC Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Access-Control-Allow-Origin","*"),("Access-Control-Allow-Methods","GET, POST, DELETE, PUT"),("Access-Control-Allow-Headers","Content-Type, api_key, Authorization"),("Content-Type","application/json"),("Content-Length","0"),("Server","Jetty(8.1.11.v20130520)")], responseBody = "", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose} +******** END ******** diff --git a/samples/client/petstore/haskell-http-client/example-app/infoLog.txt b/samples/client/petstore/haskell-http-client/example-app/infoLog.txt new file mode 100644 index 00000000000..fa386df6764 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/example-app/infoLog.txt @@ -0,0 +1,55 @@ +******** CONFIG ******** +{ configHost = "http://0.0.0.0/v2", configUserAgent = "swagger-haskell-http-client/1.0.0", ..} +******** Pet operations ******** +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC REQ:POST 0.0.0.0/v2/pet +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC RES:statusCode=200 (POST 0.0.0.0/v2/pet) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC REQ:GET 0.0.0.0/v2/pet/30 +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC RES:statusCode=200 (GET 0.0.0.0/v2/pet/30) +getPetById: found pet: Pet {petId = Just 30, petCategory = Nothing, petName = "name", petPhotoUrls = ["url1","url2"], petTags = Just [], petStatus = Nothing} +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC REQ:GET 0.0.0.0/v2/pet/findByStatus?status=available%2Cpending%2Csold +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC RES:statusCode=200 (GET 0.0.0.0/v2/pet/findByStatus?status=available%2Cpending%2Csold) +findPetsByStatus: found 13 pets +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC REQ:GET 0.0.0.0/v2/pet/findByTags?tags=name%2Ctag1 +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC RES:statusCode=200 (GET 0.0.0.0/v2/pet/findByTags?tags=name%2Ctag1) +findPetsByTags: found 3 pets +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC REQ:PUT 0.0.0.0/v2/pet +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC RES:statusCode=200 (PUT 0.0.0.0/v2/pet) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:49UTC REQ:POST 0.0.0.0/v2/pet/30 +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (POST 0.0.0.0/v2/pet/30) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:POST 0.0.0.0/v2/pet/30/uploadImage +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (POST 0.0.0.0/v2/pet/30/uploadImage) +uploadFile: ApiResponse {apiResponseCode = Just 200, apiResponseType = Just "unknown", apiResponseMessage = Just "additionalMetadata: a package.yaml file\nFile uploaded to ./package.yaml, 893 bytes"} +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:DELETE 0.0.0.0/v2/pet/30 +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (DELETE 0.0.0.0/v2/pet/30) +******** Store operations ******** +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:GET 0.0.0.0/v2/store/inventory +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (GET 0.0.0.0/v2/store/inventory) +getInventoryRequest: found 3 results +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:POST 0.0.0.0/v2/store/order +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (POST 0.0.0.0/v2/store/order) +placeOrderResult: Order {orderId = Just 21, orderPetId = Just 0, orderQuantity = Just 210, orderShipDate = Just 2017-09-02 19:51:50.222 UTC, orderStatus = Nothing, orderComplete = Just False} +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:GET 0.0.0.0/v2/store/order/21 +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (GET 0.0.0.0/v2/store/order/21) +getOrderById: found order: Order {orderId = Just 21, orderPetId = Just 0, orderQuantity = Just 210, orderShipDate = Just 2017-09-02 19:51:50.222 UTC, orderStatus = Nothing, orderComplete = Just False} +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:DELETE 0.0.0.0/v2/store/order/21 +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (DELETE 0.0.0.0/v2/store/order/21) +******** User operations ******** +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:POST 0.0.0.0/v2/user +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (POST 0.0.0.0/v2/user) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:POST 0.0.0.0/v2/user/createWithArray +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (POST 0.0.0.0/v2/user/createWithArray) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:POST 0.0.0.0/v2/user/createWithList +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (POST 0.0.0.0/v2/user/createWithList) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:GET 0.0.0.0/v2/user/hsusername +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (GET 0.0.0.0/v2/user/hsusername) +getUserByName: found user: User {userId = Just 21, userUsername = Just "hsusername", userFirstName = Nothing, userLastName = Nothing, userEmail = Nothing, userPassword = Nothing, userPhone = Nothing, userUserStatus = Just 0} +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:GET 0.0.0.0/v2/user/login?password=password1&username=hsusername +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (GET 0.0.0.0/v2/user/login?password=password1&username=hsusername) +loginUser: logged in user session:1504381910612 +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:PUT 0.0.0.0/v2/user/hsusername +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (PUT 0.0.0.0/v2/user/hsusername) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:GET 0.0.0.0/v2/user/logout +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (GET 0.0.0.0/v2/user/logout) +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC REQ:DELETE 0.0.0.0/v2/user/hsusername +[Info#SwaggerPetstore/Client] 2017-09-02T19:51:50UTC RES:statusCode=200 (DELETE 0.0.0.0/v2/user/hsusername) +******** END ******** diff --git a/samples/client/petstore/haskell-http-client/example-app/package.yaml b/samples/client/petstore/haskell-http-client/example-app/package.yaml new file mode 100644 index 00000000000..072f0a2d323 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/example-app/package.yaml @@ -0,0 +1,37 @@ +name: swagger-petstore-app +version: '0.1.0.0' +synopsis: Auto-generated swagger-petstore API Client +description: ! ' + Sample app for calling the swagger-petstore API based on http-client. +' +category: Web +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +homepage: https://github.com/swagger-api/swagger-codegen#readme +extra-source-files: +- README.md +ghc-options: -Wall +dependencies: +- base >=4.7 && <5.0 +- transformers >=0.4.0.0 +- mtl >=2.2.1 +- unordered-containers +- containers >=0.5.0.0 && <0.6 +- aeson >=1.0 && <2.0 +- bytestring >=0.10.0 && <0.11 +- http-types >=0.8 && <0.10 +- http-client >=0.5 && <0.6 +- http-client-tls +- http-api-data >= 0.3.4 && <0.4 +- http-media >= 0.4 && < 0.8 +- text >=0.11 && <1.3 +- time >=1.5 && <1.9 +- vector >=0.10.9 && <0.13 +- case-insensitive +- swagger-petstore +- microlens +executables: + swagger-petstore-app: + main: Main.hs diff --git a/samples/client/petstore/haskell-http-client/example-app/stack.yaml b/samples/client/petstore/haskell-http-client/example-app/stack.yaml new file mode 100644 index 00000000000..c8e4763e0bd --- /dev/null +++ b/samples/client/petstore/haskell-http-client/example-app/stack.yaml @@ -0,0 +1,5 @@ +resolver: lts-9.0 +packages: + - location: '.' + - location: '..' + extra-dep: true diff --git a/samples/client/petstore/haskell-http-client/example-app/swagger-petstore-app.cabal b/samples/client/petstore/haskell-http-client/example-app/swagger-petstore-app.cabal new file mode 100644 index 00000000000..c62609490b1 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/example-app/swagger-petstore-app.cabal @@ -0,0 +1,43 @@ +-- This file has been generated from package.yaml by hpack version 0.17.1. +-- +-- see: https://github.com/sol/hpack + +name: swagger-petstore-app +version: 0.1.0.0 +synopsis: Auto-generated swagger-petstore API Client +description: Sample app for calling the swagger-petstore API based on http-client. +category: Web +homepage: https://github.com/swagger-api/swagger-codegen#readme +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +build-type: Simple +cabal-version: >= 1.10 + +extra-source-files: + README.md + +executable swagger-petstore-app + main-is: Main.hs + ghc-options: -Wall + build-depends: + base >=4.7 && <5.0 + , transformers >=0.4.0.0 + , mtl >=2.2.1 + , unordered-containers + , containers >=0.5.0.0 && <0.6 + , aeson >=1.0 && <2.0 + , bytestring >=0.10.0 && <0.11 + , http-types >=0.8 && <0.10 + , http-client >=0.5 && <0.6 + , http-client-tls + , http-api-data >= 0.3.4 && <0.4 + , http-media >= 0.4 && < 0.8 + , text >=0.11 && <1.3 + , time >=1.5 && <1.9 + , vector >=0.10.9 && <0.13 + , case-insensitive + , swagger-petstore + , microlens + default-language: Haskell2010 diff --git a/samples/client/petstore/haskell-http-client/git_push.sh b/samples/client/petstore/haskell-http-client/git_push.sh new file mode 100644 index 00000000000..ed374619b13 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git crediential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore.hs b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore.hs new file mode 100644 index 00000000000..edfeec4b1de --- /dev/null +++ b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore.hs @@ -0,0 +1,17 @@ +{-| +Module : SwaggerPetstore +-} + +module SwaggerPetstore + ( module SwaggerPetstore.Client + , module SwaggerPetstore.API + , module SwaggerPetstore.Model + , module SwaggerPetstore.MimeTypes + , module SwaggerPetstore.Lens + ) where + +import SwaggerPetstore.API +import SwaggerPetstore.Client +import SwaggerPetstore.Model +import SwaggerPetstore.MimeTypes +import SwaggerPetstore.Lens diff --git a/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/API.hs b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/API.hs new file mode 100644 index 00000000000..0d2f2ee8b20 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/API.hs @@ -0,0 +1,830 @@ +{-| +Module : SwaggerPetstore.API +-} + +{-# LANGUAGE RecordWildCards #-} + +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE InstanceSigs #-} +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module SwaggerPetstore.API where + + +import SwaggerPetstore.Model as M +import SwaggerPetstore.MimeTypes + +import qualified Data.Aeson as A +import Data.Aeson (Value) + +import qualified Data.Time as TI +import Data.Time (UTCTime) + +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import Data.ByteString.Lazy (ByteString) +import qualified Data.ByteString.Builder as BB +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy.Char8 as BCL + +import qualified Network.HTTP.Client.MultipartFormData as NH +import qualified Network.HTTP.Media as ME +import qualified Network.HTTP.Types as NH + +import qualified Web.HttpApiData as WH +import qualified Web.FormUrlEncoded as WH + +import qualified Data.CaseInsensitive as CI +import qualified Data.Data as P (Typeable) +import qualified Data.Foldable as P +import qualified Data.Map as Map +import qualified Data.Maybe as P +import qualified Data.Proxy as P (Proxy(..)) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Text.Lazy as TL +import qualified Data.Text.Lazy.Encoding as TL +import qualified GHC.Base as P (Alternative) +import qualified Control.Arrow as P (left) + +import Data.Monoid ((<>)) +import Data.Function ((&)) +import Data.Set (Set) +import Data.Text (Text) +import GHC.Base ((<|>)) + +import Prelude ((==),(/=),($), (.),(<$>),(<*>),(>>=),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor) +import qualified Prelude as P + +-- * Operations + + +-- ** Pet + +-- *** addPet + +-- | @POST \/pet@ +-- +-- Add a new pet to the store +-- +-- +-- +-- AuthMethod: petstore_auth +-- +-- Note: Has 'Produces' instances, but no response schema +-- +addPet + :: (Consumes AddPet contentType, MimeRender contentType Pet) + => contentType -- ^ request content-type ('MimeType') + -> Pet -- ^ "body" - Pet object that needs to be added to the store + -> SwaggerPetstoreRequest AddPet contentType res +addPet _ body = + _mkRequest "POST" ["/pet"] + `setBodyParam` body + +data AddPet + +-- | /Body Param/ "body" - Pet object that needs to be added to the store +instance HasBodyParam AddPet Pet + +-- | @application/json@ +instance Consumes AddPet MimeJSON +-- | @application/xml@ +instance Consumes AddPet MimeXML + +-- | @application/xml@ +instance Produces AddPet MimeXML +-- | @application/json@ +instance Produces AddPet MimeJSON + + +-- *** deletePet + +-- | @DELETE \/pet\/{petId}@ +-- +-- Deletes a pet +-- +-- +-- +-- AuthMethod: petstore_auth +-- +-- Note: Has 'Produces' instances, but no response schema +-- +deletePet + :: Integer -- ^ "petId" - Pet id to delete + -> SwaggerPetstoreRequest DeletePet MimeNoContent res +deletePet petId = + _mkRequest "DELETE" ["/pet/",toPath petId] + + +data DeletePet +instance HasOptionalParam DeletePet ApiUnderscorekey where + applyOptionalParam req (ApiUnderscorekey xs) = + req `setHeader` toHeader ("api_key", xs) +-- | @application/xml@ +instance Produces DeletePet MimeXML +-- | @application/json@ +instance Produces DeletePet MimeJSON + + +-- *** findPetsByStatus + +-- | @GET \/pet\/findByStatus@ +-- +-- Finds Pets by status +-- +-- Multiple status values can be provided with comma separated strings +-- +-- AuthMethod: petstore_auth +-- +findPetsByStatus + :: [Text] -- ^ "status" - Status values that need to be considered for filter + -> SwaggerPetstoreRequest FindPetsByStatus MimeNoContent [Pet] +findPetsByStatus status = + _mkRequest "GET" ["/pet/findByStatus"] + `_setQuery` toQueryColl CommaSeparated ("status", Just status) + +data FindPetsByStatus +-- | @application/xml@ +instance Produces FindPetsByStatus MimeXML +-- | @application/json@ +instance Produces FindPetsByStatus MimeJSON + + +-- *** findPetsByTags + +-- | @GET \/pet\/findByTags@ +-- +-- Finds Pets by tags +-- +-- Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. +-- +-- AuthMethod: petstore_auth +-- +findPetsByTags + :: [Text] -- ^ "tags" - Tags to filter by + -> SwaggerPetstoreRequest FindPetsByTags MimeNoContent [Pet] +findPetsByTags tags = + _mkRequest "GET" ["/pet/findByTags"] + `_setQuery` toQueryColl CommaSeparated ("tags", Just tags) + +{-# DEPRECATED findPetsByTags "" #-} + +data FindPetsByTags +-- | @application/xml@ +instance Produces FindPetsByTags MimeXML +-- | @application/json@ +instance Produces FindPetsByTags MimeJSON + + +-- *** getPetById + +-- | @GET \/pet\/{petId}@ +-- +-- Find pet by ID +-- +-- Returns a single pet +-- +-- AuthMethod: api_key +-- +getPetById + :: Integer -- ^ "petId" - ID of pet to return + -> SwaggerPetstoreRequest GetPetById MimeNoContent Pet +getPetById petId = + _mkRequest "GET" ["/pet/",toPath petId] + + +data GetPetById +-- | @application/xml@ +instance Produces GetPetById MimeXML +-- | @application/json@ +instance Produces GetPetById MimeJSON + + +-- *** updatePet + +-- | @PUT \/pet@ +-- +-- Update an existing pet +-- +-- +-- +-- AuthMethod: petstore_auth +-- +-- Note: Has 'Produces' instances, but no response schema +-- +updatePet + :: (Consumes UpdatePet contentType, MimeRender contentType Pet) + => contentType -- ^ request content-type ('MimeType') + -> Pet -- ^ "body" - Pet object that needs to be added to the store + -> SwaggerPetstoreRequest UpdatePet contentType res +updatePet _ body = + _mkRequest "PUT" ["/pet"] + `setBodyParam` body + +data UpdatePet + +-- | /Body Param/ "body" - Pet object that needs to be added to the store +instance HasBodyParam UpdatePet Pet + +-- | @application/json@ +instance Consumes UpdatePet MimeJSON +-- | @application/xml@ +instance Consumes UpdatePet MimeXML + +-- | @application/xml@ +instance Produces UpdatePet MimeXML +-- | @application/json@ +instance Produces UpdatePet MimeJSON + + +-- *** updatePetWithForm + +-- | @POST \/pet\/{petId}@ +-- +-- Updates a pet in the store with form data +-- +-- +-- +-- AuthMethod: petstore_auth +-- +-- Note: Has 'Produces' instances, but no response schema +-- +updatePetWithForm + :: (Consumes UpdatePetWithForm contentType) + => contentType -- ^ request content-type ('MimeType') + -> Integer -- ^ "petId" - ID of pet that needs to be updated + -> SwaggerPetstoreRequest UpdatePetWithForm contentType res +updatePetWithForm _ petId = + _mkRequest "POST" ["/pet/",toPath petId] + + +data UpdatePetWithForm + +-- | /Optional Param/ "name" - Updated name of the pet +instance HasOptionalParam UpdatePetWithForm Name where + applyOptionalParam req (Name xs) = + req `_addForm` toForm ("name", xs) + +-- | /Optional Param/ "status" - Updated status of the pet +instance HasOptionalParam UpdatePetWithForm Status where + applyOptionalParam req (Status xs) = + req `_addForm` toForm ("status", xs) + +-- | @application/x-www-form-urlencoded@ +instance Consumes UpdatePetWithForm MimeFormUrlEncoded + +-- | @application/xml@ +instance Produces UpdatePetWithForm MimeXML +-- | @application/json@ +instance Produces UpdatePetWithForm MimeJSON + + +-- *** uploadFile + +-- | @POST \/pet\/{petId}\/uploadImage@ +-- +-- uploads an image +-- +-- +-- +-- AuthMethod: petstore_auth +-- +uploadFile + :: (Consumes UploadFile contentType) + => contentType -- ^ request content-type ('MimeType') + -> Integer -- ^ "petId" - ID of pet to update + -> SwaggerPetstoreRequest UploadFile contentType ApiResponse +uploadFile _ petId = + _mkRequest "POST" ["/pet/",toPath petId,"/uploadImage"] + + +data UploadFile + +-- | /Optional Param/ "additionalMetadata" - Additional data to pass to server +instance HasOptionalParam UploadFile AdditionalMetadata where + applyOptionalParam req (AdditionalMetadata xs) = + req `_addMultiFormPart` NH.partLBS "additionalMetadata" (mimeRender' MimeMultipartFormData xs) + +-- | /Optional Param/ "file" - file to upload +instance HasOptionalParam UploadFile File where + applyOptionalParam req (File xs) = + req `_addMultiFormPart` NH.partFileSource "file" xs + +-- | @multipart/form-data@ +instance Consumes UploadFile MimeMultipartFormData + +-- | @application/json@ +instance Produces UploadFile MimeJSON + + +-- ** Store + +-- *** deleteOrder + +-- | @DELETE \/store\/order\/{orderId}@ +-- +-- Delete purchase order by ID +-- +-- For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors +-- +-- Note: Has 'Produces' instances, but no response schema +-- +deleteOrder + :: Text -- ^ "orderId" - ID of the order that needs to be deleted + -> SwaggerPetstoreRequest DeleteOrder MimeNoContent res +deleteOrder orderId = + _mkRequest "DELETE" ["/store/order/",toPath orderId] + + +data DeleteOrder +-- | @application/xml@ +instance Produces DeleteOrder MimeXML +-- | @application/json@ +instance Produces DeleteOrder MimeJSON + + +-- *** getInventory + +-- | @GET \/store\/inventory@ +-- +-- Returns pet inventories by status +-- +-- Returns a map of status codes to quantities +-- +-- AuthMethod: api_key +-- +getInventory + :: SwaggerPetstoreRequest GetInventory MimeNoContent (Map.Map String Int) +getInventory = + _mkRequest "GET" ["/store/inventory"] + +data GetInventory +-- | @application/json@ +instance Produces GetInventory MimeJSON + + +-- *** getOrderById + +-- | @GET \/store\/order\/{orderId}@ +-- +-- Find purchase order by ID +-- +-- For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions +-- +getOrderById + :: Integer -- ^ "orderId" - ID of pet that needs to be fetched + -> SwaggerPetstoreRequest GetOrderById MimeNoContent Order +getOrderById orderId = + _mkRequest "GET" ["/store/order/",toPath orderId] + + +data GetOrderById +-- | @application/xml@ +instance Produces GetOrderById MimeXML +-- | @application/json@ +instance Produces GetOrderById MimeJSON + + +-- *** placeOrder + +-- | @POST \/store\/order@ +-- +-- Place an order for a pet +-- +-- +-- +placeOrder + :: (Consumes PlaceOrder contentType, MimeRender contentType Order) + => contentType -- ^ request content-type ('MimeType') + -> Order -- ^ "body" - order placed for purchasing the pet + -> SwaggerPetstoreRequest PlaceOrder contentType Order +placeOrder _ body = + _mkRequest "POST" ["/store/order"] + `setBodyParam` body + +data PlaceOrder + +-- | /Body Param/ "body" - order placed for purchasing the pet +instance HasBodyParam PlaceOrder Order +-- | @application/xml@ +instance Produces PlaceOrder MimeXML +-- | @application/json@ +instance Produces PlaceOrder MimeJSON + + +-- ** User + +-- *** createUser + +-- | @POST \/user@ +-- +-- Create user +-- +-- This can only be done by the logged in user. +-- +-- Note: Has 'Produces' instances, but no response schema +-- +createUser + :: (Consumes CreateUser contentType, MimeRender contentType User) + => contentType -- ^ request content-type ('MimeType') + -> User -- ^ "body" - Created user object + -> SwaggerPetstoreRequest CreateUser contentType res +createUser _ body = + _mkRequest "POST" ["/user"] + `setBodyParam` body + +data CreateUser + +-- | /Body Param/ "body" - Created user object +instance HasBodyParam CreateUser User +-- | @application/xml@ +instance Produces CreateUser MimeXML +-- | @application/json@ +instance Produces CreateUser MimeJSON + + +-- *** createUsersWithArrayInput + +-- | @POST \/user\/createWithArray@ +-- +-- Creates list of users with given input array +-- +-- +-- +-- Note: Has 'Produces' instances, but no response schema +-- +createUsersWithArrayInput + :: (Consumes CreateUsersWithArrayInput contentType, MimeRender contentType [User]) + => contentType -- ^ request content-type ('MimeType') + -> [User] -- ^ "body" - List of user object + -> SwaggerPetstoreRequest CreateUsersWithArrayInput contentType res +createUsersWithArrayInput _ body = + _mkRequest "POST" ["/user/createWithArray"] + `setBodyParam` body + +data CreateUsersWithArrayInput + +-- | /Body Param/ "body" - List of user object +instance HasBodyParam CreateUsersWithArrayInput [User] +-- | @application/xml@ +instance Produces CreateUsersWithArrayInput MimeXML +-- | @application/json@ +instance Produces CreateUsersWithArrayInput MimeJSON + + +-- *** createUsersWithListInput + +-- | @POST \/user\/createWithList@ +-- +-- Creates list of users with given input array +-- +-- +-- +-- Note: Has 'Produces' instances, but no response schema +-- +createUsersWithListInput + :: (Consumes CreateUsersWithListInput contentType, MimeRender contentType [User]) + => contentType -- ^ request content-type ('MimeType') + -> [User] -- ^ "body" - List of user object + -> SwaggerPetstoreRequest CreateUsersWithListInput contentType res +createUsersWithListInput _ body = + _mkRequest "POST" ["/user/createWithList"] + `setBodyParam` body + +data CreateUsersWithListInput + +-- | /Body Param/ "body" - List of user object +instance HasBodyParam CreateUsersWithListInput [User] +-- | @application/xml@ +instance Produces CreateUsersWithListInput MimeXML +-- | @application/json@ +instance Produces CreateUsersWithListInput MimeJSON + + +-- *** deleteUser + +-- | @DELETE \/user\/{username}@ +-- +-- Delete user +-- +-- This can only be done by the logged in user. +-- +-- Note: Has 'Produces' instances, but no response schema +-- +deleteUser + :: Text -- ^ "username" - The name that needs to be deleted + -> SwaggerPetstoreRequest DeleteUser MimeNoContent res +deleteUser username = + _mkRequest "DELETE" ["/user/",toPath username] + + +data DeleteUser +-- | @application/xml@ +instance Produces DeleteUser MimeXML +-- | @application/json@ +instance Produces DeleteUser MimeJSON + + +-- *** getUserByName + +-- | @GET \/user\/{username}@ +-- +-- Get user by user name +-- +-- +-- +getUserByName + :: Text -- ^ "username" - The name that needs to be fetched. Use user1 for testing. + -> SwaggerPetstoreRequest GetUserByName MimeNoContent User +getUserByName username = + _mkRequest "GET" ["/user/",toPath username] + + +data GetUserByName +-- | @application/xml@ +instance Produces GetUserByName MimeXML +-- | @application/json@ +instance Produces GetUserByName MimeJSON + + +-- *** loginUser + +-- | @GET \/user\/login@ +-- +-- Logs user into the system +-- +-- +-- +loginUser + :: Text -- ^ "username" - The user name for login + -> Text -- ^ "password" - The password for login in clear text + -> SwaggerPetstoreRequest LoginUser MimeNoContent Text +loginUser username password = + _mkRequest "GET" ["/user/login"] + `_setQuery` toQuery ("username", Just username) + `_setQuery` toQuery ("password", Just password) + +data LoginUser +-- | @application/xml@ +instance Produces LoginUser MimeXML +-- | @application/json@ +instance Produces LoginUser MimeJSON + + +-- *** logoutUser + +-- | @GET \/user\/logout@ +-- +-- Logs out current logged in user session +-- +-- +-- +-- Note: Has 'Produces' instances, but no response schema +-- +logoutUser + :: SwaggerPetstoreRequest LogoutUser MimeNoContent res +logoutUser = + _mkRequest "GET" ["/user/logout"] + +data LogoutUser +-- | @application/xml@ +instance Produces LogoutUser MimeXML +-- | @application/json@ +instance Produces LogoutUser MimeJSON + + +-- *** updateUser + +-- | @PUT \/user\/{username}@ +-- +-- Updated user +-- +-- This can only be done by the logged in user. +-- +-- Note: Has 'Produces' instances, but no response schema +-- +updateUser + :: (Consumes UpdateUser contentType, MimeRender contentType User) + => contentType -- ^ request content-type ('MimeType') + -> Text -- ^ "username" - name that need to be deleted + -> User -- ^ "body" - Updated user object + -> SwaggerPetstoreRequest UpdateUser contentType res +updateUser _ username body = + _mkRequest "PUT" ["/user/",toPath username] + + `setBodyParam` body + +data UpdateUser + +-- | /Body Param/ "body" - Updated user object +instance HasBodyParam UpdateUser User +-- | @application/xml@ +instance Produces UpdateUser MimeXML +-- | @application/json@ +instance Produces UpdateUser MimeJSON + + + +-- * HasBodyParam + +-- | Designates the body parameter of a request +class HasBodyParam req param where + setBodyParam :: forall contentType res. (Consumes req contentType, MimeRender contentType param) => SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res + setBodyParam req xs = + req `_setBodyLBS` mimeRender (P.Proxy :: P.Proxy contentType) xs & _setContentTypeHeader + +-- * HasOptionalParam + +-- | Designates the optional parameters of a request +class HasOptionalParam req param where + {-# MINIMAL applyOptionalParam | (-&-) #-} + + -- | Apply an optional parameter to a request + applyOptionalParam :: SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res + applyOptionalParam = (-&-) + {-# INLINE applyOptionalParam #-} + + -- | infix operator \/ alias for 'addOptionalParam' + (-&-) :: SwaggerPetstoreRequest req contentType res -> param -> SwaggerPetstoreRequest req contentType res + (-&-) = applyOptionalParam + {-# INLINE (-&-) #-} + +infixl 2 -&- + +-- * Optional Request Parameter Types + + +newtype ApiUnderscorekey = ApiUnderscorekey { unApiUnderscorekey :: Text } deriving (P.Eq, P.Show) + +newtype Name = Name { unName :: Text } deriving (P.Eq, P.Show) + +newtype Status = Status { unStatus :: Text } deriving (P.Eq, P.Show) + +newtype AdditionalMetadata = AdditionalMetadata { unAdditionalMetadata :: Text } deriving (P.Eq, P.Show) + +newtype File = File { unFile :: FilePath } deriving (P.Eq, P.Show) + + +-- * SwaggerPetstoreRequest + +-- | Represents a request. The "req" type variable is the request type. The "res" type variable is the response type. +data SwaggerPetstoreRequest req contentType res = SwaggerPetstoreRequest + { rMethod :: NH.Method -- ^ Method of SwaggerPetstoreRequest + , urlPath :: [BCL.ByteString] -- ^ Endpoint of SwaggerPetstoreRequest + , params :: Params -- ^ params of SwaggerPetstoreRequest + } + deriving (P.Show) + +-- | Request Params +data Params = Params + { paramsQuery :: NH.Query + , paramsHeaders :: NH.RequestHeaders + , paramsBody :: ParamBody + } + deriving (P.Show) + +-- | Request Body +data ParamBody + = ParamBodyNone + | ParamBodyB B.ByteString + | ParamBodyBL BL.ByteString + | ParamBodyFormUrlEncoded WH.Form + | ParamBodyMultipartFormData [NH.Part] + deriving (P.Show) + +-- ** SwaggerPetstoreRequest Utils + +_mkRequest :: NH.Method -- ^ Method + -> [BCL.ByteString] -- ^ Endpoint + -> SwaggerPetstoreRequest req contentType res -- ^ req: Request Type, res: Response Type +_mkRequest m u = SwaggerPetstoreRequest m u _mkParams + +_mkParams :: Params +_mkParams = Params [] [] ParamBodyNone + +setHeader :: SwaggerPetstoreRequest req contentType res -> [NH.Header] -> SwaggerPetstoreRequest req contentType res +setHeader req header = + let _params = params (req `removeHeader` P.fmap P.fst header) + in req { params = _params { paramsHeaders = header P.++ paramsHeaders _params } } + +removeHeader :: SwaggerPetstoreRequest req contentType res -> [NH.HeaderName] -> SwaggerPetstoreRequest req contentType res +removeHeader req header = + let _params = params req + in req { params = _params { paramsHeaders = [h | h <- paramsHeaders _params, cifst h `P.notElem` P.fmap CI.mk header] } } + where cifst = CI.mk . P.fst + + +_setContentTypeHeader :: forall req contentType res. MimeType contentType => SwaggerPetstoreRequest req contentType res -> SwaggerPetstoreRequest req contentType res +_setContentTypeHeader req = + case mimeType (P.Proxy :: P.Proxy contentType) of + Just m -> req `setHeader` [("content-type", BC.pack $ P.show m)] + Nothing -> req `removeHeader` ["content-type"] + +_setAcceptHeader :: forall req contentType res accept. MimeType accept => SwaggerPetstoreRequest req contentType res -> accept -> SwaggerPetstoreRequest req contentType res +_setAcceptHeader req accept = + case mimeType' accept of + Just m -> req `setHeader` [("accept", BC.pack $ P.show m)] + Nothing -> req `removeHeader` ["accept"] + +_setQuery :: SwaggerPetstoreRequest req contentType res -> [NH.QueryItem] -> SwaggerPetstoreRequest req contentType res +_setQuery req query = + let _params = params req + in req { params = _params { paramsQuery = query P.++ [q | q <- paramsQuery _params, cifst q `P.notElem` P.fmap cifst query] } } + where cifst = CI.mk . P.fst + +_addForm :: SwaggerPetstoreRequest req contentType res -> WH.Form -> SwaggerPetstoreRequest req contentType res +_addForm req newform = + let _params = params req + form = case paramsBody _params of + ParamBodyFormUrlEncoded _form -> _form + _ -> mempty + in req { params = _params { paramsBody = ParamBodyFormUrlEncoded (newform <> form) } } + +_addMultiFormPart :: SwaggerPetstoreRequest req contentType res -> NH.Part -> SwaggerPetstoreRequest req contentType res +_addMultiFormPart req newpart = + let _params = params req + parts = case paramsBody _params of + ParamBodyMultipartFormData _parts -> _parts + _ -> [] + in req { params = _params { paramsBody = ParamBodyMultipartFormData (newpart : parts) } } + +_setBodyBS :: SwaggerPetstoreRequest req contentType res -> B.ByteString -> SwaggerPetstoreRequest req contentType res +_setBodyBS req body = + let _params = params req + in req { params = _params { paramsBody = ParamBodyB body } } + +_setBodyLBS :: SwaggerPetstoreRequest req contentType res -> BL.ByteString -> SwaggerPetstoreRequest req contentType res +_setBodyLBS req body = + let _params = params req + in req { params = _params { paramsBody = ParamBodyBL body } } + + +-- ** Params Utils + +toPath + :: WH.ToHttpApiData a + => a -> BCL.ByteString +toPath = BB.toLazyByteString . WH.toEncodedUrlPiece + +toHeader :: WH.ToHttpApiData a => (NH.HeaderName, a) -> [NH.Header] +toHeader x = [fmap WH.toHeader x] + +toForm :: WH.ToHttpApiData v => (BC.ByteString, v) -> WH.Form +toForm (k,v) = WH.toForm [(BC.unpack k,v)] + +toQuery :: WH.ToHttpApiData a => (BC.ByteString, Maybe a) -> [NH.QueryItem] +toQuery x = [(fmap . fmap) toQueryParam x] + where toQueryParam = T.encodeUtf8 . WH.toQueryParam + +-- *** Swagger `CollectionFormat` Utils + +-- | Determines the format of the array if type array is used. +data CollectionFormat + = CommaSeparated -- ^ CSV format for multiple parameters. + | SpaceSeparated -- ^ Also called "SSV" + | TabSeparated -- ^ Also called "TSV" + | PipeSeparated -- ^ `value1|value2|value2` + | MultiParamArray -- ^ Using multiple GET parameters, e.g. `foo=bar&foo=baz`. This is valid only for parameters in "query" ('NH.Query') or "formData" ('WH.Form') + +toHeaderColl :: WH.ToHttpApiData a => CollectionFormat -> (NH.HeaderName, [a]) -> [NH.Header] +toHeaderColl c xs = _toColl c toHeader xs + +toFormColl :: WH.ToHttpApiData v => CollectionFormat -> (BC.ByteString, [v]) -> WH.Form +toFormColl c xs = WH.toForm $ fmap unpack $ _toColl c toHeader $ pack xs + where + pack (k,v) = (CI.mk k, v) + unpack (k,v) = (BC.unpack (CI.original k), BC.unpack v) + +toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query +toQueryColl c xs = _toCollA c toQuery xs + +_toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)] +_toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs)) + where fencode = fmap (fmap Just) . encode . fmap P.fromJust + {-# INLINE fencode #-} + +_toCollA :: (P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t BC.ByteString)]) -> f (t [a]) -> [(b, t BC.ByteString)] +_toCollA c encode xs = _toCollA' c encode BC.singleton xs + +_toCollA' :: (P.Monoid c, P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t c)]) -> (Char -> c) -> f (t [a]) -> [(b, t c)] +_toCollA' c encode one xs = case c of + CommaSeparated -> go (one ',') + SpaceSeparated -> go (one ' ') + TabSeparated -> go (one '\t') + PipeSeparated -> go (one '|') + MultiParamArray -> expandList + where + go sep = + [P.foldl1 (\(sk, sv) (_, v) -> (sk, (combine sep <$> sv <*> v) <|> sv <|> v)) expandList] + combine sep x y = x <> sep <> y + expandList = (P.concatMap encode . (P.traverse . P.traverse) P.toList) xs + {-# INLINE go #-} + {-# INLINE expandList #-} + {-# INLINE combine #-} + diff --git a/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Client.hs b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Client.hs new file mode 100644 index 00000000000..8d9d6b53f7b --- /dev/null +++ b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Client.hs @@ -0,0 +1,317 @@ +{-| +Module : SwaggerPetstore.Client +-} + +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveTraversable #-} +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module SwaggerPetstore.Client where + +import SwaggerPetstore.Model +import SwaggerPetstore.API +import SwaggerPetstore.MimeTypes + +import qualified Control.Monad.IO.Class as P +import qualified Data.Aeson as A +import qualified Data.Aeson.Types as A +import qualified Data.Proxy as P (Proxy(..)) +import Data.Function ((&)) +import Data.Monoid ((<>)) +import Data.Text (Text) +import GHC.Exts (IsString(..)) +import Web.FormUrlEncoded as WH +import Web.HttpApiData as WH +import Control.Monad.Catch (MonadThrow) + +import qualified Control.Monad.Logger as LG + +import qualified Data.Time as TI +import qualified Data.Map as Map +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Text.Printf as T + +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy.Char8 as BCL +import qualified Data.ByteString.Builder as BB +import qualified Network.HTTP.Client as NH +import qualified Network.HTTP.Client.TLS as NH +import qualified Network.HTTP.Client.MultipartFormData as NH +import qualified Network.HTTP.Types.Method as NH +import qualified Network.HTTP.Types as NH +import qualified Network.HTTP.Types.URI as NH + +import qualified Control.Exception.Safe as E +-- * Config + +-- | +data SwaggerPetstoreConfig = SwaggerPetstoreConfig + { configHost :: BCL.ByteString -- ^ host supplied in the Request + , configUserAgent :: Text -- ^ user-agent supplied in the Request + , configExecLoggingT :: ExecLoggingT -- ^ Run a block using a MonadLogger instance + , configLoggingFilter :: LG.LogSource -> LG.LogLevel -> Bool -- ^ Only log messages passing the given predicate function. + } + +-- | display the config +instance Show SwaggerPetstoreConfig where + show c = + T.printf + "{ configHost = %v, configUserAgent = %v, ..}" + (show (configHost c)) + (show (configUserAgent c)) + +-- | constructs a default SwaggerPetstoreConfig +-- +-- configHost: +-- +-- @http://petstore.swagger.io/v2@ +-- +-- configUserAgent: +-- +-- @"swagger-haskell-http-client/1.0.0"@ +-- +-- configExecLoggingT: 'runNullLoggingT' +-- +-- configLoggingFilter: 'infoLevelFilter' +newConfig :: SwaggerPetstoreConfig +newConfig = + SwaggerPetstoreConfig + { configHost = "http://petstore.swagger.io/v2" + , configUserAgent = "swagger-haskell-http-client/1.0.0" + , configExecLoggingT = runNullLoggingT + , configLoggingFilter = infoLevelFilter + } + +-- | updates the config to use a MonadLogger instance which prints to stdout. +withStdoutLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig +withStdoutLogging p = p { configExecLoggingT = LG.runStdoutLoggingT} + +-- | updates the config to use a MonadLogger instance which prints to stderr. +withStderrLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig +withStderrLogging p = p { configExecLoggingT = LG.runStderrLoggingT} + +-- | updates the config to disable logging +withNoLogging :: SwaggerPetstoreConfig -> SwaggerPetstoreConfig +withNoLogging p = p { configExecLoggingT = runNullLoggingT} + +-- * Dispatch + +-- ** Lbs + +-- | send a request returning the raw http response +dispatchLbs + :: (Produces req accept, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> SwaggerPetstoreConfig -- ^ config + -> SwaggerPetstoreRequest req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchLbs manager config request accept = do + initReq <- _toInitRequest config request accept + dispatchInitUnsafe manager config initReq + +-- ** Mime + +-- | pair of decoded http body and http response +data MimeResult res = + MimeResult { mimeResult :: Either MimeError res -- ^ decoded http body + , mimeResultResponse :: NH.Response BCL.ByteString -- ^ http response + } + deriving (Show, Functor, Foldable, Traversable) + +-- | pair of unrender/parser error and http response +data MimeError = + MimeError { + mimeError :: String -- ^ unrender/parser error + , mimeErrorResponse :: NH.Response BCL.ByteString -- ^ http response + } deriving (Eq, Show) + +-- | send a request returning the 'MimeResult' +dispatchMime + :: (Produces req accept, MimeUnrender accept res, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> SwaggerPetstoreConfig -- ^ config + -> SwaggerPetstoreRequest req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (MimeResult res) -- ^ response +dispatchMime manager config request accept = do + httpResponse <- dispatchLbs manager config request accept + parsedResult <- + runExceptionLoggingT "Client" config $ + do case mimeUnrender' accept (NH.responseBody httpResponse) of + Left s -> do + logNST LG.LevelError "Client" (T.pack s) + pure (Left (MimeError s httpResponse)) + Right r -> pure (Right r) + return (MimeResult parsedResult httpResponse) + +-- | like 'dispatchMime', but only returns the decoded http body +dispatchMime' + :: (Produces req accept, MimeUnrender accept res, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> SwaggerPetstoreConfig -- ^ config + -> SwaggerPetstoreRequest req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (Either MimeError res) -- ^ response +dispatchMime' manager config request accept = do + MimeResult parsedResult _ <- dispatchMime manager config request accept + return parsedResult + +-- ** Unsafe + +-- | like 'dispatchReqLbs', but does not validate the operation is a 'Producer' of the "accept" 'MimeType'. (Useful if the server's response is undocumented) +dispatchLbsUnsafe + :: (MimeType accept, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> SwaggerPetstoreConfig -- ^ config + -> SwaggerPetstoreRequest req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchLbsUnsafe manager config request accept = do + initReq <- _toInitRequest config request accept + dispatchInitUnsafe manager config initReq + +-- | dispatch an InitRequest +dispatchInitUnsafe + :: NH.Manager -- ^ http-client Connection manager + -> SwaggerPetstoreConfig -- ^ config + -> InitRequest req contentType res accept -- ^ init request + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchInitUnsafe manager config (InitRequest req) = do + runExceptionLoggingT logSrc config $ + do logNST LG.LevelInfo logSrc requestLogMsg + logNST LG.LevelDebug logSrc requestDbgLogMsg + res <- P.liftIO $ NH.httpLbs req manager + logNST LG.LevelInfo logSrc (responseLogMsg res) + logNST LG.LevelDebug logSrc ((T.pack . show) res) + return res + where + logSrc = "Client" + endpoint = + T.pack $ + BC.unpack $ + NH.method req <> " " <> NH.host req <> NH.path req <> NH.queryString req + requestLogMsg = "REQ:" <> endpoint + requestDbgLogMsg = + "Headers=" <> (T.pack . show) (NH.requestHeaders req) <> " Body=" <> + (case NH.requestBody req of + NH.RequestBodyLBS xs -> T.decodeUtf8 (BL.toStrict xs) + _ -> "") + responseStatusCode = (T.pack . show) . NH.statusCode . NH.responseStatus + responseLogMsg res = + "RES:statusCode=" <> responseStatusCode res <> " (" <> endpoint <> ")" + +-- * InitRequest + +-- | wraps an http-client 'Request' with request/response type parameters +newtype InitRequest req contentType res accept = InitRequest + { unInitRequest :: NH.Request + } deriving (Show) + +-- | Build an http-client 'Request' record from the supplied config and request +_toInitRequest + :: (MimeType accept, MimeType contentType) + => SwaggerPetstoreConfig -- ^ config + -> SwaggerPetstoreRequest req contentType res -- ^ request + -> accept -- ^ "accept" 'MimeType' + -> IO (InitRequest req contentType res accept) -- ^ initialized request +_toInitRequest config req0 accept = do + parsedReq <- NH.parseRequest $ BCL.unpack $ BCL.append (configHost config) (BCL.concat (urlPath req0)) + let req1 = _setAcceptHeader req0 accept & _setContentTypeHeader + reqHeaders = ("User-Agent", WH.toHeader (configUserAgent config)) : paramsHeaders (params req1) + reqQuery = NH.renderQuery True (paramsQuery (params req1)) + pReq = parsedReq { NH.method = (rMethod req1) + , NH.requestHeaders = reqHeaders + , NH.queryString = reqQuery + } + outReq <- case paramsBody (params req1) of + ParamBodyNone -> pure (pReq { NH.requestBody = mempty }) + ParamBodyB bs -> pure (pReq { NH.requestBody = NH.RequestBodyBS bs }) + ParamBodyBL bl -> pure (pReq { NH.requestBody = NH.RequestBodyLBS bl }) + ParamBodyFormUrlEncoded form -> pure (pReq { NH.requestBody = NH.RequestBodyLBS (WH.urlEncodeForm form) }) + ParamBodyMultipartFormData parts -> NH.formDataBody parts pReq + + pure (InitRequest outReq) + +-- | modify the underlying Request +modifyInitRequest :: InitRequest req contentType res accept -> (NH.Request -> NH.Request) -> InitRequest req contentType res accept +modifyInitRequest (InitRequest req) f = InitRequest (f req) + +-- | modify the underlying Request (monadic) +modifyInitRequestM :: Monad m => InitRequest req contentType res accept -> (NH.Request -> m NH.Request) -> m (InitRequest req contentType res accept) +modifyInitRequestM (InitRequest req) f = fmap InitRequest (f req) + +-- * Logging + +-- | A block using a MonadLogger instance +type ExecLoggingT = forall m. P.MonadIO m => + forall a. LG.LoggingT m a -> m a + +-- ** Null Logger + +-- | a logger which disables logging +nullLogger :: LG.Loc -> LG.LogSource -> LG.LogLevel -> LG.LogStr -> IO () +nullLogger _ _ _ _ = return () + +-- | run the monad transformer that disables logging +runNullLoggingT :: LG.LoggingT m a -> m a +runNullLoggingT = (`LG.runLoggingT` nullLogger) + +-- ** Logging Filters + +-- | a log filter that uses 'LevelError' as the minimum logging level +errorLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool +errorLevelFilter = minLevelFilter LG.LevelError + +-- | a log filter that uses 'LevelInfo' as the minimum logging level +infoLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool +infoLevelFilter = minLevelFilter LG.LevelInfo + +-- | a log filter that uses 'LevelDebug' as the minimum logging level +debugLevelFilter :: LG.LogSource -> LG.LogLevel -> Bool +debugLevelFilter = minLevelFilter LG.LevelDebug + +minLevelFilter :: LG.LogLevel -> LG.LogSource -> LG.LogLevel -> Bool +minLevelFilter l _ l' = l' >= l + +-- ** Logging + +-- | Log a message using the current time +logNST :: (P.MonadIO m, LG.MonadLogger m) => LG.LogLevel -> Text -> Text -> m () +logNST level src msg = do + now <- P.liftIO (formatTimeLog <$> TI.getCurrentTime) + LG.logOtherNS sourceLog level (now <> " " <> msg) + where + sourceLog = "SwaggerPetstore/" <> src + formatTimeLog = + T.pack . TI.formatTime TI.defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Z" + +-- | re-throws exceptions after logging them +logExceptions + :: (LG.MonadLogger m, E.MonadCatch m, P.MonadIO m) + => Text -> m a -> m a +logExceptions src = + E.handle + (\(e :: E.SomeException) -> do + logNST LG.LevelError src ((T.pack . show) e) + E.throw e) + +-- | Run a block using the configured MonadLogger instance +runLoggingT :: SwaggerPetstoreConfig -> ExecLoggingT +runLoggingT config = + configExecLoggingT config . LG.filterLogger (configLoggingFilter config) + +-- | Run a block using the configured MonadLogger instance (logs exceptions) +runExceptionLoggingT + :: (E.MonadCatch m, P.MonadIO m) + => T.Text -> SwaggerPetstoreConfig -> LG.LoggingT m a -> m a +runExceptionLoggingT logSrc config = runLoggingT config . logExceptions logSrc diff --git a/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Lens.hs b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Lens.hs new file mode 100644 index 00000000000..19c6ea3415a --- /dev/null +++ b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Lens.hs @@ -0,0 +1,202 @@ +{-| +Module : SwaggerPetstore.Lens +-} + +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} +{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module SwaggerPetstore.Lens where + +import Data.Text (Text) + +import qualified Data.Aeson as A +import Data.Aeson (Value) +import qualified Data.ByteString as B +import Data.ByteString.Lazy (ByteString) +import qualified Data.Data as P (Data, Typeable) +import qualified Data.Map as Map + +import qualified Data.Time as TI +import Data.Time (UTCTime) + +import Prelude (($), (.),(<$>),(<*>),(=<<),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor) +import qualified Prelude as P + +import SwaggerPetstore.Model + +-- * Type Aliases + +type Traversal_' s a = Traversal_ s s a a +type Traversal_ s t a b = forall (f :: * -> *). Applicative f => (a -> f b) -> s -> f t +type Lens_' s a = Lens_ s s a a +type Lens_ s t a b = forall (f :: * -> *). Functor f => (a -> f b) -> s -> f t + + +-- * ApiResponse + +-- | 'apiResponseCode' Traversal +apiResponseCodeT :: Traversal_' ApiResponse Int +apiResponseCodeT f s = _mtraversal apiResponseCode (\b -> s { apiResponseCode = Just b}) f s +{-# INLINE apiResponseCodeT #-} + +-- | 'apiResponseType' Traversal +apiResponseTypeT :: Traversal_' ApiResponse Text +apiResponseTypeT f s = _mtraversal apiResponseType (\b -> s { apiResponseType = Just b}) f s +{-# INLINE apiResponseTypeT #-} + +-- | 'apiResponseMessage' Traversal +apiResponseMessageT :: Traversal_' ApiResponse Text +apiResponseMessageT f s = _mtraversal apiResponseMessage (\b -> s { apiResponseMessage = Just b}) f s +{-# INLINE apiResponseMessageT #-} + + + +-- * Category + +-- | 'categoryId' Traversal +categoryIdT :: Traversal_' Category Integer +categoryIdT f s = _mtraversal categoryId (\b -> s { categoryId = Just b}) f s +{-# INLINE categoryIdT #-} + +-- | 'categoryName' Traversal +categoryNameT :: Traversal_' Category Text +categoryNameT f s = _mtraversal categoryName (\b -> s { categoryName = Just b}) f s +{-# INLINE categoryNameT #-} + + + +-- * Order + +-- | 'orderId' Traversal +orderIdT :: Traversal_' Order Integer +orderIdT f s = _mtraversal orderId (\b -> s { orderId = Just b}) f s +{-# INLINE orderIdT #-} + +-- | 'orderPetId' Traversal +orderPetIdT :: Traversal_' Order Integer +orderPetIdT f s = _mtraversal orderPetId (\b -> s { orderPetId = Just b}) f s +{-# INLINE orderPetIdT #-} + +-- | 'orderQuantity' Traversal +orderQuantityT :: Traversal_' Order Int +orderQuantityT f s = _mtraversal orderQuantity (\b -> s { orderQuantity = Just b}) f s +{-# INLINE orderQuantityT #-} + +-- | 'orderShipDate' Traversal +orderShipDateT :: Traversal_' Order UTCTime +orderShipDateT f s = _mtraversal orderShipDate (\b -> s { orderShipDate = Just b}) f s +{-# INLINE orderShipDateT #-} + +-- | 'orderStatus' Traversal +orderStatusT :: Traversal_' Order Text +orderStatusT f s = _mtraversal orderStatus (\b -> s { orderStatus = Just b}) f s +{-# INLINE orderStatusT #-} + +-- | 'orderComplete' Traversal +orderCompleteT :: Traversal_' Order Bool +orderCompleteT f s = _mtraversal orderComplete (\b -> s { orderComplete = Just b}) f s +{-# INLINE orderCompleteT #-} + + + +-- * Pet + +-- | 'petId' Traversal +petIdT :: Traversal_' Pet Integer +petIdT f s = _mtraversal petId (\b -> s { petId = Just b}) f s +{-# INLINE petIdT #-} + +-- | 'petCategory' Traversal +petCategoryT :: Traversal_' Pet Category +petCategoryT f s = _mtraversal petCategory (\b -> s { petCategory = Just b}) f s +{-# INLINE petCategoryT #-} + +-- | 'petName' Lens +petNameL :: Lens_' Pet Text +petNameL f Pet{..} = (\petName -> Pet { petName, ..} ) <$> f petName +{-# INLINE petNameL #-} + +-- | 'petPhotoUrls' Lens +petPhotoUrlsL :: Lens_' Pet [Text] +petPhotoUrlsL f Pet{..} = (\petPhotoUrls -> Pet { petPhotoUrls, ..} ) <$> f petPhotoUrls +{-# INLINE petPhotoUrlsL #-} + +-- | 'petTags' Traversal +petTagsT :: Traversal_' Pet [Tag] +petTagsT f s = _mtraversal petTags (\b -> s { petTags = Just b}) f s +{-# INLINE petTagsT #-} + +-- | 'petStatus' Traversal +petStatusT :: Traversal_' Pet Text +petStatusT f s = _mtraversal petStatus (\b -> s { petStatus = Just b}) f s +{-# INLINE petStatusT #-} + + + +-- * Tag + +-- | 'tagId' Traversal +tagIdT :: Traversal_' Tag Integer +tagIdT f s = _mtraversal tagId (\b -> s { tagId = Just b}) f s +{-# INLINE tagIdT #-} + +-- | 'tagName' Traversal +tagNameT :: Traversal_' Tag Text +tagNameT f s = _mtraversal tagName (\b -> s { tagName = Just b}) f s +{-# INLINE tagNameT #-} + + + +-- * User + +-- | 'userId' Traversal +userIdT :: Traversal_' User Integer +userIdT f s = _mtraversal userId (\b -> s { userId = Just b}) f s +{-# INLINE userIdT #-} + +-- | 'userUsername' Traversal +userUsernameT :: Traversal_' User Text +userUsernameT f s = _mtraversal userUsername (\b -> s { userUsername = Just b}) f s +{-# INLINE userUsernameT #-} + +-- | 'userFirstName' Traversal +userFirstNameT :: Traversal_' User Text +userFirstNameT f s = _mtraversal userFirstName (\b -> s { userFirstName = Just b}) f s +{-# INLINE userFirstNameT #-} + +-- | 'userLastName' Traversal +userLastNameT :: Traversal_' User Text +userLastNameT f s = _mtraversal userLastName (\b -> s { userLastName = Just b}) f s +{-# INLINE userLastNameT #-} + +-- | 'userEmail' Traversal +userEmailT :: Traversal_' User Text +userEmailT f s = _mtraversal userEmail (\b -> s { userEmail = Just b}) f s +{-# INLINE userEmailT #-} + +-- | 'userPassword' Traversal +userPasswordT :: Traversal_' User Text +userPasswordT f s = _mtraversal userPassword (\b -> s { userPassword = Just b}) f s +{-# INLINE userPasswordT #-} + +-- | 'userPhone' Traversal +userPhoneT :: Traversal_' User Text +userPhoneT f s = _mtraversal userPhone (\b -> s { userPhone = Just b}) f s +{-# INLINE userPhoneT #-} + +-- | 'userUserStatus' Traversal +userUserStatusT :: Traversal_' User Int +userUserStatusT f s = _mtraversal userUserStatus (\b -> s { userUserStatus = Just b}) f s +{-# INLINE userUserStatusT #-} + + + + +-- * Helpers + +_mtraversal :: Applicative f => (b -> Maybe t) -> (a -> b) -> (t -> f a) -> b -> f b +_mtraversal x fsb f s = maybe (pure s) (\a -> fsb <$> f a) (x s) +{-# INLINE _mtraversal #-} diff --git a/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/MimeTypes.hs b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/MimeTypes.hs new file mode 100644 index 00000000000..d10b66356a3 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/MimeTypes.hs @@ -0,0 +1,190 @@ + +{-| +Module : SwaggerPetstore.MimeTypes +-} + +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module SwaggerPetstore.MimeTypes where + + +import qualified Data.Aeson as A + +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Builder as BB +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy.Char8 as BCL + +import qualified Network.HTTP.Media as ME + +import qualified Web.FormUrlEncoded as WH + +import qualified Data.Data as P (Typeable) +import qualified Data.Proxy as P (Proxy(..)) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Control.Arrow as P (left) + +import Prelude (($), (.),(<$>),(<*>),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty) +import qualified Prelude as P + +-- * Content Negotiation + +-- | A type for responses without content-body. +data NoContent = NoContent + deriving (P.Show, P.Eq) + +-- ** Mime Types + +data MimeJSON = MimeJSON deriving (P.Typeable) +data MimeXML = MimeXML deriving (P.Typeable) +data MimePlainText = MimePlainText deriving (P.Typeable) +data MimeFormUrlEncoded = MimeFormUrlEncoded deriving (P.Typeable) +data MimeMultipartFormData = MimeMultipartFormData deriving (P.Typeable) +data MimeOctetStream = MimeOctetStream deriving (P.Typeable) +data MimeNoContent = MimeNoContent deriving (P.Typeable) + + +-- ** MimeType Class + +class P.Typeable mtype => MimeType mtype where + {-# MINIMAL mimeType | mimeTypes #-} + + mimeTypes :: P.Proxy mtype -> [ME.MediaType] + mimeTypes p = + case mimeType p of + Just x -> [x] + Nothing -> [] + + mimeType :: P.Proxy mtype -> Maybe ME.MediaType + mimeType p = + case mimeTypes p of + [] -> Nothing + (x:_) -> Just x + + mimeType' :: mtype -> Maybe ME.MediaType + mimeType' _ = mimeType (P.Proxy :: P.Proxy mtype) + mimeTypes' :: mtype -> [ME.MediaType] + mimeTypes' _ = mimeTypes (P.Proxy :: P.Proxy mtype) + +-- ** MimeType Instances + +-- | @application/json@ +instance MimeType MimeJSON where + mimeTypes _ = + [ "application" ME.// "json" ME./: ("charset", "utf-8") + , "application" ME.// "json" + ] + +-- | @application/xml@ +instance MimeType MimeXML where + mimeType _ = Just $ "application" ME.// "xml" + +-- | @application/x-www-form-urlencoded@ +instance MimeType MimeFormUrlEncoded where + mimeType _ = Just $ "application" ME.// "x-www-form-urlencoded" + +-- | @multipart/form-data@ +instance MimeType MimeMultipartFormData where + mimeType _ = Just $ "multipart" ME.// "form-data" + +-- | @text/plain;charset=utf-8@ +instance MimeType MimePlainText where + mimeType _ = Just $ "text" ME.// "plain" ME./: ("charset", "utf-8") +instance MimeType MimeOctetStream where + mimeType _ = Just $ "application" ME.// "octet-stream" +instance MimeType MimeNoContent where + mimeType _ = Nothing + + +-- ** MimeRender Class + +class MimeType mtype => MimeRender mtype x where + mimeRender :: P.Proxy mtype -> x -> BL.ByteString + mimeRender' :: mtype -> x -> BL.ByteString + mimeRender' _ x = mimeRender (P.Proxy :: P.Proxy mtype) x + + +-- ** MimeRender Instances + +-- | `A.encode` +instance A.ToJSON a => MimeRender MimeJSON a where mimeRender _ = A.encode +-- | @WH.urlEncodeAsForm@ +instance WH.ToForm a => MimeRender MimeFormUrlEncoded a where mimeRender _ = WH.urlEncodeAsForm + +-- | @P.id@ +instance MimeRender MimePlainText BL.ByteString where mimeRender _ = P.id +-- | @BL.fromStrict . T.encodeUtf8@ +instance MimeRender MimePlainText T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8 +-- | @BCL.pack@ +instance MimeRender MimePlainText String where mimeRender _ = BCL.pack + +-- | @P.id@ +instance MimeRender MimeOctetStream BL.ByteString where mimeRender _ = P.id +-- | @BL.fromStrict . T.encodeUtf8@ +instance MimeRender MimeOctetStream T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8 +-- | @BCL.pack@ +instance MimeRender MimeOctetStream String where mimeRender _ = BCL.pack + +-- | @P.id@ +instance MimeRender MimeMultipartFormData BL.ByteString where mimeRender _ = P.id +-- | @BL.fromStrict . T.encodeUtf8@ +instance MimeRender MimeMultipartFormData T.Text where mimeRender _ = BL.fromStrict . T.encodeUtf8 +-- | @BCL.pack@ +instance MimeRender MimeMultipartFormData String where mimeRender _ = BCL.pack + +-- | @P.Right . P.const NoContent@ +instance MimeRender MimeNoContent NoContent where mimeRender _ = P.const BCL.empty + +-- instance MimeRender MimeOctetStream Double where mimeRender _ = BB.toLazyByteString . BB.doubleDec +-- instance MimeRender MimeOctetStream Float where mimeRender _ = BB.toLazyByteString . BB.floatDec +-- instance MimeRender MimeOctetStream Int where mimeRender _ = BB.toLazyByteString . BB.intDec +-- instance MimeRender MimeOctetStream Integer where mimeRender _ = BB.toLazyByteString . BB.integerDec + + +-- ** MimeUnrender Class + +class MimeType mtype => MimeUnrender mtype o where + mimeUnrender :: P.Proxy mtype -> BL.ByteString -> P.Either String o + mimeUnrender' :: mtype -> BL.ByteString -> P.Either String o + mimeUnrender' _ x = mimeUnrender (P.Proxy :: P.Proxy mtype) x + +-- ** MimeUnrender Instances + +-- | @A.eitherDecode@ +instance A.FromJSON a => MimeUnrender MimeJSON a where mimeUnrender _ = A.eitherDecode +-- | @P.left T.unpack . WH.urlDecodeAsForm@ +instance WH.FromForm a => MimeUnrender MimeFormUrlEncoded a where mimeUnrender _ = P.left T.unpack . WH.urlDecodeAsForm +-- | @P.Right . P.id@ + +instance MimeUnrender MimePlainText BL.ByteString where mimeUnrender _ = P.Right . P.id +-- | @P.left P.show . TL.decodeUtf8'@ +instance MimeUnrender MimePlainText T.Text where mimeUnrender _ = P.left P.show . T.decodeUtf8' . BL.toStrict +-- | @P.Right . BCL.unpack@ +instance MimeUnrender MimePlainText String where mimeUnrender _ = P.Right . BCL.unpack + +-- | @P.Right . P.id@ +instance MimeUnrender MimeOctetStream BL.ByteString where mimeUnrender _ = P.Right . P.id +-- | @P.left P.show . T.decodeUtf8' . BL.toStrict@ +instance MimeUnrender MimeOctetStream T.Text where mimeUnrender _ = P.left P.show . T.decodeUtf8' . BL.toStrict +-- | @P.Right . BCL.unpack@ +instance MimeUnrender MimeOctetStream String where mimeUnrender _ = P.Right . BCL.unpack + +-- | @P.Right . P.const NoContent@ +instance MimeUnrender MimeNoContent NoContent where mimeUnrender _ = P.Right . P.const NoContent + + +-- ** Request Consumes + +class MimeType mtype => Consumes req mtype where + +-- ** Request Produces + +class MimeType mtype => Produces req mtype where diff --git a/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Model.hs b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Model.hs new file mode 100644 index 00000000000..a9faf092395 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/lib/SwaggerPetstore/Model.hs @@ -0,0 +1,378 @@ +{-| +Module : SwaggerPetstore.Model +-} + +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module SwaggerPetstore.Model where + +import Data.Aeson ((.:),(.:!),(.:?),(.=)) +import Data.Text (Text) + +import Data.Aeson (Value) +import Data.ByteString.Lazy (ByteString) + +import qualified Data.Aeson as A +import qualified Data.ByteString as B +import qualified Data.Data as P (Data, Typeable) +import qualified Data.HashMap.Lazy as HM +import qualified Data.Map as Map +import qualified Data.Maybe as P +import qualified Data.Foldable as P +import qualified Web.FormUrlEncoded as WH +import qualified Web.HttpApiData as WH + +import qualified Data.Time as TI +import qualified Data.Time.ISO8601 as TI +import Data.Time (UTCTime) + +import Control.Applicative ((<|>)) +import Control.Applicative (Alternative) +import Prelude (($), (.),(<$>),(<*>),(>>=),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor) +import qualified Prelude as P + + + +-- * Models + + +-- ** ApiResponse +-- | +-- An uploaded response +-- +-- Describes the result of uploading an image resource +data ApiResponse = ApiResponse + { apiResponseCode :: Maybe Int -- ^ "code" + , apiResponseType :: Maybe Text -- ^ "type" + , apiResponseMessage :: Maybe Text -- ^ "message" + } deriving (P.Show,P.Eq,P.Typeable) + +instance A.FromJSON ApiResponse where + parseJSON = A.withObject "ApiResponse" $ \o -> + ApiResponse + <$> (o .:? "code") + <*> (o .:? "type") + <*> (o .:? "message") + +instance A.ToJSON ApiResponse where + toJSON ApiResponse {..} = + _omitNulls + [ "code" .= apiResponseCode + , "type" .= apiResponseType + , "message" .= apiResponseMessage + ] + + +-- | Construct a value of type 'ApiResponse' (by applying it's required fields, if any) +mkApiResponse + :: ApiResponse +mkApiResponse = + ApiResponse + { apiResponseCode = Nothing + , apiResponseType = Nothing + , apiResponseMessage = Nothing + } + + + +-- ** Category +-- | +-- Pet catehgry +-- +-- A category for a pet +data Category = Category + { categoryId :: Maybe Integer -- ^ "id" + , categoryName :: Maybe Text -- ^ "name" + } deriving (P.Show,P.Eq,P.Typeable) + +instance A.FromJSON Category where + parseJSON = A.withObject "Category" $ \o -> + Category + <$> (o .:? "id") + <*> (o .:? "name") + +instance A.ToJSON Category where + toJSON Category {..} = + _omitNulls + [ "id" .= categoryId + , "name" .= categoryName + ] + + +-- | Construct a value of type 'Category' (by applying it's required fields, if any) +mkCategory + :: Category +mkCategory = + Category + { categoryId = Nothing + , categoryName = Nothing + } + + + +-- ** Order +-- | +-- Pet Order +-- +-- An order for a pets from the pet store +data Order = Order + { orderId :: Maybe Integer -- ^ "id" + , orderPetId :: Maybe Integer -- ^ "petId" + , orderQuantity :: Maybe Int -- ^ "quantity" + , orderShipDate :: Maybe UTCTime -- ^ "shipDate" + , orderStatus :: Maybe Text -- ^ "status" - Order Status + , orderComplete :: Maybe Bool -- ^ "complete" + } deriving (P.Show,P.Eq,P.Typeable) + +instance A.FromJSON Order where + parseJSON = A.withObject "Order" $ \o -> + Order + <$> (o .:? "id") + <*> (o .:? "petId") + <*> (o .:? "quantity") + <*> (o .:? "shipDate" >>= P.mapM _readDateTime) + <*> (o .:? "status") + <*> (o .:? "complete") + +instance A.ToJSON Order where + toJSON Order {..} = + _omitNulls + [ "id" .= orderId + , "petId" .= orderPetId + , "quantity" .= orderQuantity + , "shipDate" .= P.fmap _showDateTime orderShipDate + , "status" .= orderStatus + , "complete" .= orderComplete + ] + + +-- | Construct a value of type 'Order' (by applying it's required fields, if any) +mkOrder + :: Order +mkOrder = + Order + { orderId = Nothing + , orderPetId = Nothing + , orderQuantity = Nothing + , orderShipDate = Nothing + , orderStatus = Nothing + , orderComplete = Nothing + } + + + +-- ** Pet +-- | +-- a Pet +-- +-- A pet for sale in the pet store +data Pet = Pet + { petId :: Maybe Integer -- ^ "id" + , petCategory :: Maybe Category -- ^ "category" + , petName :: Text -- ^ /Required/ "name" + , petPhotoUrls :: [Text] -- ^ /Required/ "photoUrls" + , petTags :: Maybe [Tag] -- ^ "tags" + , petStatus :: Maybe Text -- ^ "status" - pet status in the store + } deriving (P.Show,P.Eq,P.Typeable) + +instance A.FromJSON Pet where + parseJSON = A.withObject "Pet" $ \o -> + Pet + <$> (o .:? "id") + <*> (o .:? "category") + <*> (o .: "name") + <*> (o .: "photoUrls") + <*> (o .:? "tags") + <*> (o .:? "status") + +instance A.ToJSON Pet where + toJSON Pet {..} = + _omitNulls + [ "id" .= petId + , "category" .= petCategory + , "name" .= petName + , "photoUrls" .= petPhotoUrls + , "tags" .= petTags + , "status" .= petStatus + ] + + +-- | Construct a value of type 'Pet' (by applying it's required fields, if any) +mkPet + :: Text -- ^ 'petName' + -> [Text] -- ^ 'petPhotoUrls' + -> Pet +mkPet petName petPhotoUrls = + Pet + { petId = Nothing + , petCategory = Nothing + , petName + , petPhotoUrls + , petTags = Nothing + , petStatus = Nothing + } + + + +-- ** Tag +-- | +-- Pet Tag +-- +-- A tag for a pet +data Tag = Tag + { tagId :: Maybe Integer -- ^ "id" + , tagName :: Maybe Text -- ^ "name" + } deriving (P.Show,P.Eq,P.Typeable) + +instance A.FromJSON Tag where + parseJSON = A.withObject "Tag" $ \o -> + Tag + <$> (o .:? "id") + <*> (o .:? "name") + +instance A.ToJSON Tag where + toJSON Tag {..} = + _omitNulls + [ "id" .= tagId + , "name" .= tagName + ] + + +-- | Construct a value of type 'Tag' (by applying it's required fields, if any) +mkTag + :: Tag +mkTag = + Tag + { tagId = Nothing + , tagName = Nothing + } + + + +-- ** User +-- | +-- a User +-- +-- A User who is purchasing from the pet store +data User = User + { userId :: Maybe Integer -- ^ "id" + , userUsername :: Maybe Text -- ^ "username" + , userFirstName :: Maybe Text -- ^ "firstName" + , userLastName :: Maybe Text -- ^ "lastName" + , userEmail :: Maybe Text -- ^ "email" + , userPassword :: Maybe Text -- ^ "password" + , userPhone :: Maybe Text -- ^ "phone" + , userUserStatus :: Maybe Int -- ^ "userStatus" - User Status + } deriving (P.Show,P.Eq,P.Typeable) + +instance A.FromJSON User where + parseJSON = A.withObject "User" $ \o -> + User + <$> (o .:? "id") + <*> (o .:? "username") + <*> (o .:? "firstName") + <*> (o .:? "lastName") + <*> (o .:? "email") + <*> (o .:? "password") + <*> (o .:? "phone") + <*> (o .:? "userStatus") + +instance A.ToJSON User where + toJSON User {..} = + _omitNulls + [ "id" .= userId + , "username" .= userUsername + , "firstName" .= userFirstName + , "lastName" .= userLastName + , "email" .= userEmail + , "password" .= userPassword + , "phone" .= userPhone + , "userStatus" .= userUserStatus + ] + + +-- | Construct a value of type 'User' (by applying it's required fields, if any) +mkUser + :: User +mkUser = + User + { userId = Nothing + , userUsername = Nothing + , userFirstName = Nothing + , userLastName = Nothing + , userEmail = Nothing + , userPassword = Nothing + , userPhone = Nothing + , userUserStatus = Nothing + } + + + +-- * Utils + +-- | Removes Null fields. (OpenAPI-Specification 2.0 does not allow Null in JSON) + +_omitNulls :: [(Text, A.Value)] -> A.Value +_omitNulls = A.object . P.filter notNull + where + notNull (_, A.Null) = False + notNull _ = True + +_toFormItem :: (WH.ToHttpApiData a, Functor f) => t -> f a -> f (t, [Text]) +_toFormItem name x = (name,) . (:[]) . WH.toQueryParam <$> x + +_emptyToNothing :: Maybe String -> Maybe String +_emptyToNothing (Just "") = Nothing +_emptyToNothing x = x +{-# INLINE _emptyToNothing #-} + +_memptyToNothing :: (P.Monoid a, P.Eq a) => Maybe a -> Maybe a +_memptyToNothing (Just x) | x P.== P.mempty = Nothing +_memptyToNothing x = x +{-# INLINE _memptyToNothing #-} + +-- * DateTime Formatting + +-- | @_parseISO8601@ +_readDateTime :: (TI.ParseTime t, Monad m, Alternative m) => String -> m t +_readDateTime = + _parseISO8601 +{-# INLINE _readDateTime #-} + +-- | @TI.formatISO8601Millis@ +_showDateTime :: (t ~ UTCTime, TI.FormatTime t) => t -> String +_showDateTime = + TI.formatISO8601Millis +{-# INLINE _showDateTime #-} + +_parseISO8601 :: (TI.ParseTime t, Monad m, Alternative m) => String -> m t +_parseISO8601 t = + P.asum $ + P.flip (TI.parseTimeM True TI.defaultTimeLocale) t <$> + ["%FT%T%QZ", "%FT%T%Q%z", "%FT%T%Q%Z"] +{-# INLINE _parseISO8601 #-} + +-- * Date Formatting + +-- | @TI.parseTimeM True TI.defaultTimeLocale ""@ +_readDate :: (TI.ParseTime t, Monad m) => String -> m t +_readDate = + TI.parseTimeM True TI.defaultTimeLocale "" +{-# INLINE _readDate #-} + +-- | @TI.formatTime TI.defaultTimeLocale ""@ +_showDate :: TI.FormatTime t => t -> String +_showDate = + TI.formatTime TI.defaultTimeLocale "" +{-# INLINE _showDate #-} \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/package.yaml b/samples/client/petstore/haskell-http-client/package.yaml new file mode 100644 index 00000000000..19711dee476 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/package.yaml @@ -0,0 +1,81 @@ +name: swagger-petstore +version: '0.1.0.0' +synopsis: Auto-generated swagger-petstore API Client +description: ! ' + + Client library for calling the swagger-petstore API based on http-client. + + host: petstore.swagger.io + + + base path: http://petstore.swagger.io/v2 + + + apiVersion: 0.0.1 + + + swagger version: 2.0 + + + OpenAPI-Specification: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md +' +category: Web +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +homepage: https://github.com/swagger-api/swagger-codegen#readme +extra-source-files: +- README.md +- swagger.json +dependencies: +- base >=4.7 && <5.0 +- transformers >=0.4.0.0 +- mtl >=2.2.1 +- unordered-containers +library: + source-dirs: lib + ghc-options: -Wall + exposed-modules: + - SwaggerPetstore + - SwaggerPetstore.API + - SwaggerPetstore.Client + - SwaggerPetstore.Model + - SwaggerPetstore.MimeTypes + - SwaggerPetstore.Lens + dependencies: + - aeson >=1.0 && <2.0 + - bytestring >=0.10.0 && <0.11 + - containers >=0.5.0.0 && <0.6 + - http-types >=0.8 && <0.10 + - http-client >=0.5 && <0.6 + - http-client-tls + - http-api-data >= 0.3.4 && <0.4 + - http-media >= 0.4 && < 0.8 + - text >=0.11 && <1.3 + - time >=1.5 && <1.9 + - iso8601-time >=0.1.3 && <0.2.0 + - vector >=0.10.9 && <0.13 + - network >=2.6.2 && <2.7 + - random >=1.1 + - exceptions >= 0.4 + - monad-logger >=0.3 && <0.4 + - safe-exceptions <0.2 + - case-insensitive +tests: + tests: + main: Test.hs + source-dirs: tests + ghc-options: + - -fno-warn-orphans + dependencies: + - swagger-petstore + - bytestring >=0.10.0 && <0.11 + - containers + - hspec >=1.8 + - text + - time + - iso8601-time + - aeson + - semigroups + - QuickCheck diff --git a/samples/client/petstore/haskell-http-client/pom.xml b/samples/client/petstore/haskell-http-client/pom.xml new file mode 100644 index 00000000000..7ef1adb2331 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + io.swagger + swagger-petstore-haskell-http-client + pom + 1.0-SNAPSHOT + Swagger Petstore - Haskell http-client Client + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory} + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + stack-haddock + pre-integration-test + + exec + + + stack + + --install-ghc + --no-haddock-deps + haddock + + + + + stack-test + integration-test + + exec + + + stack + + test + + + + + + + + diff --git a/samples/client/petstore/haskell-http-client/stack.yaml b/samples/client/petstore/haskell-http-client/stack.yaml new file mode 100644 index 00000000000..174a76815bc --- /dev/null +++ b/samples/client/petstore/haskell-http-client/stack.yaml @@ -0,0 +1,8 @@ +resolver: lts-9.0 +build: + haddock-arguments: + haddock-args: + - "--odir=./docs" +extra-deps: [] +packages: +- '.' diff --git a/samples/client/petstore/haskell-http-client/swagger-petstore.cabal b/samples/client/petstore/haskell-http-client/swagger-petstore.cabal new file mode 100644 index 00000000000..fd7d16c7f93 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/swagger-petstore.cabal @@ -0,0 +1,94 @@ +-- This file has been generated from package.yaml by hpack version 0.17.1. +-- +-- see: https://github.com/sol/hpack + +name: swagger-petstore +version: 0.1.0.0 +synopsis: Auto-generated swagger-petstore API Client +description: . + Client library for calling the swagger-petstore API based on http-client. + . + base path: http://petstore.swagger.io/v2 + . + apiVersion: 0.0.1 + . + swagger version: 2.0 + . + OpenAPI-Specification: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md +category: Web +homepage: https://github.com/swagger-api/swagger-codegen#readme +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +build-type: Simple +cabal-version: >= 1.10 + +extra-source-files: + README.md + swagger.json + +library + hs-source-dirs: + lib + ghc-options: -Wall + build-depends: + base >=4.7 && <5.0 + , transformers >=0.4.0.0 + , mtl >=2.2.1 + , unordered-containers + , aeson >=1.0 && <2.0 + , bytestring >=0.10.0 && <0.11 + , containers >=0.5.0.0 && <0.6 + , http-types >=0.8 && <0.10 + , http-client >=0.5 && <0.6 + , http-client-tls + , http-api-data >= 0.3.4 && <0.4 + , http-media >= 0.4 && < 0.8 + , text >=0.11 && <1.3 + , time >=1.5 && <1.9 + , iso8601-time >=0.1.3 && <0.2.0 + , vector >=0.10.9 && <0.13 + , network >=2.6.2 && <2.7 + , random >=1.1 + , exceptions >= 0.4 + , monad-logger >=0.3 && <0.4 + , safe-exceptions <0.2 + , case-insensitive + exposed-modules: + SwaggerPetstore + SwaggerPetstore.API + SwaggerPetstore.Client + SwaggerPetstore.Model + SwaggerPetstore.MimeTypes + SwaggerPetstore.Lens + other-modules: + Paths_swagger_petstore + default-language: Haskell2010 + +test-suite tests + type: exitcode-stdio-1.0 + main-is: Test.hs + hs-source-dirs: + tests + ghc-options: -fno-warn-orphans + build-depends: + base >=4.7 && <5.0 + , transformers >=0.4.0.0 + , mtl >=2.2.1 + , unordered-containers + , swagger-petstore + , bytestring >=0.10.0 && <0.11 + , containers + , hspec >=1.8 + , text + , time + , iso8601-time + , aeson + , semigroups + , QuickCheck + other-modules: + ApproxEq + Instances + PropMime + default-language: Haskell2010 diff --git a/samples/client/petstore/haskell-http-client/swagger.json b/samples/client/petstore/haskell-http-client/swagger.json new file mode 100644 index 00000000000..a16c8a8a14d --- /dev/null +++ b/samples/client/petstore/haskell-http-client/swagger.json @@ -0,0 +1,831 @@ +{ + "swagger" : "2.0", + "info" : { + "description" : "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", + "version" : "1.0.0", + "title" : "Swagger Petstore", + "termsOfService" : "http://swagger.io/terms/", + "contact" : { + "email" : "apiteam@swagger.io" + }, + "license" : { + "name" : "Apache 2.0", + "url" : "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host" : "petstore.swagger.io", + "basePath" : "/v2", + "tags" : [ { + "name" : "pet", + "description" : "Everything about your Pets", + "externalDocs" : { + "description" : "Find out more", + "url" : "http://swagger.io" + } + }, { + "name" : "store", + "description" : "Access to Petstore orders" + }, { + "name" : "user", + "description" : "Operations about user", + "externalDocs" : { + "description" : "Find out more about our store", + "url" : "http://swagger.io" + } + } ], + "schemes" : [ "http" ], + "paths" : { + "/pet" : { + "post" : { + "tags" : [ "pet" ], + "summary" : "Add a new pet to the store", + "description" : "", + "operationId" : "addPet", + "consumes" : [ "application/json", "application/xml" ], + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "in" : "body", + "name" : "body", + "description" : "Pet object that needs to be added to the store", + "required" : true, + "schema" : { + "$ref" : "#/definitions/Pet" + } + } ], + "responses" : { + "405" : { + "description" : "Invalid input" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + }, + "put" : { + "tags" : [ "pet" ], + "summary" : "Update an existing pet", + "description" : "", + "operationId" : "updatePet", + "consumes" : [ "application/json", "application/xml" ], + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "in" : "body", + "name" : "body", + "description" : "Pet object that needs to be added to the store", + "required" : true, + "schema" : { + "$ref" : "#/definitions/Pet" + } + } ], + "responses" : { + "400" : { + "description" : "Invalid ID supplied" + }, + "404" : { + "description" : "Pet not found" + }, + "405" : { + "description" : "Validation exception" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + } + }, + "/pet/findByStatus" : { + "get" : { + "tags" : [ "pet" ], + "summary" : "Finds Pets by status", + "description" : "Multiple status values can be provided with comma separated strings", + "operationId" : "findPetsByStatus", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "status", + "in" : "query", + "description" : "Status values that need to be considered for filter", + "required" : true, + "type" : "array", + "items" : { + "type" : "string", + "enum" : [ "available", "pending", "sold" ], + "default" : "available" + }, + "collectionFormat" : "csv" + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/definitions/Pet" + } + } + }, + "400" : { + "description" : "Invalid status value" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + } + }, + "/pet/findByTags" : { + "get" : { + "tags" : [ "pet" ], + "summary" : "Finds Pets by tags", + "description" : "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "operationId" : "findPetsByTags", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "tags", + "in" : "query", + "description" : "Tags to filter by", + "required" : true, + "type" : "array", + "items" : { + "type" : "string" + }, + "collectionFormat" : "csv" + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/definitions/Pet" + } + } + }, + "400" : { + "description" : "Invalid tag value" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ], + "deprecated" : true + } + }, + "/pet/{petId}" : { + "get" : { + "tags" : [ "pet" ], + "summary" : "Find pet by ID", + "description" : "Returns a single pet", + "operationId" : "getPetById", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "petId", + "in" : "path", + "description" : "ID of pet to return", + "required" : true, + "type" : "integer", + "format" : "int64" + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "$ref" : "#/definitions/Pet" + } + }, + "400" : { + "description" : "Invalid ID supplied" + }, + "404" : { + "description" : "Pet not found" + } + }, + "security" : [ { + "api_key" : [ ] + } ] + }, + "post" : { + "tags" : [ "pet" ], + "summary" : "Updates a pet in the store with form data", + "description" : "", + "operationId" : "updatePetWithForm", + "consumes" : [ "application/x-www-form-urlencoded" ], + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "petId", + "in" : "path", + "description" : "ID of pet that needs to be updated", + "required" : true, + "type" : "integer", + "format" : "int64" + }, { + "name" : "name", + "in" : "formData", + "description" : "Updated name of the pet", + "required" : false, + "type" : "string" + }, { + "name" : "status", + "in" : "formData", + "description" : "Updated status of the pet", + "required" : false, + "type" : "string" + } ], + "responses" : { + "405" : { + "description" : "Invalid input" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + }, + "delete" : { + "tags" : [ "pet" ], + "summary" : "Deletes a pet", + "description" : "", + "operationId" : "deletePet", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "api_key", + "in" : "header", + "required" : false, + "type" : "string" + }, { + "name" : "petId", + "in" : "path", + "description" : "Pet id to delete", + "required" : true, + "type" : "integer", + "format" : "int64" + } ], + "responses" : { + "400" : { + "description" : "Invalid pet value" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + } + }, + "/pet/{petId}/uploadImage" : { + "post" : { + "tags" : [ "pet" ], + "summary" : "uploads an image", + "description" : "", + "operationId" : "uploadFile", + "consumes" : [ "multipart/form-data" ], + "produces" : [ "application/json" ], + "parameters" : [ { + "name" : "petId", + "in" : "path", + "description" : "ID of pet to update", + "required" : true, + "type" : "integer", + "format" : "int64" + }, { + "name" : "additionalMetadata", + "in" : "formData", + "description" : "Additional data to pass to server", + "required" : false, + "type" : "string" + }, { + "name" : "file", + "in" : "formData", + "description" : "file to upload", + "required" : false, + "type" : "file" + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "$ref" : "#/definitions/ApiResponse" + } + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + } + }, + "/store/inventory" : { + "get" : { + "tags" : [ "store" ], + "summary" : "Returns pet inventories by status", + "description" : "Returns a map of status codes to quantities", + "operationId" : "getInventory", + "produces" : [ "application/json" ], + "parameters" : [ ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "type" : "object", + "additionalProperties" : { + "type" : "integer", + "format" : "int32" + } + } + } + }, + "security" : [ { + "api_key" : [ ] + } ] + } + }, + "/store/order" : { + "post" : { + "tags" : [ "store" ], + "summary" : "Place an order for a pet", + "description" : "", + "operationId" : "placeOrder", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "in" : "body", + "name" : "body", + "description" : "order placed for purchasing the pet", + "required" : true, + "schema" : { + "$ref" : "#/definitions/Order" + } + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "$ref" : "#/definitions/Order" + } + }, + "400" : { + "description" : "Invalid Order" + } + } + } + }, + "/store/order/{orderId}" : { + "get" : { + "tags" : [ "store" ], + "summary" : "Find purchase order by ID", + "description" : "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions", + "operationId" : "getOrderById", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "orderId", + "in" : "path", + "description" : "ID of pet that needs to be fetched", + "required" : true, + "type" : "integer", + "maximum" : 5, + "minimum" : 1, + "format" : "int64" + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "$ref" : "#/definitions/Order" + } + }, + "400" : { + "description" : "Invalid ID supplied" + }, + "404" : { + "description" : "Order not found" + } + } + }, + "delete" : { + "tags" : [ "store" ], + "summary" : "Delete purchase order by ID", + "description" : "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "operationId" : "deleteOrder", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "orderId", + "in" : "path", + "description" : "ID of the order that needs to be deleted", + "required" : true, + "type" : "string" + } ], + "responses" : { + "400" : { + "description" : "Invalid ID supplied" + }, + "404" : { + "description" : "Order not found" + } + } + } + }, + "/user" : { + "post" : { + "tags" : [ "user" ], + "summary" : "Create user", + "description" : "This can only be done by the logged in user.", + "operationId" : "createUser", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "in" : "body", + "name" : "body", + "description" : "Created user object", + "required" : true, + "schema" : { + "$ref" : "#/definitions/User" + } + } ], + "responses" : { + "default" : { + "description" : "successful operation" + } + } + } + }, + "/user/createWithArray" : { + "post" : { + "tags" : [ "user" ], + "summary" : "Creates list of users with given input array", + "description" : "", + "operationId" : "createUsersWithArrayInput", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "in" : "body", + "name" : "body", + "description" : "List of user object", + "required" : true, + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/definitions/User" + } + } + } ], + "responses" : { + "default" : { + "description" : "successful operation" + } + } + } + }, + "/user/createWithList" : { + "post" : { + "tags" : [ "user" ], + "summary" : "Creates list of users with given input array", + "description" : "", + "operationId" : "createUsersWithListInput", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "in" : "body", + "name" : "body", + "description" : "List of user object", + "required" : true, + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/definitions/User" + } + } + } ], + "responses" : { + "default" : { + "description" : "successful operation" + } + } + } + }, + "/user/login" : { + "get" : { + "tags" : [ "user" ], + "summary" : "Logs user into the system", + "description" : "", + "operationId" : "loginUser", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "username", + "in" : "query", + "description" : "The user name for login", + "required" : true, + "type" : "string" + }, { + "name" : "password", + "in" : "query", + "description" : "The password for login in clear text", + "required" : true, + "type" : "string" + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "type" : "string" + }, + "headers" : { + "X-Rate-Limit" : { + "type" : "integer", + "format" : "int32", + "description" : "calls per hour allowed by the user" + }, + "X-Expires-After" : { + "type" : "string", + "format" : "date-time", + "description" : "date in UTC when toekn expires" + } + } + }, + "400" : { + "description" : "Invalid username/password supplied" + } + } + } + }, + "/user/logout" : { + "get" : { + "tags" : [ "user" ], + "summary" : "Logs out current logged in user session", + "description" : "", + "operationId" : "logoutUser", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ ], + "responses" : { + "default" : { + "description" : "successful operation" + } + } + } + }, + "/user/{username}" : { + "get" : { + "tags" : [ "user" ], + "summary" : "Get user by user name", + "description" : "", + "operationId" : "getUserByName", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The name that needs to be fetched. Use user1 for testing. ", + "required" : true, + "type" : "string" + } ], + "responses" : { + "200" : { + "description" : "successful operation", + "schema" : { + "$ref" : "#/definitions/User" + } + }, + "400" : { + "description" : "Invalid username supplied" + }, + "404" : { + "description" : "User not found" + } + } + }, + "put" : { + "tags" : [ "user" ], + "summary" : "Updated user", + "description" : "This can only be done by the logged in user.", + "operationId" : "updateUser", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "name that need to be deleted", + "required" : true, + "type" : "string" + }, { + "in" : "body", + "name" : "body", + "description" : "Updated user object", + "required" : true, + "schema" : { + "$ref" : "#/definitions/User" + } + } ], + "responses" : { + "400" : { + "description" : "Invalid user supplied" + }, + "404" : { + "description" : "User not found" + } + } + }, + "delete" : { + "tags" : [ "user" ], + "summary" : "Delete user", + "description" : "This can only be done by the logged in user.", + "operationId" : "deleteUser", + "produces" : [ "application/xml", "application/json" ], + "parameters" : [ { + "name" : "username", + "in" : "path", + "description" : "The name that needs to be deleted", + "required" : true, + "type" : "string" + } ], + "responses" : { + "400" : { + "description" : "Invalid username supplied" + }, + "404" : { + "description" : "User not found" + } + } + } + } + }, + "securityDefinitions" : { + "petstore_auth" : { + "type" : "oauth2", + "authorizationUrl" : "http://petstore.swagger.io/api/oauth/dialog", + "flow" : "implicit", + "scopes" : { + "write:pets" : "modify pets in your account", + "read:pets" : "read your pets" + } + }, + "api_key" : { + "type" : "apiKey", + "name" : "api_key", + "in" : "header" + } + }, + "definitions" : { + "Order" : { + "type" : "object", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64" + }, + "petId" : { + "type" : "integer", + "format" : "int64" + }, + "quantity" : { + "type" : "integer", + "format" : "int32" + }, + "shipDate" : { + "type" : "string", + "format" : "date-time" + }, + "status" : { + "type" : "string", + "description" : "Order Status", + "enum" : [ "placed", "approved", "delivered" ] + }, + "complete" : { + "type" : "boolean", + "default" : false + } + }, + "title" : "Pet Order", + "description" : "An order for a pets from the pet store", + "xml" : { + "name" : "Order" + } + }, + "Category" : { + "type" : "object", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64" + }, + "name" : { + "type" : "string" + } + }, + "title" : "Pet catehgry", + "description" : "A category for a pet", + "xml" : { + "name" : "Category" + } + }, + "User" : { + "type" : "object", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64" + }, + "username" : { + "type" : "string" + }, + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "password" : { + "type" : "string" + }, + "phone" : { + "type" : "string" + }, + "userStatus" : { + "type" : "integer", + "format" : "int32", + "description" : "User Status" + } + }, + "title" : "a User", + "description" : "A User who is purchasing from the pet store", + "xml" : { + "name" : "User" + } + }, + "Tag" : { + "type" : "object", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64" + }, + "name" : { + "type" : "string" + } + }, + "title" : "Pet Tag", + "description" : "A tag for a pet", + "xml" : { + "name" : "Tag" + } + }, + "Pet" : { + "type" : "object", + "required" : [ "name", "photoUrls" ], + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64" + }, + "category" : { + "$ref" : "#/definitions/Category" + }, + "name" : { + "type" : "string", + "example" : "doggie" + }, + "photoUrls" : { + "type" : "array", + "xml" : { + "name" : "photoUrl", + "wrapped" : true + }, + "items" : { + "type" : "string" + } + }, + "tags" : { + "type" : "array", + "xml" : { + "name" : "tag", + "wrapped" : true + }, + "items" : { + "$ref" : "#/definitions/Tag" + } + }, + "status" : { + "type" : "string", + "description" : "pet status in the store", + "enum" : [ "available", "pending", "sold" ] + } + }, + "title" : "a Pet", + "description" : "A pet for sale in the pet store", + "xml" : { + "name" : "Pet" + } + }, + "ApiResponse" : { + "type" : "object", + "properties" : { + "code" : { + "type" : "integer", + "format" : "int32" + }, + "type" : { + "type" : "string" + }, + "message" : { + "type" : "string" + } + }, + "title" : "An uploaded response", + "description" : "Describes the result of uploading an image resource" + } + }, + "externalDocs" : { + "description" : "Find out more about Swagger", + "url" : "http://swagger.io" + } +} \ No newline at end of file diff --git a/samples/client/petstore/haskell-http-client/tests-integration/README.md b/samples/client/petstore/haskell-http-client/tests-integration/README.md new file mode 100644 index 00000000000..66aba9b5c60 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests-integration/README.md @@ -0,0 +1,54 @@ +# swagger-petstore-tests-integration + +This contains integration tests for the haskell http-client swagger-petstore api client library. + +This module is not auto-generated. + +The integration tests require a swagger petstore server running at +`http://0.0.0.0/v2`, or the value of the `HOST` environment variable. + +The api client library bindings are expected to live in the parent folder + + +### Petstore Server + +The petstore server can be obtained at: + +https://github.com/wing328/swagger-samples/tree/docker/java/java-jersey-jaxrs + +Follow the instructions in the readme to install and run the petstore +server (the docker branch is used here, but docker is not required) + +### Usage + +1. Install the [Haskell `stack` tool](http://docs.haskellstack.org/en/stable/README). +2. Start the petstore server (described above) +3. To run the integration tests: +``` +stack --install-ghc test +``` +4. After stack installs ghc on the first run, `--install-ghc` can be omitted + +### Optional Environment Variables + +* `HOST` - the root url of the petstore server +* `http_proxy` - the address of the http proxy + +Example: + +``` +HOST=http://0.0.0.0/v2 http_proxy=http://0.0.0.0:8080 stack --install-ghc test +``` + + +### Running with Maven + +If using Maven, after ensuring the haskell `stack` tool is installed +(run `stack --version` to verify installation), an example command to +run the integration tests with maven in this directory is: + +``` +mvn -q verify -Pintegration-test +``` + +Adjust `pom.xml` as necessary to set environment variables. diff --git a/samples/client/petstore/haskell-http-client/tests-integration/package.yaml b/samples/client/petstore/haskell-http-client/tests-integration/package.yaml new file mode 100644 index 00000000000..2fb6db94d74 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests-integration/package.yaml @@ -0,0 +1,52 @@ +name: swagger-petstore-tests-integration +version: '0.1.0.0' +synopsis: integration tests for auto-generated swagger-petstore API Client +description: ! ' + integration tests for auto-generated swagger-petstore API Client +' +category: Web +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +homepage: https://github.com/swagger-api/swagger-codegen#readme +extra-source-files: +- README.md +ghc-options: -Wall +dependencies: +- base >=4.7 && <5.0 +- transformers >=0.4.0.0 +- mtl >=2.2.1 +- unordered-containers +- containers >=0.5.0.0 && <0.6 +- aeson >=1.0 && <2.0 +- bytestring >=0.10.0 && <0.11 +- http-types >=0.8 && <0.10 +- http-client >=0.5 && <0.6 +- http-client-tls +- http-api-data >= 0.3.4 && <0.4 +- http-media >= 0.4 && < 0.8 +- text >=0.11 && <1.3 +- time >=1.5 && <1.9 +- vector >=0.10.9 && <0.13 +- case-insensitive +- swagger-petstore +- microlens +tests: + tests: + main: Test.hs + source-dirs: tests + ghc-options: + - -fno-warn-orphans + dependencies: + - swagger-petstore + - bytestring >=0.10.0 && <0.11 + - containers + - hspec >=1.8 + - HUnit > 1.5.0 + - text + - time + - iso8601-time + - aeson + - semigroups + - QuickCheck diff --git a/samples/client/petstore/haskell-http-client/tests-integration/pom.xml b/samples/client/petstore/haskell-http-client/tests-integration/pom.xml new file mode 100644 index 00000000000..41078a36d22 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests-integration/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + io.swagger + swagger-petstore-haskell-http-client-tests-integration + pom + 1.0-SNAPSHOT + Swagger Petstore - Haskell http-client Client - Integration Tests + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory} + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + stack-test + integration-test + + exec + + + + http://0.0.0.0/v2 + + stack + + test + + + + + + + + diff --git a/samples/client/petstore/haskell-http-client/tests-integration/stack.yaml b/samples/client/petstore/haskell-http-client/tests-integration/stack.yaml new file mode 100644 index 00000000000..c8e4763e0bd --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests-integration/stack.yaml @@ -0,0 +1,5 @@ +resolver: lts-9.0 +packages: + - location: '.' + - location: '..' + extra-dep: true diff --git a/samples/client/petstore/haskell-http-client/tests-integration/swagger-petstore-tests-integration.cabal b/samples/client/petstore/haskell-http-client/tests-integration/swagger-petstore-tests-integration.cabal new file mode 100644 index 00000000000..5fb889006a5 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests-integration/swagger-petstore-tests-integration.cabal @@ -0,0 +1,57 @@ +-- This file has been generated from package.yaml by hpack version 0.17.1. +-- +-- see: https://github.com/sol/hpack + +name: swagger-petstore-tests-integration +version: 0.1.0.0 +synopsis: integration tests for auto-generated swagger-petstore API Client +description: integration tests for auto-generated swagger-petstore API Client +category: Web +homepage: https://github.com/swagger-api/swagger-codegen#readme +author: Author Name Here +maintainer: author.name@email.com +copyright: YEAR - AUTHOR +license: UnspecifiedLicense +build-type: Simple +cabal-version: >= 1.10 + +extra-source-files: + README.md + +test-suite tests + type: exitcode-stdio-1.0 + main-is: Test.hs + hs-source-dirs: + tests + ghc-options: -Wall -fno-warn-orphans + build-depends: + base >=4.7 && <5.0 + , transformers >=0.4.0.0 + , mtl >=2.2.1 + , unordered-containers + , containers >=0.5.0.0 && <0.6 + , aeson >=1.0 && <2.0 + , bytestring >=0.10.0 && <0.11 + , http-types >=0.8 && <0.10 + , http-client >=0.5 && <0.6 + , http-client-tls + , http-api-data >= 0.3.4 && <0.4 + , http-media >= 0.4 && < 0.8 + , text >=0.11 && <1.3 + , time >=1.5 && <1.9 + , vector >=0.10.9 && <0.13 + , case-insensitive + , swagger-petstore + , microlens + , swagger-petstore + , bytestring >=0.10.0 && <0.11 + , containers + , hspec >=1.8 + , HUnit > 1.5.0 + , text + , time + , iso8601-time + , aeson + , semigroups + , QuickCheck + default-language: Haskell2010 diff --git a/samples/client/petstore/haskell-http-client/tests-integration/tests/Test.hs b/samples/client/petstore/haskell-http-client/tests-integration/tests/Test.hs new file mode 100644 index 00000000000..85c530af3e1 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests-integration/tests/Test.hs @@ -0,0 +1,289 @@ +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE LambdaCase #-} +{-# OPTIONS_GHC -fno-warn-deprecations -fno-warn-unused-matches -fno-warn-unused-imports -fno-warn-unused-binds -fno-warn-orphans #-} + +import qualified Data.Aeson as A +import qualified Data.ByteString.Lazy.Char8 as BCL +import qualified Data.Text as T +import qualified Data.Time as TI +import qualified Lens.Micro as L +import qualified Network.HTTP.Client as NH +import qualified Network.HTTP.Types.Status as NH + +import Data.Typeable (Proxy(..)) +import Test.Hspec +import Test.Hspec.QuickCheck +import Test.HUnit +import Test.HUnit.Lang + +import Control.Monad.IO.Class +import Data.IORef +import qualified Data.Map.Strict as Map +import Data.Map.Strict (Map) +import System.Environment (getEnvironment) + +import qualified SwaggerPetstore as S + +import Data.Monoid ((<>)) + +-- * UTILS + +assertSuccess :: Expectation +assertSuccess = Success `shouldBe` Success + +-- * INSTANCES + +instance S.Consumes S.PlaceOrder S.MimeJSON +instance S.Consumes S.CreateUser S.MimeJSON +instance S.Consumes S.UpdateUser S.MimeJSON +instance S.Consumes S.CreateUsersWithArrayInput S.MimeJSON +instance S.Consumes S.CreateUsersWithListInput S.MimeJSON +instance S.Produces S.CreateUsersWithArrayInput S.MimeNoContent +instance S.Produces S.CreateUsersWithListInput S.MimeNoContent + +-- * MAIN + +main :: IO () +main = do + + env <- getEnvironment + + let host = case lookup "HOST" env of + Just h -> BCL.pack h + _ -> "http://0.0.0.0/v2" + + let config = + S.withStdoutLogging + S.newConfig { S.configHost = host } + -- , S.configLoggingFilter = S.debugLevelFilter } + + putStrLn "\n******** CONFIG ********" + putStrLn (show config) + + mgr <- NH.newManager NH.defaultManagerSettings + + hspec $ do + testPetOps mgr config + testStoreOps mgr config + testUserOps mgr config + +-- * PET TESTS + +testPetOps :: NH.Manager -> S.SwaggerPetstoreConfig -> Spec +testPetOps mgr config = + + describe "** pet operations" $ do + + _pet <- runIO $ newIORef (Nothing :: Maybe S.Pet) + + it "addPet" $ do + let addPetRequest = + S.addPet S.MimeJSON (S.mkPet "name" ["url1", "url2"]) + addPetResponse <- S.dispatchLbs mgr config addPetRequest S.MimeJSON + NH.responseStatus addPetResponse `shouldBe` NH.status200 + case A.eitherDecode (NH.responseBody addPetResponse) of + Right pet -> do + _pet `writeIORef` Just pet + assertSuccess + Left e -> assertFailure e + + around (\go -> + readIORef _pet >>= \case + Just pet@S.Pet {S.petId = Just petId} -> go (petId, pet) + _ -> pendingWith "no petId") $ + it "getPetById" $ \(petId, pet) -> do + let getPetByIdRequest = S.getPetById petId + getPetByIdRequestResult <- S.dispatchMime mgr config getPetByIdRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse getPetByIdRequestResult) `shouldBe` NH.status200 + case S.mimeResult getPetByIdRequestResult of + Right p -> p `shouldBe` pet + Left (S.MimeError e _) -> assertFailure e + + it "findPetsByStatus" $ do + let findPetsByStatusRequest = S.findPetsByStatus ["available","pending","sold"] + findPetsByStatusResult <- S.dispatchMime mgr config findPetsByStatusRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse findPetsByStatusResult) `shouldBe` NH.status200 + case S.mimeResult findPetsByStatusResult of + Right r -> length r `shouldSatisfy` (> 0) + Left (S.MimeError e _) -> assertFailure e + + it "findPetsByTags" $ do + let findPetsByTagsRequest = S.findPetsByTags ["name","tag1"] + findPetsByTagsResult <- S.dispatchMime mgr config findPetsByTagsRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse findPetsByTagsResult) `shouldBe` NH.status200 + case S.mimeResult findPetsByTagsResult of + Right r -> length r `shouldSatisfy` (> 0) + Left (S.MimeError e _) -> assertFailure e + + around (\go -> + readIORef _pet >>= \case + Just pet -> go pet + _ -> pendingWith "no pet") $ + it "updatePet" $ \pet -> do + let updatePetRequest = S.updatePet S.MimeJSON $ pet + { S.petStatus = Just "available" + , S.petCategory = Just (S.Category (Just 3) (Just "catname")) + } + updatePetResponse <- S.dispatchLbs mgr config updatePetRequest S.MimeXML + NH.responseStatus updatePetResponse `shouldBe` NH.status200 + + it "updatePetWithFormRequest" $ do + readIORef _pet >>= \case + Just S.Pet {S.petId = Just petId} -> do + let updatePetWithFormRequest = S.updatePetWithForm S.MimeFormUrlEncoded petId + `S.applyOptionalParam` S.Name "petName" + `S.applyOptionalParam` S.Status "pending" + updatePetWithFormResponse <- S.dispatchLbs mgr config updatePetWithFormRequest S.MimeJSON + NH.responseStatus updatePetWithFormResponse `shouldBe` NH.status200 + _ -> pendingWith "no pet" + + around (\go -> + readIORef _pet >>= \case + Just pet@S.Pet {S.petId = Just petId} -> go petId + _ -> pendingWith "no petId") $ + it "uploadFile" $ \petId -> do + let uploadFileRequest = S.uploadFile S.MimeMultipartFormData petId + `S.applyOptionalParam` S.File "package.yaml" + `S.applyOptionalParam` S.AdditionalMetadata "a package.yaml file" + uploadFileRequestResult <- S.dispatchMime mgr config uploadFileRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse uploadFileRequestResult) `shouldBe` NH.status200 + case S.mimeResult uploadFileRequestResult of + Right _ -> assertSuccess + Left (S.MimeError e _) -> assertFailure e + + around (\go -> + readIORef _pet >>= \case + Just pet@S.Pet {S.petId = Just petId} -> go petId + _ -> pendingWith "no petId") $ + it "deletePet" $ \petId -> do + let deletePetRequest = S.deletePet petId + `S.applyOptionalParam` S.ApiUnderscorekey "api key" + deletePetResponse <- S.dispatchLbs mgr config deletePetRequest S.MimeJSON + NH.responseStatus deletePetResponse `shouldBe` NH.status200 + +-- * STORE TESTS + + +testStoreOps :: NH.Manager -> S.SwaggerPetstoreConfig -> Spec +testStoreOps mgr config = do + + describe "** store operations" $ do + + _order <- runIO $ newIORef (Nothing :: Maybe S.Order) + + it "getInventory" $ do + let getInventoryRequest = S.getInventory + `S.setHeader` [("api_key","special-key")] + getInventoryRequestRequestResult <- S.dispatchMime mgr config getInventoryRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse getInventoryRequestRequestResult) `shouldBe` NH.status200 + case S.mimeResult getInventoryRequestRequestResult of + Right r -> length r `shouldSatisfy` (> 0) + Left (S.MimeError e _) -> assertFailure e + + it "placeOrder" $ do + now <- TI.getCurrentTime + let placeOrderRequest = S.placeOrder S.MimeJSON + (S.mkOrder + { S.orderId = Just 21 + , S.orderQuantity = Just 210 + , S.orderShipDate = Just now + }) + placeOrderResult <- S.dispatchMime mgr config placeOrderRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse placeOrderResult) `shouldBe` NH.status200 + case S.mimeResult placeOrderResult of + Right order -> do + _order `writeIORef` Just order + assertSuccess + Left (S.MimeError e _) -> assertFailure e + + around (\go -> + readIORef _order >>= \case + Just order@S.Order {S.orderId = Just orderId} -> go (orderId, order) + _ -> pendingWith "no orderId") $ + it "getOrderById" $ \(orderId, order) -> do + let getOrderByIdRequest = S.getOrderById orderId + getOrderByIdRequestResult <- S.dispatchMime mgr config getOrderByIdRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse getOrderByIdRequestResult) `shouldBe` NH.status200 + case S.mimeResult getOrderByIdRequestResult of + Right o -> o `shouldBe` order + Left (S.MimeError e _) -> assertFailure e + + around (\go -> + readIORef _order >>= \case + Just S.Order {S.orderId = Just orderId} -> go (T.pack (show orderId)) + _ -> pendingWith "no orderId") $ + it "deleteOrder" $ \orderId -> do + let deleteOrderRequest = S.deleteOrder orderId + deleteOrderResult <- S.dispatchLbs mgr config deleteOrderRequest S.MimeJSON + NH.responseStatus deleteOrderResult `shouldBe` NH.status200 + + +-- * USER TESTS + +testUserOps :: NH.Manager -> S.SwaggerPetstoreConfig -> Spec +testUserOps mgr config = do + + describe "** user operations" $ do + + let _username = "hsusername" + _password = "password1" + _user = + S.mkUser + { S.userId = Just 21 + , S.userUsername = Just _username + , S.userEmail = Just "xyz@example.com" + , S.userUserStatus = Just 0 + } + _users = + take 8 $ + drop 1 $ iterate (L.over S.userUsernameT (<> "*") . L.over S.userIdT (+ 1)) _user + + before (pure _user) $ + it "createUser" $ \user -> do + let createUserRequest = S.createUser S.MimeJSON user + createUserResult <- S.dispatchLbs mgr config createUserRequest S.MimeJSON + NH.responseStatus createUserResult `shouldBe` NH.status200 + + before (pure _users) $ + it "createUsersWithArrayInput" $ \users -> do + let createUsersWithArrayInputRequest = S.createUsersWithArrayInput S.MimeJSON users + createUsersWithArrayInputResult <- S.dispatchLbs mgr config createUsersWithArrayInputRequest S.MimeNoContent + NH.responseStatus createUsersWithArrayInputResult `shouldBe` NH.status200 + + before (pure _users) $ + it "createUsersWithListInput" $ \users -> do + let createUsersWithListInputRequest = S.createUsersWithListInput S.MimeJSON users + createUsersWithListInputResult <- S.dispatchLbs mgr config createUsersWithListInputRequest S.MimeNoContent + NH.responseStatus createUsersWithListInputResult `shouldBe` NH.status200 + + before (pure (_username, _user)) $ + it "getUserByName" $ \(username, user) -> do + let getUserByNameRequest = S.getUserByName username + getUserByNameResult <- S.dispatchMime mgr config getUserByNameRequest S.MimeJSON + NH.responseStatus (S.mimeResultResponse getUserByNameResult) `shouldBe` NH.status200 + case S.mimeResult getUserByNameResult of + Right u -> u `shouldBe` user + Left (S.MimeError e _) -> assertFailure e + + before (pure (_username, _password)) $ + it "loginUser" $ \(username, password) -> do + let loginUserRequest = S.loginUser username password + loginUserResult <- S.dispatchLbs mgr config loginUserRequest S.MimeJSON + NH.responseStatus loginUserResult `shouldBe` NH.status200 + + before (pure (_username, _user)) $ + it "updateUser" $ \(username, user) -> do + let updateUserRequest = S.updateUser S.MimeJSON username user + updateUserResult <- S.dispatchLbs mgr config updateUserRequest S.MimeJSON + NH.responseStatus updateUserResult `shouldBe` NH.status200 + + it "logoutuser" $ do + logoutUserResult <- S.dispatchLbs mgr config S.logoutUser S.MimeJSON + NH.responseStatus logoutUserResult `shouldBe` NH.status200 + + before (pure _username) $ + it "deleteUser" $ \username -> do + let deleteUserRequest = S.deleteUser username + deleteUserResult <- S.dispatchLbs mgr config deleteUserRequest S.MimeJSON + NH.responseStatus deleteUserResult `shouldBe` NH.status200 diff --git a/samples/client/petstore/haskell-http-client/tests/ApproxEq.hs b/samples/client/petstore/haskell-http-client/tests/ApproxEq.hs new file mode 100644 index 00000000000..88ca2110a06 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests/ApproxEq.hs @@ -0,0 +1,81 @@ +{-# LANGUAGE DefaultSignatures #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeOperators #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} + +module ApproxEq where + +import Data.Text (Text) +import Data.Time.Clock +import Test.QuickCheck +import GHC.Generics as G + +(==~) + :: (ApproxEq a, Show a) + => a -> a -> Property +a ==~ b = counterexample (show a ++ " !=~ " ++ show b) (a =~ b) + +class GApproxEq f where + gApproxEq :: f a -> f a -> Bool + +instance GApproxEq U1 where + gApproxEq U1 U1 = True + +instance (GApproxEq a, GApproxEq b) => + GApproxEq (a :+: b) where + gApproxEq (L1 a) (L1 b) = gApproxEq a b + gApproxEq (R1 a) (R1 b) = gApproxEq a b + gApproxEq _ _ = False + +instance (GApproxEq a, GApproxEq b) => + GApproxEq (a :*: b) where + gApproxEq (a1 :*: b1) (a2 :*: b2) = gApproxEq a1 a2 && gApproxEq b1 b2 + +instance (ApproxEq a) => + GApproxEq (K1 i a) where + gApproxEq (K1 a) (K1 b) = a =~ b + +instance (GApproxEq f) => + GApproxEq (M1 i t f) where + gApproxEq (M1 a) (M1 b) = gApproxEq a b + +class ApproxEq a where + (=~) :: a -> a -> Bool + default (=~) :: (Generic a, GApproxEq (Rep a)) => a -> a -> Bool + a =~ b = gApproxEq (G.from a) (G.from b) + +instance ApproxEq Text where + (=~) = (==) + +instance ApproxEq Char where + (=~) = (==) + +instance ApproxEq Bool where + (=~) = (==) + +instance ApproxEq Int where + (=~) = (==) + +instance ApproxEq Double where + (=~) = (==) + +instance ApproxEq a => + ApproxEq (Maybe a) + +instance ApproxEq UTCTime where + (=~) = (==) + +instance ApproxEq a => + ApproxEq [a] where + as =~ bs = and (zipWith (=~) as bs) + +instance (ApproxEq l, ApproxEq r) => + ApproxEq (Either l r) where + Left a =~ Left b = a =~ b + Right a =~ Right b = a =~ b + _ =~ _ = False + +instance (ApproxEq l, ApproxEq r) => + ApproxEq (l, r) where + (=~) (l1, r1) (l2, r2) = l1 =~ l2 && r1 =~ r2 diff --git a/samples/client/petstore/haskell-http-client/tests/Instances.hs b/samples/client/petstore/haskell-http-client/tests/Instances.hs new file mode 100644 index 00000000000..6f995219f7c --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests/Instances.hs @@ -0,0 +1,100 @@ +module Instances where + +import Data.Text (Text, pack) +import Data.Char (isSpace) +import Data.List (sort) +import Data.Time.Calendar (Day(..)) +import Data.Time.Clock (UTCTime(..), secondsToDiffTime) +import Test.QuickCheck +import qualified Data.HashMap.Strict as HM +import qualified Data.Set as Set + +import ApproxEq +import SwaggerPetstore.Model + +instance Arbitrary Text where + arbitrary = pack <$> arbitrary + +instance Arbitrary Day where + arbitrary = ModifiedJulianDay . (2000 +) <$> arbitrary + shrink = (ModifiedJulianDay <$>) . shrink . toModifiedJulianDay + +instance Arbitrary UTCTime where + arbitrary = + UTCTime <$> arbitrary <*> (secondsToDiffTime <$> choose (0, 86401)) + +-- | Checks if a given list has no duplicates in _O(n log n)_. +hasNoDups + :: (Ord a) + => [a] -> Bool +hasNoDups = go Set.empty + where + go _ [] = True + go s (x:xs) + | s' <- Set.insert x s + , Set.size s' > Set.size s = go s' xs + | otherwise = False + +instance ApproxEq Day where + (=~) = (==) + +-- * Models + +instance Arbitrary ApiResponse where + arbitrary = + ApiResponse + <$> arbitrary -- apiResponseCode :: Maybe Int + <*> arbitrary -- apiResponseType :: Maybe Text + <*> arbitrary -- apiResponseMessage :: Maybe Text + + +instance Arbitrary Category where + arbitrary = + Category + <$> arbitrary -- categoryId :: Maybe Integer + <*> arbitrary -- categoryName :: Maybe Text + + +instance Arbitrary Order where + arbitrary = + Order + <$> arbitrary -- orderId :: Maybe Integer + <*> arbitrary -- orderPetId :: Maybe Integer + <*> arbitrary -- orderQuantity :: Maybe Int + <*> arbitrary -- orderShipDate :: Maybe UTCTime + <*> arbitrary -- orderStatus :: Maybe Text + <*> arbitrary -- orderComplete :: Maybe Bool + + +instance Arbitrary Pet where + arbitrary = + Pet + <$> arbitrary -- petId :: Maybe Integer + <*> arbitrary -- petCategory :: Maybe Category + <*> arbitrary -- petName :: Text + <*> arbitrary -- petPhotoUrls :: [Text] + <*> arbitrary -- petTags :: Maybe [Tag] + <*> arbitrary -- petStatus :: Maybe Text + + +instance Arbitrary Tag where + arbitrary = + Tag + <$> arbitrary -- tagId :: Maybe Integer + <*> arbitrary -- tagName :: Maybe Text + + +instance Arbitrary User where + arbitrary = + User + <$> arbitrary -- userId :: Maybe Integer + <*> arbitrary -- userUsername :: Maybe Text + <*> arbitrary -- userFirstName :: Maybe Text + <*> arbitrary -- userLastName :: Maybe Text + <*> arbitrary -- userEmail :: Maybe Text + <*> arbitrary -- userPassword :: Maybe Text + <*> arbitrary -- userPhone :: Maybe Text + <*> arbitrary -- userUserStatus :: Maybe Int + + + diff --git a/samples/client/petstore/haskell-http-client/tests/PropMime.hs b/samples/client/petstore/haskell-http-client/tests/PropMime.hs new file mode 100644 index 00000000000..c7f66604461 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests/PropMime.hs @@ -0,0 +1,50 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ConstraintKinds #-} + +module PropMime where + +import Data.Aeson +import Data.Aeson.Types (parseEither) +import Data.Monoid ((<>)) +import Data.Typeable (Proxy(..), typeOf, Typeable) +import qualified Data.ByteString.Lazy.Char8 as BL8 +import Test.Hspec +import Test.QuickCheck +import Test.QuickCheck.Property +import Test.Hspec.QuickCheck (prop) + +import SwaggerPetstore.MimeTypes + +import ApproxEq + +-- * Type Aliases + +type ArbitraryMime mime a = ArbitraryRoundtrip (MimeUnrender mime) (MimeRender mime) a + +type ArbitraryRoundtrip from to a = (from a, to a, Arbitrary' a) + +type Arbitrary' a = (Arbitrary a, Show a, Typeable a) + +-- * Mime + +propMime + :: forall a b mime. + (ArbitraryMime mime a, Testable b) + => String -> (a -> a -> b) -> mime -> Proxy a -> Spec +propMime eqDescr eq m _ = + prop + (show (typeOf (undefined :: a)) <> " " <> show (typeOf (undefined :: mime)) <> " roundtrip " <> eqDescr) $ + \(x :: a) -> + let rendered = mimeRender' m x + actual = mimeUnrender' m rendered + expected = Right x + failMsg = + "ACTUAL: " <> show actual <> "\nRENDERED: " <> BL8.unpack rendered + in counterexample failMsg $ + either reject property (eq <$> actual <*> expected) + where + reject = property . const rejected + +propMimeEq :: (ArbitraryMime mime a, Eq a) => mime -> Proxy a -> Spec +propMimeEq = propMime "(EQ)" (==) diff --git a/samples/client/petstore/haskell-http-client/tests/Test.hs b/samples/client/petstore/haskell-http-client/tests/Test.hs new file mode 100644 index 00000000000..81253e34028 --- /dev/null +++ b/samples/client/petstore/haskell-http-client/tests/Test.hs @@ -0,0 +1,28 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE PartialTypeSignatures #-} + +module Main where + +import Data.Typeable (Proxy(..)) +import Test.Hspec +import Test.Hspec.QuickCheck + +import PropMime +import Instances () + +import SwaggerPetstore.Model +import SwaggerPetstore.MimeTypes + +main :: IO () +main = + hspec $ modifyMaxSize (const 10) $ + do describe "JSON instances" $ + do propMimeEq MimeJSON (Proxy :: Proxy ApiResponse) + propMimeEq MimeJSON (Proxy :: Proxy Category) + propMimeEq MimeJSON (Proxy :: Proxy Order) + propMimeEq MimeJSON (Proxy :: Proxy Pet) + propMimeEq MimeJSON (Proxy :: Proxy Tag) + propMimeEq MimeJSON (Proxy :: Proxy User) +