added scalatra server generator (WIP)

This commit is contained in:
Tony Tam 2012-08-29 09:27:55 -07:00
parent 21848c3cf3
commit 07addb366e
26 changed files with 692 additions and 0 deletions

View File

@ -0,0 +1,75 @@
/**
* Copyright 2012 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.wordnik.swagger.codegen.BasicScalaGenerator
import com.wordnik.swagger.core._
import scala.collection.mutable.{ HashMap, ListBuffer }
object ScalatraServerGenerator extends BasicScalaGenerator {
def main(args: Array[String]) = generateClient(args)
override def templateDir = "samples/server-generator/scalatra/templates"
val outputFolder = "samples/server-generator/scalatra/output"
// where to write generated code
override def destinationDir = outputFolder + "/src/main/scala"
override def modelPackage = Some("com.wordnik.client.model")
// template used for apis
apiTemplateFiles ++= Map("api.mustache" -> ".scala")
modelTemplateFiles ++= Map("model.mustache" -> ".scala")
override def apiPackage = Some("apis")
// supporting classes
override def supportingFiles = List(
("README.mustache", outputFolder, "README.md"),
("build.sbt", outputFolder, "build.sbt"),
("JsonUtil.scala", destinationDir, "JsonUtil.scala"),
("project/build.properties", outputFolder, "project/build.properties"),
("project/plugins.sbt", outputFolder, "project/plugins.sbt"))
def processApiMap(m: Map[String, AnyRef]): Map[String, AnyRef] = {
val mutable = scala.collection.mutable.Map() ++ m
mutable.map(k => {
k._1 match {
// the scalatra templates like lower-case httpMethods
case e: String if (e == "httpMethod") => mutable += "httpMethod" -> k._2.toString.toLowerCase
// convert path into ruby-ish syntax (i.e. /pet.{format}/{petId} => /:petId
case e: String if (e == "path") => {
val path = {
val arr = k._2.toString.split("/")
if (arr.length >= 2)
"/" + arr.slice(2, arr.length).mkString("", "/", "")
else
k._2.toString
}
// rip out the root path
mutable += "path" -> path.replaceAll("\\{", ":").replaceAll("\\}", "")
}
case _ =>
}
})
mutable.toMap
}
}

View File

@ -0,0 +1,10 @@
# Swagger generated server
## Overview
This server was generated by the [swagger-codegen](https://github.com/wordnik/swagger-codegen) project. By using the
[swagger-spec](https://github.com/wordnik/swagger-core/wiki) from a remote server, you can easily generate a server stub. This
is an example of building a swagger-enabled scalatra server.
This example uses the [scalatra](http://scalatra.org/) framework. To see how to make this your own, look here:
[README](https://github.com/wordnik/swagger-codegen/tree/master/samples/server-generator/scalatra)

View File

@ -0,0 +1,31 @@
organization := "com.wordnik"
name := "swagger-scalatra-server"
version := "0.1.0-SNAPSHOT"
scalaVersion := "2.9.1"
scalaSource in Compile <<= baseDirectory.identity
seq(webSettings :_*)
libraryDependencies ++= Seq(
"com.fasterxml.jackson.module" % "jackson-module-scala" % "2.0.0" % "compile;container;test;runtime",
"org.scalatra" % "scalatra" % "2.1.0.M2",
"org.scalatra" % "scalatra-scalate" % "2.1.0.M2",
"org.scalatra" % "scalatra-specs2" % "2.1.0.M2" % "test",
"org.scalatra" % "scalatra-swagger" % "2.1.0.M2",
"com.wordnik" %% "swagger-core" % "1.1.0",
"ch.qos.logback" % "logback-classic" % "1.0.0" % "runtime",
"org.eclipse.jetty" % "jetty-server" % "8.1.3.v20120416" % "compile;container;test;runtime",
"org.eclipse.jetty" % "jetty-servlet" % "8.1.3.v20120416" % "compile;container;test;runtime",
"org.eclipse.jetty" % "jetty-webapp" % "8.1.3.v20120416" % "compile;container;test;runtime",
"javax.servlet" % "javax.servlet-api" % "3.0.1" % "provided;container;test;runtime"
)
resolvers += "Sonatype OSS Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/"
ivyXML := <dependencies>
<exclude org="org.eclipse.jetty.orbit" />
</dependencies>

View File

@ -0,0 +1 @@
sbt.version=0.11.3

View File

@ -0,0 +1 @@
libraryDependencies <+= sbtVersion(v => "com.github.siasia" %% "xsbt-web-plugin" % (v+"-0.2.11.1"))

View File

@ -0,0 +1,12 @@
package json
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.core.JsonGenerator.Feature
import com.fasterxml.jackson.databind._
object JsonUtil {
val mapper = new ObjectMapper()
mapper.registerModule(new DefaultScalaModule())
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
}

View File

@ -0,0 +1,100 @@
package apis
import json.JsonUtil
import com.wordnik.swagger.core.ApiPropertiesReader
import com.wordnik.client.model.Pet
import org.scalatra.ScalatraServlet
import org.scalatra.swagger._
import scala.collection.JavaConverters._
class PetApi (implicit val swagger: Swagger) extends ScalatraServlet with SwaggerBase with SwaggerSupport {
protected def buildFullUrl(path: String) = "http://petstore.swagger.wordnik.com/api/%s" format path
// val data = new PetData
val m = JsonUtil.mapper
// models = Map(swaggerToModel(classOf[Pet]))
get("/:petId",
summary("Find pet by ID"),
nickname("getPetById"),
responseClass("Pet"),
endpoint("{NOT SURE}"),
notes("Returns a pet based on ID"),
parameters(
// it's a path param
Parameter("petId", "ID of pet that needs to be fetched",
dataType = DataType.String,
paramType = ParamType.Path)
)) {
}
post("/",
summary("Add a new pet to the store"),
nickname("addPet"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
// it's a body param
Parameter("body", "Pet object that needs to be added to the store",
dataType = DataType("Pet"),
paramType = ParamType.Body)
)) {
}
put("/",
summary("Update an existing pet"),
nickname("updatePet"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
// it's a body param
Parameter("body", "Pet object that needs to be updated in the store",
dataType = DataType("Pet"),
paramType = ParamType.Body)
)) {
}
get("/findByStatus",
summary("Finds Pets by status"),
nickname("findPetsByStatus"),
responseClass("List[Pet]"),
endpoint("{NOT SURE}"),
notes("Multiple status values can be provided with comma seperated strings"),
parameters(
// it's a query param
Parameter("status", "Status values that need to be considered for filter",
paramType = ParamType.Query,
required = true,
allowMultiple = true,
allowableValues = "LIST[available,pending,sold]",defaultValue = Some("available"),
dataType = DataType("String"))
)) {
}
get("/findByTags",
summary("Finds Pets by tags"),
nickname("findPetsByTags"),
responseClass("List[Pet]"),
endpoint("{NOT SURE}"),
notes("Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing."),
parameters(
// it's a query param
Parameter("tags", "Tags to filter by",
paramType = ParamType.Query,
required = true,
allowMultiple = true,
defaultValue = None,
dataType = DataType("String"))
)) {
}
}

View File

@ -0,0 +1,64 @@
package apis
import json.JsonUtil
import com.wordnik.swagger.core.ApiPropertiesReader
import com.wordnik.client.model.Order
import org.scalatra.ScalatraServlet
import org.scalatra.swagger._
import scala.collection.JavaConverters._
class StoreApi (implicit val swagger: Swagger) extends ScalatraServlet with SwaggerBase with SwaggerSupport {
protected def buildFullUrl(path: String) = "http://petstore.swagger.wordnik.com/api/%s" format path
// val data = new PetData
val m = JsonUtil.mapper
// models = Map(swaggerToModel(classOf[Pet]))
get("/order/:orderId",
summary("Find purchase order by ID"),
nickname("getOrderById"),
responseClass("Order"),
endpoint("{NOT SURE}"),
notes("For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors"),
parameters(
// it's a path param
Parameter("orderId", "ID of pet that needs to be fetched",
dataType = DataType.String,
paramType = ParamType.Path)
)) {
}
delete("/order/:orderId",
summary("Delete purchase order by ID"),
nickname("deleteOrder"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes("For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors"),
parameters(
// it's a path param
Parameter("orderId", "ID of the order that needs to be deleted",
dataType = DataType.String,
paramType = ParamType.Path)
)) {
}
post("/order",
summary("Place an order for a pet"),
nickname("placeOrder"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
// it's a body param
Parameter("body", "order placed for purchasing the pet",
dataType = DataType("Order"),
paramType = ParamType.Body)
)) {
}
}

View File

@ -0,0 +1,154 @@
package apis
import json.JsonUtil
import com.wordnik.swagger.core.ApiPropertiesReader
import com.wordnik.client.model.User
import org.scalatra.ScalatraServlet
import org.scalatra.swagger._
import scala.collection.JavaConverters._
class UserApi (implicit val swagger: Swagger) extends ScalatraServlet with SwaggerBase with SwaggerSupport {
protected def buildFullUrl(path: String) = "http://petstore.swagger.wordnik.com/api/%s" format path
// val data = new PetData
val m = JsonUtil.mapper
// models = Map(swaggerToModel(classOf[Pet]))
post("/createWithArray",
summary("Creates list of users with given input array"),
nickname("createUsersWithArrayInput"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
// it's a body param
Parameter("body", "List of user object",
dataType = DataType("Array[User]"),
paramType = ParamType.Body)
)) {
}
post("/",
summary("Create user"),
nickname("createUser"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes("This can only be done by the logged in user."),
parameters(
// it's a body param
Parameter("body", "Created user object",
dataType = DataType("User"),
paramType = ParamType.Body)
)) {
}
post("/createWithList",
summary("Creates list of users with given list input"),
nickname("createUsersWithListInput"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
// it's a body param
Parameter("body", "List of user object",
dataType = DataType("List[User]"),
paramType = ParamType.Body)
)) {
}
put("/:username",
summary("Updated user"),
nickname("updateUser"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes("This can only be done by the logged in user."),
parameters(
// it's a path param
Parameter("username", "name that need to be deleted",
dataType = DataType.String,
paramType = ParamType.Path)
// it's a body param
Parameter("username", "name that need to be deleted",
dataType = DataType("String"),
paramType = ParamType.Body)
,
// it's a body param
Parameter("body", "Updated user object",
dataType = DataType("User"),
paramType = ParamType.Body)
)) {
}
delete("/:username",
summary("Delete user"),
nickname("deleteUser"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes("This can only be done by the logged in user."),
parameters(
// it's a path param
Parameter("username", "The name that needs to be deleted",
dataType = DataType.String,
paramType = ParamType.Path)
)) {
}
get("/:username",
summary("Get user by user name"),
nickname("getUserByName"),
responseClass("User"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
// it's a path param
Parameter("username", "The name that needs to be fetched. Use user1 for testing.",
dataType = DataType.String,
paramType = ParamType.Path)
)) {
}
get("/login",
summary("Logs user into the system"),
nickname("loginUser"),
responseClass("String"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
// it's a query param
Parameter("username", "The user name for login",
paramType = ParamType.Query,
required = true,
allowMultiple = false,
defaultValue = None,
dataType = DataType("String"))
,
// it's a query param
Parameter("password", "The password for login in clear text",
paramType = ParamType.Query,
required = true,
allowMultiple = false,
defaultValue = None,
dataType = DataType("String"))
)) {
}
get("/logout",
summary("Logs out current logged in user session"),
nickname("logoutUser"),
responseClass("void"),
endpoint("{NOT SURE}"),
notes(""),
parameters(
)) {
}
}

View File

@ -0,0 +1,8 @@
package com.wordnik.client.model
import scala.reflect.BeanProperty
case class Category (
var id: Long,
var name: String)

View File

@ -0,0 +1,13 @@
package com.wordnik.client.model
import java.util.Date
import scala.reflect.BeanProperty
case class Order (
var id: Long,
var petId: Long,
/* Order Status */
var status: String,
var quantity: Int,
var shipDate: Date)

