diff --git a/bin/scalaz-petstore.sh b/bin/scalaz-petstore.sh new file mode 100755 index 00000000000..266e8cbf9e7 --- /dev/null +++ b/bin/scalaz-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/scalaz -i modules/swagger-codegen/src/test/resources/2_0/petstore.yaml -l scalaz -o samples/client/petstore/scalaz" + +java $JAVA_OPTS -jar $executable $ags diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalazClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalazClientCodegen.java new file mode 100644 index 00000000000..30f984464c1 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalazClientCodegen.java @@ -0,0 +1,250 @@ +package io.swagger.codegen.languages; + +import com.google.common.base.CaseFormat; +import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Template; + +import io.swagger.codegen.*; + +import io.swagger.models.auth.SecuritySchemeDefinition; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.BooleanProperty; +import io.swagger.models.properties.DateProperty; +import io.swagger.models.properties.DateTimeProperty; +import io.swagger.models.properties.DoubleProperty; +import io.swagger.models.properties.FloatProperty; +import io.swagger.models.properties.IntegerProperty; +import io.swagger.models.properties.LongProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.properties.StringProperty; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.*; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ScalazClientCodegen extends AbstractScalaCodegen implements CodegenConfig { + + public ScalazClientCodegen() { + super(); + outputFolder = "generated-code/scalaz"; + embeddedTemplateDir = templateDir = "scalaz"; + apiPackage = "io.swagger.client.api"; + modelPackage = "io.swagger.client.api"; + + modelTemplateFiles.put("model.mustache", ".scala"); + apiTemplateFiles.put("api.mustache", ".scala"); + + setReservedWordsLowerCase( + Arrays.asList( + // local variable names used in API methods (endpoints) + "path", "contentTypes", "contentType", "queryParams", "headerParams", + "formParams", "postBody", "mp", "basePath", "apiInvoker", + + // scala reserved words + "abstract", "case", "catch", "class", "def", "do", "else", "extends", + "false", "final", "finally", "for", "forSome", "if", "implicit", + "import", "lazy", "match", "new", "null", "object", "override", "package", + "private", "protected", "return", "sealed", "super", "this", "throw", + "trait", "try", "true", "type", "val", "var", "while", "with", "yield") + ); + + additionalProperties.put("apiPackage", apiPackage); + + supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt")); + supportingFiles.add(new SupportingFile("dateTimeCodecs.mustache", (sourceFolder + File.separator + apiPackage).replace(".", File.separator), "DateTimeCodecs.scala")); + supportingFiles.add(new SupportingFile("HelperCodecs.mustache", (sourceFolder + File.separator + apiPackage).replace(".", File.separator), "HelperCodecs.scala")); + supportingFiles.add(new SupportingFile("QueryParamTypeclass.mustache", (sourceFolder + File.separator + apiPackage).replace(".", File.separator), "QueryParamTypeclass.scala")); + + importMapping.remove("List"); + importMapping.remove("Set"); + importMapping.remove("Map"); + + importMapping.put("Date", "java.util.Date"); + importMapping.put("ListBuffer", "scala.collection.mutable.ListBuffer"); + + typeMapping = new HashMap(); + typeMapping.put("enum", "NSString"); + typeMapping.put("array", "List"); + typeMapping.put("set", "Set"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("int", "Int"); + typeMapping.put("long", "Long"); + typeMapping.put("float", "Float"); + typeMapping.put("byte", "Byte"); + typeMapping.put("short", "Short"); + typeMapping.put("char", "Char"); + typeMapping.put("double", "Double"); + typeMapping.put("object", "Any"); + typeMapping.put("file", "File"); + typeMapping.put("number", "BigDecimal"); + typeMapping.put("date-time", "DateTime"); + typeMapping.put("date", "DateTime"); + + + //instantiationTypes.put("array", "ListBuffer"); + instantiationTypes.put("array", "ListBuffer"); + instantiationTypes.put("map", "HashMap"); + + additionalProperties.put("fnEnumEntry", new EnumEntryLambda()); + + cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); + } + + @Override + public void processOpts() { + super.processOpts(); + if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) { + setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING)); + } + } + + public void setModelPropertyNaming(String naming) { + if ("original".equals(naming) || "camelCase".equals(naming) || + "PascalCase".equals(naming) || "snake_case".equals(naming)) { + this.modelPropertyNaming = naming; + } else { + throw new IllegalArgumentException("Invalid model property naming '" + + naming + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + } + + public String getModelPropertyNaming() { + return this.modelPropertyNaming; + } + @Override + public String toVarName(String name) { + // sanitize name + name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + if("_".equals(name)) { + name = "_u"; + } + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } + + name = getNameUsingModelPropertyNaming(name); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } + + return name; + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toEnumName(CodegenProperty property) { + return formatIdentifier(property.baseName, true); + } + + public String getNameUsingModelPropertyNaming(String name) { + switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) { + case original: return name; + case camelCase: return camelize(name, true); + case PascalCase: return camelize(name); + case snake_case: return underscore(name); + default: throw new IllegalArgumentException("Invalid model property naming '" + + name + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + + } + + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public String getName() { + return "scalaz"; + } + + @Override + public String getHelp() { + return "Generates a Scalaz client library that uses http4s"; + } + + @Override + public String toOperationId(String operationId) { + // throw exception if method name is empty + if (StringUtils.isEmpty(operationId)) { + throw new RuntimeException("Empty method name (operationId) not allowed"); + } + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + throw new RuntimeException(operationId + " (reserved word) cannot be used as method name"); + } + + return camelize(operationId, true); + } + + @Override + public String toModelName(final String name) { + final String sanitizedName = sanitizeName(modelNamePrefix + this.stripPackageName(name) + modelNameSuffix); + + // camelize the model name + // phone_number => PhoneNumber + final String camelizedName = camelize(sanitizedName); + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(camelizedName)) { + final String modelName = "Model" + camelizedName; + LOGGER.warn(camelizedName + " (reserved word) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + // model name starts with number + if (name.matches("^\\d.*")) { + final String modelName = "Model" + camelizedName; // e.g. 200Response => Model200Response (after camelize) + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + return camelizedName; + } + + private static abstract class CustomLambda implements Mustache.Lambda { + @Override + public void execute(Template.Fragment frag, Writer out) throws IOException { + final StringWriter tempWriter = new StringWriter(); + frag.execute(tempWriter); + out.write(formatFragment(tempWriter.toString())); + } + + public abstract String formatFragment(String fragment); + } + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + private class EnumEntryLambda extends CustomLambda { + @Override + public String formatFragment(String fragment) { + return formatIdentifier(fragment, true); + } + } +} 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 c8438e09a30..0ca26403132 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 @@ -58,6 +58,7 @@ io.swagger.codegen.languages.RubyClientCodegen io.swagger.codegen.languages.RustClientCodegen io.swagger.codegen.languages.ScalaClientCodegen io.swagger.codegen.languages.ScalatraServerCodegen +io.swagger.codegen.languages.ScalazClientCodegen io.swagger.codegen.languages.SilexServerCodegen io.swagger.codegen.languages.SinatraServerCodegen io.swagger.codegen.languages.SlimFrameworkServerCodegen diff --git a/modules/swagger-codegen/src/main/resources/scalaz/HelperCodecs.mustache b/modules/swagger-codegen/src/main/resources/scalaz/HelperCodecs.mustache new file mode 100644 index 00000000000..9bb400b9bda --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/HelperCodecs.mustache @@ -0,0 +1,15 @@ +package {{apiPackage}} + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ + +import org.joda.time.DateTime + +object HelperCodecs { + implicit def returnTypeDecoder[A: EncodeJson]: EntityEncoder[List[A]] = jsonEncoderOf[List[A]] +} diff --git a/modules/swagger-codegen/src/main/resources/scalaz/QueryParamTypeclass.mustache b/modules/swagger-codegen/src/main/resources/scalaz/QueryParamTypeclass.mustache new file mode 100644 index 00000000000..6ce8ee71291 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/QueryParamTypeclass.mustache @@ -0,0 +1,15 @@ +package {{apiPackage}} + +trait QueryParam[A] { + def toParamString(a: A): String +} + +object QueryParam { + implicit def strQueryParam: QueryParam[String] = new QueryParam[String] { + def toParamString(s: String): String = s + } + + implicit def listStrQueryParam: QueryParam[List[String]] = new QueryParam[List[String]] { + def toParamString(s: List[String]): String = s.mkString(",") + } +} diff --git a/modules/swagger-codegen/src/main/resources/scalaz/api.mustache b/modules/swagger-codegen/src/main/resources/scalaz/api.mustache new file mode 100644 index 00000000000..9eeba0a96ee --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/api.mustache @@ -0,0 +1,83 @@ +package {{package}} + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import java.io.File +import java.net.URLEncoder +import java.util.UUID + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.http4s.client._ +import org.http4s.client.blaze.PooledHttp1Client +import org.http4s.headers._ + +import org.joda.time.DateTime + +import scalaz.concurrent.Task + +import HelperCodecs._ + +{{#operations}} +object {{classname}} { + + val client = PooledHttp1Client() + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + {{#operation}} + def {{nickname}}(host: String{{#allParams}}{{#-first}}, {{/-first}}{{paramName}}: {{dataType}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#queryParams}}{{#-first}}(implicit {{/-first}}{{paramName}}Query: QueryParam[{{dataType}}]{{^-last}}, {{/-last}}{{#-last}}){{/-last}}{{/queryParams}}: {{>operationReturnType}}{{#returnType}} implicit val returnTypeDecoder: EntityDecoder[{{returnType}}] = jsonOf[{{returnType}}] + +{{/returnType}} + val path = "{{path}}"{{#pathParams}}.replaceAll("\\{" + "{{baseName}}" + "\\}",escape({{paramName}}.toString)){{/pathParams}} + + val httpMethod = Method.{{httpMethod}} + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + {{#headerParams}}Header("{{baseName}}", {{paramName}}){{^-last}}, {{/-last}}{{/headerParams}}) + val queryParams = Query( + {{#queryParams}}("{{paramName}}", Some({{baseName}}Query.toParamString({{baseName}}))){{^-last}}, {{/-last}}{{/queryParams}}) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)){{#bodyParam}}.withBody({{paramName}}){{/bodyParam}} + {{>clientFunction}} + } yield resp + } + + {{/operation}} +} + +class HttpService{{classname}}(service: HttpService) { + val client = Client.fromHttpService(service) + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + {{#operation}} + def {{nickname}}({{#allParams}}{{paramName}}: {{dataType}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#queryParams}}{{#-first}}(implicit {{/-first}}{{paramName}}Query: QueryParam[{{dataType}}]{{^-last}}, {{/-last}}{{#-last}}){{/-last}}{{/queryParams}}: {{>operationReturnType}}{{#returnType}} implicit val returnTypeDecoder: EntityDecoder[{{returnType}}] = jsonOf[{{returnType}}] + +{{/returnType}} + val path = "{{path}}"{{#pathParams}}.replaceAll("\\{" + "{{baseName}}" + "\\}",escape({{paramName}}.toString)){{/pathParams}} + + val httpMethod = Method.{{httpMethod}} + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + {{#headerParams}}Header("{{baseName}}", {{paramName}}){{^-last}}, {{/-last}}{{/headerParams}}) + val queryParams = Query( + {{#queryParams}}("{{paramName}}", Some({{baseName}}Query.toParamString({{baseName}}))){{^-last}}, {{/-last}}{{/queryParams}}) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)){{#bodyParam}}.withBody({{paramName}}){{/bodyParam}} + {{>clientFunction}} + } yield resp + } + + {{/operation}} +} +{{/operations}} diff --git a/modules/swagger-codegen/src/main/resources/scalaz/build.sbt.mustache b/modules/swagger-codegen/src/main/resources/scalaz/build.sbt.mustache new file mode 100644 index 00000000000..0153bb64d34 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/build.sbt.mustache @@ -0,0 +1,19 @@ +scalaVersion := "2.11.8" + +val http4sVersion = "0.15.12a" +val scalazVersion = "7.2.12" +val shapelessVersion = "2.3.2" +val argonautShapelessVersion = "1.2.0-M4" + +libraryDependencies ++= Seq( + "joda-time" % "joda-time" % "2.2", + "com.chuusai" %% "shapeless" % shapelessVersion, + "org.http4s" %% "http4s-argonaut" % http4sVersion, + "org.http4s" %% "http4s-dsl" % http4sVersion, + "org.http4s" %% "http4s-server-metrics" % http4sVersion, + "org.http4s" %% "http4s-blaze-client" % http4sVersion, + "org.scalaz" %% "scalaz-concurrent" % scalazVersion, + "org.scalaz" %% "scalaz-core" % scalazVersion, + "io.argonaut" %% "argonaut-scalaz" % "6.2", + "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % argonautShapelessVersion +) diff --git a/modules/swagger-codegen/src/main/resources/scalaz/clientFunction.mustache b/modules/swagger-codegen/src/main/resources/scalaz/clientFunction.mustache new file mode 100644 index 00000000000..bd7c75b38d9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/clientFunction.mustache @@ -0,0 +1 @@ +{{#returnType}}resp <- client.expect[{{returnType}}](req){{/returnType}}{{^returnType}}resp <- client.fetch[Unit](req)(_ => Task.now(())){{/returnType}} diff --git a/modules/swagger-codegen/src/main/resources/scalaz/dateTimeCodecs.mustache b/modules/swagger-codegen/src/main/resources/scalaz/dateTimeCodecs.mustache new file mode 100644 index 00000000000..fa73adb562e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/dateTimeCodecs.mustache @@ -0,0 +1,19 @@ +package {{apiPackage}} + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ + +import org.joda.time.DateTime + +object DateTimeCodecs { + implicit def dateTimeEncodeJson: EncodeJson[DateTime] = + EncodeJson[DateTime](dt => StringEncodeJson(dt.toString)) + + implicit def dateTimeDecodeJson: DecodeJson[DateTime] = + DecodeJson.of[String].map(DateTime.parse(_)) setName "org.joda.time.DateTime" +} diff --git a/modules/swagger-codegen/src/main/resources/scalaz/model.mustache b/modules/swagger-codegen/src/main/resources/scalaz/model.mustache new file mode 100644 index 00000000000..e0725cb819d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/model.mustache @@ -0,0 +1,56 @@ +package {{package}} + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.joda.time.DateTime +{{#models}} +{{#model}} +import {{classname}}._ + +case class {{classname}} ( + {{#vars}}{{#description}}/* {{{description}}} */ + {{/description}}{{name}}: {{^required}}Option[{{/required}}{{^isEnum}}{{datatype}}{{/isEnum}}{{#isEnum}}{{datatypeWithEnum}}{{/isEnum}}{{^required}}]{{/required}}{{#hasMore}},{{/hasMore}}{{^hasMore}}){{/hasMore}} + {{/vars}} + +object {{classname}} { + import DateTimeCodecs._ + {{#hasEnums}} + {{#vars}} + {{#isEnum}} + sealed trait {{datatypeWithEnum}} + {{#_enum}} + case object {{#fnEnumEntry}}{{.}}{{/fnEnumEntry}} extends {{datatypeWithEnum}} + {{/_enum}} + + object {{datatypeWithEnum}} { + def to{{datatypeWithEnum}}(s: String): Option[{{datatypeWithEnum}}] = s match { +{{#_enum}} case "{{#fnEnumEntry}}{{.}}{{/fnEnumEntry}}" => Some({{#fnEnumEntry}}{{.}}{{/fnEnumEntry}}) +{{/_enum}} + case _ => None + } + + def from{{datatypeWithEnum}}(x: {{datatypeWithEnum}}): String = x match { +{{#_enum}} case {{#fnEnumEntry}}{{.}}{{/fnEnumEntry}} => "{{#fnEnumEntry}}{{.}}{{/fnEnumEntry}}" +{{/_enum}} + } + } + + implicit val {{datatypeWithEnum}}EnumEncoder: EncodeJson[{{datatypeWithEnum}}] = + EncodeJson[{{datatypeWithEnum}}](is => StringEncodeJson({{datatypeWithEnum}}.from{{datatypeWithEnum}}(is))) + + implicit val {{datatypeWithEnum}}EnumDecoder: DecodeJson[{{datatypeWithEnum}}] = + DecodeJson.optionDecoder[{{datatypeWithEnum}}](n => n.string.flatMap(jStr => {{datatypeWithEnum}}.to{{datatypeWithEnum}}(jStr)), "{{datatypeWithEnum}} failed to de-serialize") + {{/isEnum}} + {{/vars}} + {{/hasEnums}} + + implicit val {{classname}}CodecJson: CodecJson[{{classname}}] = CodecJson.derive[{{classname}}] + implicit val {{classname}}Decoder: EntityDecoder[{{classname}}] = jsonOf[{{classname}}] + implicit val {{classname}}Encoder: EntityEncoder[{{classname}}] = jsonEncoderOf[{{classname}}] +} +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/scalaz/operationReturnType.mustache b/modules/swagger-codegen/src/main/resources/scalaz/operationReturnType.mustache new file mode 100644 index 00000000000..f224ea59ad0 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalaz/operationReturnType.mustache @@ -0,0 +1 @@ +Task[{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Unit{{/returnType}}] = { diff --git a/samples/client/petstore/scalaz/.swagger-codegen-ignore b/samples/client/petstore/scalaz/.swagger-codegen-ignore new file mode 100644 index 00000000000..c5fa491b4c5 --- /dev/null +++ b/samples/client/petstore/scalaz/.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/scalaz/.swagger-codegen/VERSION b/samples/client/petstore/scalaz/.swagger-codegen/VERSION new file mode 100644 index 00000000000..f9f7450d135 --- /dev/null +++ b/samples/client/petstore/scalaz/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.0-SNAPSHOT \ No newline at end of file diff --git a/samples/client/petstore/scalaz/build.sbt b/samples/client/petstore/scalaz/build.sbt new file mode 100644 index 00000000000..0153bb64d34 --- /dev/null +++ b/samples/client/petstore/scalaz/build.sbt @@ -0,0 +1,19 @@ +scalaVersion := "2.11.8" + +val http4sVersion = "0.15.12a" +val scalazVersion = "7.2.12" +val shapelessVersion = "2.3.2" +val argonautShapelessVersion = "1.2.0-M4" + +libraryDependencies ++= Seq( + "joda-time" % "joda-time" % "2.2", + "com.chuusai" %% "shapeless" % shapelessVersion, + "org.http4s" %% "http4s-argonaut" % http4sVersion, + "org.http4s" %% "http4s-dsl" % http4sVersion, + "org.http4s" %% "http4s-server-metrics" % http4sVersion, + "org.http4s" %% "http4s-blaze-client" % http4sVersion, + "org.scalaz" %% "scalaz-concurrent" % scalazVersion, + "org.scalaz" %% "scalaz-core" % scalazVersion, + "io.argonaut" %% "argonaut-scalaz" % "6.2", + "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % argonautShapelessVersion +) diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/ApiResponse.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/ApiResponse.scala new file mode 100644 index 00000000000..7d4bd29011b --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/ApiResponse.scala @@ -0,0 +1,23 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.joda.time.DateTime +import ApiResponse._ + +case class ApiResponse ( + code: Option[Integer], +_type: Option[String], +message: Option[String]) + +object ApiResponse { + import DateTimeCodecs._ + + implicit val ApiResponseCodecJson: CodecJson[ApiResponse] = CodecJson.derive[ApiResponse] + implicit val ApiResponseDecoder: EntityDecoder[ApiResponse] = jsonOf[ApiResponse] + implicit val ApiResponseEncoder: EntityEncoder[ApiResponse] = jsonEncoderOf[ApiResponse] +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Category.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Category.scala new file mode 100644 index 00000000000..972b0dd02cd --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Category.scala @@ -0,0 +1,22 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.joda.time.DateTime +import Category._ + +case class Category ( + id: Option[Long], +name: Option[String]) + +object Category { + import DateTimeCodecs._ + + implicit val CategoryCodecJson: CodecJson[Category] = CodecJson.derive[Category] + implicit val CategoryDecoder: EntityDecoder[Category] = jsonOf[Category] + implicit val CategoryEncoder: EntityEncoder[Category] = jsonEncoderOf[Category] +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/DateTimeCodecs.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/DateTimeCodecs.scala new file mode 100644 index 00000000000..bcf5f2f3eae --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/DateTimeCodecs.scala @@ -0,0 +1,19 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ + +import org.joda.time.DateTime + +object DateTimeCodecs { + implicit def dateTimeEncodeJson: EncodeJson[DateTime] = + EncodeJson[DateTime](dt => StringEncodeJson(dt.toString)) + + implicit def dateTimeDecodeJson: DecodeJson[DateTime] = + DecodeJson.of[String].map(DateTime.parse(_)) setName "org.joda.time.DateTime" +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/HelperCodecs.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/HelperCodecs.scala new file mode 100644 index 00000000000..4276fa1654d --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/HelperCodecs.scala @@ -0,0 +1,15 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ + +import org.joda.time.DateTime + +object HelperCodecs { + implicit def returnTypeDecoder[A: EncodeJson]: EntityEncoder[List[A]] = jsonEncoderOf[List[A]] +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Order.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Order.scala new file mode 100644 index 00000000000..653757a81f0 --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Order.scala @@ -0,0 +1,52 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.joda.time.DateTime +import Order._ + +case class Order ( + id: Option[Long], +petId: Option[Long], +quantity: Option[Integer], +shipDate: Option[DateTime], +/* Order Status */ + status: Option[Status], +complete: Option[Boolean]) + +object Order { + import DateTimeCodecs._ + sealed trait Status + case object Placed extends Status + case object Approved extends Status + case object Delivered extends Status + + object Status { + def toStatus(s: String): Option[Status] = s match { + case "Placed" => Some(Placed) + case "Approved" => Some(Approved) + case "Delivered" => Some(Delivered) + case _ => None + } + + def fromStatus(x: Status): String = x match { + case Placed => "Placed" + case Approved => "Approved" + case Delivered => "Delivered" + } + } + + implicit val StatusEnumEncoder: EncodeJson[Status] = + EncodeJson[Status](is => StringEncodeJson(Status.fromStatus(is))) + + implicit val StatusEnumDecoder: DecodeJson[Status] = + DecodeJson.optionDecoder[Status](n => n.string.flatMap(jStr => Status.toStatus(jStr)), "Status failed to de-serialize") + + implicit val OrderCodecJson: CodecJson[Order] = CodecJson.derive[Order] + implicit val OrderDecoder: EntityDecoder[Order] = jsonOf[Order] + implicit val OrderEncoder: EntityEncoder[Order] = jsonEncoderOf[Order] +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Pet.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Pet.scala new file mode 100644 index 00000000000..ec00c7662bc --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Pet.scala @@ -0,0 +1,52 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.joda.time.DateTime +import Pet._ + +case class Pet ( + id: Option[Long], +category: Option[Category], +name: String, +photoUrls: List[String], +tags: Option[List[Tag]], +/* pet status in the store */ + status: Option[Status]) + +object Pet { + import DateTimeCodecs._ + sealed trait Status + case object Available extends Status + case object Pending extends Status + case object Sold extends Status + + object Status { + def toStatus(s: String): Option[Status] = s match { + case "Available" => Some(Available) + case "Pending" => Some(Pending) + case "Sold" => Some(Sold) + case _ => None + } + + def fromStatus(x: Status): String = x match { + case Available => "Available" + case Pending => "Pending" + case Sold => "Sold" + } + } + + implicit val StatusEnumEncoder: EncodeJson[Status] = + EncodeJson[Status](is => StringEncodeJson(Status.fromStatus(is))) + + implicit val StatusEnumDecoder: DecodeJson[Status] = + DecodeJson.optionDecoder[Status](n => n.string.flatMap(jStr => Status.toStatus(jStr)), "Status failed to de-serialize") + + implicit val PetCodecJson: CodecJson[Pet] = CodecJson.derive[Pet] + implicit val PetDecoder: EntityDecoder[Pet] = jsonOf[Pet] + implicit val PetEncoder: EntityEncoder[Pet] = jsonEncoderOf[Pet] +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/PetApi.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/PetApi.scala new file mode 100644 index 00000000000..34508d07f84 --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/PetApi.scala @@ -0,0 +1,357 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import java.io.File +import java.net.URLEncoder +import java.util.UUID + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.http4s.client._ +import org.http4s.client.blaze.PooledHttp1Client +import org.http4s.headers._ + +import org.joda.time.DateTime + +import scalaz.concurrent.Task + +import HelperCodecs._ + +object PetApi { + + val client = PooledHttp1Client() + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + def addPet(host: String, body: Pet): Task[Unit] = { + val path = "/pet" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def deletePet(host: String, petId: Long, apiKey: String): Task[Unit] = { + val path = "/pet/{petId}".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.DELETE + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + Header("api_key", apiKey)) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def findPetsByStatus(host: String, status: List[String])(implicit statusQuery: QueryParam[List[String]]): Task[List[Pet]] = { + implicit val returnTypeDecoder: EntityDecoder[List[Pet]] = jsonOf[List[Pet]] + + val path = "/pet/findByStatus" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ("status", Some(statusQuery.toParamString(status)))) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[List[Pet]](req) + + } yield resp + } + + def findPetsByTags(host: String, tags: List[String])(implicit tagsQuery: QueryParam[List[String]]): Task[List[Pet]] = { + implicit val returnTypeDecoder: EntityDecoder[List[Pet]] = jsonOf[List[Pet]] + + val path = "/pet/findByTags" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ("tags", Some(tagsQuery.toParamString(tags)))) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[List[Pet]](req) + + } yield resp + } + + def getPetById(host: String, petId: Long): Task[Pet] = { + implicit val returnTypeDecoder: EntityDecoder[Pet] = jsonOf[Pet] + + val path = "/pet/{petId}".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[Pet](req) + + } yield resp + } + + def updatePet(host: String, body: Pet): Task[Unit] = { + val path = "/pet" + + val httpMethod = Method.PUT + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def updatePetWithForm(host: String, petId: Long, name: String, status: String): Task[Unit] = { + val path = "/pet/{petId}".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def uploadFile(host: String, petId: Long, additionalMetadata: String, file: File): Task[ApiResponse] = { + implicit val returnTypeDecoder: EntityDecoder[ApiResponse] = jsonOf[ApiResponse] + + val path = "/pet/{petId}/uploadImage".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[ApiResponse](req) + + } yield resp + } + +} + +class HttpServicePetApi(service: HttpService) { + val client = Client.fromHttpService(service) + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + def addPet(body: Pet): Task[Unit] = { + val path = "/pet" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def deletePet(petId: Long, apiKey: String): Task[Unit] = { + val path = "/pet/{petId}".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.DELETE + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + Header("api_key", apiKey)) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def findPetsByStatus(status: List[String])(implicit statusQuery: QueryParam[List[String]]): Task[List[Pet]] = { + implicit val returnTypeDecoder: EntityDecoder[List[Pet]] = jsonOf[List[Pet]] + + val path = "/pet/findByStatus" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ("status", Some(statusQuery.toParamString(status)))) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[List[Pet]](req) + + } yield resp + } + + def findPetsByTags(tags: List[String])(implicit tagsQuery: QueryParam[List[String]]): Task[List[Pet]] = { + implicit val returnTypeDecoder: EntityDecoder[List[Pet]] = jsonOf[List[Pet]] + + val path = "/pet/findByTags" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ("tags", Some(tagsQuery.toParamString(tags)))) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[List[Pet]](req) + + } yield resp + } + + def getPetById(petId: Long): Task[Pet] = { + implicit val returnTypeDecoder: EntityDecoder[Pet] = jsonOf[Pet] + + val path = "/pet/{petId}".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[Pet](req) + + } yield resp + } + + def updatePet(body: Pet): Task[Unit] = { + val path = "/pet" + + val httpMethod = Method.PUT + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def updatePetWithForm(petId: Long, name: String, status: String): Task[Unit] = { + val path = "/pet/{petId}".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def uploadFile(petId: Long, additionalMetadata: String, file: File): Task[ApiResponse] = { + implicit val returnTypeDecoder: EntityDecoder[ApiResponse] = jsonOf[ApiResponse] + + val path = "/pet/{petId}/uploadImage".replaceAll("\\{" + "petId" + "\\}",escape(petId.toString)) + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[ApiResponse](req) + + } yield resp + } + +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/QueryParamTypeClass.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/QueryParamTypeClass.scala new file mode 100644 index 00000000000..2444a9376b2 --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/QueryParamTypeClass.scala @@ -0,0 +1,15 @@ +package io.swagger.client.api + +trait QueryParam[A] { + def toParamString(a: A): String +} + +object QueryParam { + implicit def strQueryParam: QueryParam[String] = new QueryParam[String] { + def toParamString(s: String): String = s + } + + implicit def listStrQueryParam: QueryParam[List[String]] = new QueryParam[List[String]] { + def toParamString(s: List[String]): String = s.mkString(",") + } +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/StoreApi.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/StoreApi.scala new file mode 100644 index 00000000000..4136582c685 --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/StoreApi.scala @@ -0,0 +1,201 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import java.io.File +import java.net.URLEncoder +import java.util.UUID + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.http4s.client._ +import org.http4s.client.blaze.PooledHttp1Client +import org.http4s.headers._ + +import org.joda.time.DateTime + +import scalaz.concurrent.Task + +import HelperCodecs._ + +object StoreApi { + + val client = PooledHttp1Client() + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + def deleteOrder(host: String, orderId: String): Task[Unit] = { + val path = "/store/order/{orderId}".replaceAll("\\{" + "orderId" + "\\}",escape(orderId.toString)) + + val httpMethod = Method.DELETE + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def getInventory(host: String): Task[Map[String, Integer]] = { + implicit val returnTypeDecoder: EntityDecoder[Map[String, Integer]] = jsonOf[Map[String, Integer]] + + val path = "/store/inventory" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[Map[String, Integer]](req) + + } yield resp + } + + def getOrderById(host: String, orderId: Long): Task[Order] = { + implicit val returnTypeDecoder: EntityDecoder[Order] = jsonOf[Order] + + val path = "/store/order/{orderId}".replaceAll("\\{" + "orderId" + "\\}",escape(orderId.toString)) + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[Order](req) + + } yield resp + } + + def placeOrder(host: String, body: Order): Task[Order] = { + implicit val returnTypeDecoder: EntityDecoder[Order] = jsonOf[Order] + + val path = "/store/order" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.expect[Order](req) + + } yield resp + } + +} + +class HttpServiceStoreApi(service: HttpService) { + val client = Client.fromHttpService(service) + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + def deleteOrder(orderId: String): Task[Unit] = { + val path = "/store/order/{orderId}".replaceAll("\\{" + "orderId" + "\\}",escape(orderId.toString)) + + val httpMethod = Method.DELETE + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def getInventory(): Task[Map[String, Integer]] = { + implicit val returnTypeDecoder: EntityDecoder[Map[String, Integer]] = jsonOf[Map[String, Integer]] + + val path = "/store/inventory" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[Map[String, Integer]](req) + + } yield resp + } + + def getOrderById(orderId: Long): Task[Order] = { + implicit val returnTypeDecoder: EntityDecoder[Order] = jsonOf[Order] + + val path = "/store/order/{orderId}".replaceAll("\\{" + "orderId" + "\\}",escape(orderId.toString)) + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[Order](req) + + } yield resp + } + + def placeOrder(body: Order): Task[Order] = { + implicit val returnTypeDecoder: EntityDecoder[Order] = jsonOf[Order] + + val path = "/store/order" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.expect[Order](req) + + } yield resp + } + +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Tag.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Tag.scala new file mode 100644 index 00000000000..27b1ab18f2a --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/Tag.scala @@ -0,0 +1,22 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.joda.time.DateTime +import Tag._ + +case class Tag ( + id: Option[Long], +name: Option[String]) + +object Tag { + import DateTimeCodecs._ + + implicit val TagCodecJson: CodecJson[Tag] = CodecJson.derive[Tag] + implicit val TagDecoder: EntityDecoder[Tag] = jsonOf[Tag] + implicit val TagEncoder: EntityEncoder[Tag] = jsonEncoderOf[Tag] +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/User.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/User.scala new file mode 100644 index 00000000000..f1898cc37dc --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/User.scala @@ -0,0 +1,29 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.joda.time.DateTime +import User._ + +case class User ( + id: Option[Long], +username: Option[String], +firstName: Option[String], +lastName: Option[String], +email: Option[String], +password: Option[String], +phone: Option[String], +/* User Status */ + userStatus: Option[Integer]) + +object User { + import DateTimeCodecs._ + + implicit val UserCodecJson: CodecJson[User] = CodecJson.derive[User] + implicit val UserDecoder: EntityDecoder[User] = jsonOf[User] + implicit val UserEncoder: EntityEncoder[User] = jsonEncoderOf[User] +} diff --git a/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/UserApi.scala b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/UserApi.scala new file mode 100644 index 00000000000..ea4619e01f5 --- /dev/null +++ b/samples/client/petstore/scalaz/src/main/scala/io/swagger/client/api/UserApi.scala @@ -0,0 +1,349 @@ +package io.swagger.client.api + +import argonaut._ +import argonaut.EncodeJson._ +import argonaut.DecodeJson._ + +import java.io.File +import java.net.URLEncoder +import java.util.UUID + +import org.http4s._ +import org.http4s.{EntityDecoder, EntityEncoder} +import org.http4s.argonaut._ +import org.http4s.client._ +import org.http4s.client.blaze.PooledHttp1Client +import org.http4s.headers._ + +import org.joda.time.DateTime + +import scalaz.concurrent.Task + +import HelperCodecs._ + +object UserApi { + + val client = PooledHttp1Client() + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + def createUser(host: String, body: User): Task[Unit] = { + val path = "/user" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def createUsersWithArrayInput(host: String, body: List[User]): Task[Unit] = { + val path = "/user/createWithArray" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def createUsersWithListInput(host: String, body: List[User]): Task[Unit] = { + val path = "/user/createWithList" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def deleteUser(host: String, username: String): Task[Unit] = { + val path = "/user/{username}".replaceAll("\\{" + "username" + "\\}",escape(username.toString)) + + val httpMethod = Method.DELETE + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def getUserByName(host: String, username: String): Task[User] = { + implicit val returnTypeDecoder: EntityDecoder[User] = jsonOf[User] + + val path = "/user/{username}".replaceAll("\\{" + "username" + "\\}",escape(username.toString)) + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[User](req) + + } yield resp + } + + def loginUser(host: String, username: String, password: String)(implicit usernameQuery: QueryParam[String], passwordQuery: QueryParam[String]): Task[String] = { + implicit val returnTypeDecoder: EntityDecoder[String] = jsonOf[String] + + val path = "/user/login" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ("username", Some(usernameQuery.toParamString(username))), ("password", Some(passwordQuery.toParamString(password)))) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[String](req) + + } yield resp + } + + def logoutUser(host: String): Task[Unit] = { + val path = "/user/logout" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def updateUser(host: String, username: String, body: User): Task[Unit] = { + val path = "/user/{username}".replaceAll("\\{" + "username" + "\\}",escape(username.toString)) + + val httpMethod = Method.PUT + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(host + path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + +} + +class HttpServiceUserApi(service: HttpService) { + val client = Client.fromHttpService(service) + + def escape(value: String): String = URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + + def createUser(body: User): Task[Unit] = { + val path = "/user" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def createUsersWithArrayInput(body: List[User]): Task[Unit] = { + val path = "/user/createWithArray" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def createUsersWithListInput(body: List[User]): Task[Unit] = { + val path = "/user/createWithList" + + val httpMethod = Method.POST + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def deleteUser(username: String): Task[Unit] = { + val path = "/user/{username}".replaceAll("\\{" + "username" + "\\}",escape(username.toString)) + + val httpMethod = Method.DELETE + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def getUserByName(username: String): Task[User] = { + implicit val returnTypeDecoder: EntityDecoder[User] = jsonOf[User] + + val path = "/user/{username}".replaceAll("\\{" + "username" + "\\}",escape(username.toString)) + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[User](req) + + } yield resp + } + + def loginUser(username: String, password: String)(implicit usernameQuery: QueryParam[String], passwordQuery: QueryParam[String]): Task[String] = { + implicit val returnTypeDecoder: EntityDecoder[String] = jsonOf[String] + + val path = "/user/login" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ("username", Some(usernameQuery.toParamString(username))), ("password", Some(passwordQuery.toParamString(password)))) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.expect[String](req) + + } yield resp + } + + def logoutUser(): Task[Unit] = { + val path = "/user/logout" + + val httpMethod = Method.GET + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + + def updateUser(username: String, body: User): Task[Unit] = { + val path = "/user/{username}".replaceAll("\\{" + "username" + "\\}",escape(username.toString)) + + val httpMethod = Method.PUT + val contentType = `Content-Type`(MediaType.`application/json`) + val headers = Headers( + ) + val queryParams = Query( + ) + + for { + uri <- Task.fromDisjunction(Uri.fromString(path)) + uriWithParams = uri.copy(query = queryParams) + req = Request(method = httpMethod, uri = uriWithParams, headers = headers.put(contentType)).withBody(body) + resp <- client.fetch[Unit](req)(_ => Task.now(())) + + } yield resp + } + +}