Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #267 from caoilte/2.2.x_2.9

modify scalatra-swagger api docs generation to better support apiproperty annotation
  • Loading branch information...
commit 8a1bff874ee6225d22fb7fc12c246c41c3c7a525 2 parents 6596bdb + 6744d40
@casualjim casualjim authored
View
20 swagger/src/main/scala/org/scalatra/swagger/Swagger.scala
@@ -9,8 +9,10 @@ import format.ISODateTimeFormat
import grizzled.slf4j.Logger
import java.util.Date
import reflect.{ScalaType, PrimitiveDescriptor, ClassDescriptor, Reflector}
-import com.wordnik.swagger.core.ApiPropertiesReader
+import com.wordnik.swagger.core.{DocumentationAllowableValues, DocumentationAllowableRangeValues, DocumentationAllowableListValues, ApiPropertiesReader}
import collection.JavaConverters._
+import org.scalatra.swagger.AllowableValues.AllowableValuesList
+import org.scalatra.swagger.AllowableValues.AllowableRangeValues
trait SwaggerEngine[T <: SwaggerApi[_]] {
@@ -78,11 +80,21 @@ object Swagger {
val docObj = ApiPropertiesReader.read(klass)
val name = docObj.getName
val fields = for (field <- docObj.getFields.asScala.filter(d => d.paramType != null))
- yield (field.name -> ModelField(field.name, field.notes, DataType(field.paramType)))
+ yield (field.name -> ModelField(field.name, field.description, DataType(field.paramType),
+ allowableValues = allowableValuesToString(field.allowableValues)))
Some(Model(name, name, fields.toMap))
}
}
+ private def allowableValuesToString(allowableValues: DocumentationAllowableValues) = {
+ import scala.collection.JavaConversions._
+
+ allowableValues match {
+ case list:DocumentationAllowableListValues => AllowableValuesList(list.getValues.toList)
+ case range:DocumentationAllowableRangeValues => AllowableRangeValues(Range(range.getMin.toInt, range.getMax.toInt))
+ case _ => AllowableValues.AnyValue
+ }
+ }
}
/**
@@ -202,7 +214,8 @@ private[swagger] object SwaggerSerializers {
case x: ModelField => {
val c = ("description" -> x.description) ~
("defaultValue" -> x.defaultValue) ~
- ("required" -> x.required)
+ ("required" -> x.required) ~
+ ("allowableValues" -> Extraction.decompose(x.allowableValues))
c merge serializeDataType("type", x.`type`)
}
}
@@ -377,6 +390,7 @@ case class ModelField(name: String,
description: String,
`type`: DataType.DataType,
defaultValue: Option[String] = None,
+ allowableValues: AllowableValues = AllowableValues.AnyValue,
required: Boolean = true)
object ModelField {
View
8 swagger/src/main/scala/org/scalatra/swagger/package.scala
@@ -14,4 +14,10 @@ package object swagger {
val Description = Symbol("swagger.description")
val AllSymbols = Set(Summary, Notes, Nickname, ResponseClass, Parameters, Errors, Endpoint, Allows, Operation)
}
-}
+
+ object annotations {
+ import scala.annotation.target.getter
+
+ type ApiProperty = com.wordnik.swagger.annotations.ApiProperty @getter
+ }
+}
View
33 swagger/src/test/resources/pet.json
@@ -170,45 +170,48 @@
"properties": {
"category": {
"description": null,
- "enum": [],
- "name": "category",
"required": true,
"type": "Category"
},
"id": {
"description": null,
- "enum": [],
- "name": "id",
"required": true,
"type": "long"
},
"name": {
"description": null,
- "enum": [],
- "name": "name",
"required": true,
"type": "string"
},
"status": {
- "description": null,
- "enum": [],
- "name": "status",
+ "description": "pet availability",
"required": true,
+ "allowableValues": {
+ "valueType": "LIST",
+ "values": [
+ "available",
+ "sold"
+ ]
+ },
"type": "string"
},
"tags": {
"description": null,
- "enum": [],
- "name": "tags",
"required": true,
- "type": "List[Tag]"
+ "type": "Array",
+ "uniqueItems": false,
+ "items": {
+ "$ref": "Tag"
+ }
},
"urls": {
"description": null,
- "enum": [],
- "name": "urls",
"required": true,
- "type": "List[string]"
+ "type": "Array",
+ "uniqueItems": false,
+ "items": {
+ "type": "string"
+ }
}
}
}
View
37 swagger/src/test/scala/org/scalatra/swagger/ModelSpec.scala
@@ -0,0 +1,37 @@
+package org.scalatra.swagger
+
+import org.specs2.mutable.Specification
+import org.scalatra.swagger.annotations.ApiProperty
+import org.scalatra.swagger.AllowableValues.{AllowableRangeValues, AllowableValuesList}
+
+object ModelSpec {
+
+ case class WithDescription(@ApiProperty(value = "a description", allowableValues = "item1,item2")
+ id: String)
+ case class WithAllowableValues(@ApiProperty(allowableValues = "item1,item2")
+ id: String)
+ case class WithAllowableRangeValues(@ApiProperty(allowableValues = "range[1,10]")
+ id: String)
+
+ def swaggerProperties[T](implicit mf: Manifest[T]) = Swagger.modelToSwagger(mf.erasure).get.properties.get("id").get
+
+}
+
+class ModelSpec extends Specification {
+ import ModelSpec._
+
+ "Model to Swagger" should {
+
+ "convert a populated description property of an ApiProperty annotation" in {
+ swaggerProperties[WithDescription].description must_== "a description"
+ }
+
+ "convert a populated allowable values property of an ApiProperty annotation" in {
+ swaggerProperties[WithAllowableValues].allowableValues must_== AllowableValuesList(List("item1", "item2"))
+ }
+ "convert a populated allowable values property of an ApiProperty annotation when it is a range" in {
+ swaggerProperties[WithAllowableRangeValues].allowableValues must_== AllowableRangeValues(Range(1, 10))
+ }
+ }
+
+}
View
16 swagger/src/test/scala/org/scalatra/swagger/SwaggerSpec.scala
@@ -12,6 +12,7 @@ import org.json4s.native.JsonParser
import org.scalatra.json.{JValueResult, NativeJsonSupport}
import scala.io.Source
import java.net.ServerSocket
+import org.scalatra.swagger.annotations.ApiProperty
class SwaggerSpec extends ScalatraSpec with JsonMatchers { def is = sequential ^
"Swagger integration should" ^
@@ -53,7 +54,8 @@ class SwaggerSpec extends ScalatraSpec with JsonMatchers { def is = sequential ^
val bo = JsonParser.parseOpt(body)
bo must beSome[JValue] and
verifyCommon(bo.get) and
- operations.map(verifyOperation(bo.get, _)).reduce(_ and _)
+ operations.map(verifyOperation(bo.get, _)).reduce(_ and _) and
+ verifyPetModel(bo.get)
}
}
@@ -78,6 +80,15 @@ class SwaggerSpec extends ScalatraSpec with JsonMatchers { def is = sequential ^
}
}
+ def verifyPetModel(actualPetJson: JValue) = {
+ def petProperties(jv: JValue) = jv \ "models" \ "Pet" \ "properties"
+ val actualPetProps = petProperties(actualPetJson)
+ val expectedPetProps = petProperties(listOperationsJValue)
+
+ val m = verifyFields(actualPetProps, expectedPetProps, "category", "id", "name", "status", "tags", "urls")
+ m setMessage (m.message + " of the pet model")
+ }
+
def verifyFields(actual: JValue, expected: JValue, fields: String*): MatchResult[Any] = {
def verifyField(act: JValue, exp: JValue, fn: String): MatchResult[Any] = {
fn match {
@@ -202,7 +213,8 @@ class SwaggerTestServlet(protected val swagger:Swagger) extends ScalatraServlet
class SwaggerResourcesServlet(val swagger: Swagger) extends ScalatraServlet with NativeSwaggerBase
-case class Pet(id: Long, category: Category, name: String, urls: List[String], tags: List[Tag], status: String)
+case class Pet(id: Long, category: Category, name: String, urls: List[String], tags: List[Tag],
+ @ApiProperty(value = "pet availability", allowableValues = "available,sold") status: String)
case class Tag(id: Long, name: String)
case class Category(id: Long, name: String)
Please sign in to comment.
Something went wrong with that request. Please try again.