View File

@ -0,0 +1,15 @@
package com.wordnik.client.model
import com.wordnik.client.model.Category
import com.wordnik.client.model.Tag
import scala.reflect.BeanProperty
case class Pet (
var id: Long,
var tags: java.util.List[Tag],
var category: Category,
/* pet status in the store */
var status: String,
var name: String,
var photoUrls: java.util.List[String])

View File

@ -0,0 +1,8 @@
package com.wordnik.client.model
import scala.reflect.BeanProperty
case class Tag (
var id: Long,
var name: String)

View File

@ -0,0 +1,15 @@
package com.wordnik.client.model
import scala.reflect.BeanProperty
case class User (
var id: Long,
var lastName: String,
var username: String,
var phone: String,
var email: String,
/* User Status */
var userStatus: Int,
var firstName: String,
var password: String)

View File

@ -0,0 +1,12 @@
package json
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.core.JsonGenerator.Feature
import com.fasterxml.jackson.databind._
object JsonUtil {
val mapper = new ObjectMapper()
mapper.registerModule(new DefaultScalaModule())
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
}

View File

@ -0,0 +1,10 @@
# Swagger generated server
## Overview
This server was generated by the [swagger-codegen](https://github.com/wordnik/swagger-codegen) project. By using the
[swagger-spec](https://github.com/wordnik/swagger-core/wiki) from a remote server, you can easily generate a server stub. This
is an example of building a swagger-enabled scalatra server.
This example uses the [scalatra](http://scalatra.org/) framework. To see how to make this your own, look here:
[README](https://github.com/wordnik/swagger-codegen/tree/master/samples/server-generator/scalatra)

View File

@ -0,0 +1,65 @@
package {{package}}
import json.JsonUtil
import com.wordnik.swagger.core.ApiPropertiesReader
{{#imports}}import {{import}}
{{/imports}}
import org.scalatra.ScalatraServlet
import org.scalatra.swagger._
import scala.collection.JavaConverters._
class {{name}} (implicit val swagger: Swagger) extends ScalatraServlet with SwaggerBase with SwaggerSupport {
protected def buildFullUrl(path: String) = "{{basePath}}/%s" format path
// val data = new PetData
val m = JsonUtil.mapper
// models = Map(swaggerToModel(classOf[Pet]))
{{#operations}}
{{#operation}}
{{httpMethod}}("{{path}}",
summary("{{{summary}}}"),
nickname("{{nickname}}"),
responseClass("{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}"),
endpoint("{NOT SURE}"),
notes("{{{notes}}}"),
parameters(
{{#allParams}}
{{#queryParam}}
// it's a query param
Parameter("{{paramName}}", "{{{description}}}",
paramType = ParamType.Query,
required = {{required}},
allowMultiple = {{allowMultiple}},
{{#allowableValues}}allowableValues = "{{{allowableValues}}}",{{/allowableValues}}
defaultValue = {{#defaultValue}}Some({{{defaultValue}}}){{/defaultValue}}{{^defaultValue}}None{{/defaultValue}},
dataType = DataType("{{dataType}}"))
{{/queryParam}}
{{#pathParam}}
// it's a path param
Parameter("{{paramName}}", "{{{description}}}",
dataType = DataType.String,
paramType = ParamType.Path)
{{/pathParam}}
{{#headerParam}}
// it's a header param
Parameter("{{paramName}}", "{{{description}}}",
dataType = DataType("{{dataType}}"),
paramType = ParamType.Header)
{{/headerParam}}
{{#bodyParam}}
// it's a body param
Parameter("{{paramName}}", "{{{description}}}",
dataType = DataType("{{dataType}}"),
paramType = ParamType.Body)
{{/bodyParam}}
{{#hasMore}},{{/hasMore}}{{newline}}
{{/allParams}}
)) {
}
{{/operation}}
{{/operations}}
}

View File

@ -0,0 +1,31 @@
organization := "com.wordnik"
name := "swagger-scalatra-server"
version := "0.1.0-SNAPSHOT"
scalaVersion := "2.9.1"
scalaSource in Compile <<= baseDirectory.identity
seq(webSettings :_*)
libraryDependencies ++= Seq(
"com.fasterxml.jackson.module" % "jackson-module-scala" % "2.0.0" % "compile;container;test;runtime",
"org.scalatra" % "scalatra" % "2.1.0.M2",
"org.scalatra" % "scalatra-scalate" % "2.1.0.M2",
"org.scalatra" % "scalatra-specs2" % "2.1.0.M2" % "test",
"org.scalatra" % "scalatra-swagger" % "2.1.0.M2",
"com.wordnik" %% "swagger-core" % "1.1.0",
"ch.qos.logback" % "logback-classic" % "1.0.0" % "runtime",
"org.eclipse.jetty" % "jetty-server" % "8.1.3.v20120416" % "compile;container;test;runtime",
"org.eclipse.jetty" % "jetty-servlet" % "8.1.3.v20120416" % "compile;container;test;runtime",
"org.eclipse.jetty" % "jetty-webapp" % "8.1.3.v20120416" % "compile;container;test;runtime",
"javax.servlet" % "javax.servlet-api" % "3.0.1" % "provided;container;test;runtime"
)
resolvers += "Sonatype OSS Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/"
ivyXML := <dependencies>
<exclude org="org.eclipse.jetty.orbit" />
</dependencies>

View File

@ -0,0 +1,27 @@
var express = require("express")
, url = require("url")
, swagger = require("./Common/node/swagger.js")
, db = false
var app = express.createServer(
function(req, res, next) { if (req.db === undefined) { req.db = db; } next(); });
app.use(express.bodyParser());
swagger.setAppHandler(app);
// resources for the demo
{{#apis}}
var {{name}} = require("./apis/{{name}}.js");
{{/apis}}
swagger.addModels(models)
{{#apis}}
{{#operations}}
{{#operation}}.add{{httpMethod}}({{name}}.{{nickname}}){{/operation}}{{newline}}
{{/operations}}
{{/apis}};
// configures the app
swagger.configure("http://localhost:8002", "0.1");
// start the server
app.listen(8002);

View File

@ -0,0 +1,21 @@
package {{package}}
{{#imports}}import {{import}}
{{/imports}}
{{#models}}
import scala.reflect.BeanProperty
{{#model}}
case class {{classname}} (
{{#vars}}
{{#notes}}/* {{notes}} */
{{/notes}}
{{#description}}/* {{description}} */
{{/description}}
var {{name}}: {{datatype}}{{#hasMore}},{{newline}} {{/hasMore}}
{{/vars}}
)
{{/model}}
{{/models}}

View File

@ -0,0 +1,17 @@
{
"name": "sample-app",
"description": "Wordnik node.js server generator",
"version": "1.0.0",
"homepage": "https://github.com/wordnik/swagger-codegen",
"main": "./Common/node/swagger.js",
"directories": {
"lib": "./Common/node"
},
"engines": {
"node": ">= 0.8.x"
},
"dependencies": {
"connect": ">= 1.8.x",
"express": "3.x"
}
}

View File

@ -0,0 +1 @@
sbt.version=0.11.3

View File

@ -0,0 +1 @@
libraryDependencies <+= sbtVersion(v => "com.github.siasia" %% "xsbt-web-plugin" % (v+"-0.2.11.1"))