updates for response class to 1.2 spec

This commit is contained in:
Tony Tam 2013-08-11 15:36:16 -07:00
parent 93067a0ce0
commit aa1fbb680b
6 changed files with 239 additions and 171 deletions

View File

@ -27,6 +27,47 @@ object SwaggerSerializers {
("array", "") -> "Array" ("array", "") -> "Array"
) )
def toJsonSchema(name: String, `type`: String): JObject = {
`type` match {
case "int" => (name -> "integer") ~ ("format" -> "int32")
case "long" => (name -> "integer") ~ ("format" -> "int64")
case "float" => (name -> "number") ~ ("format" -> "float")
case "double" => (name -> "number") ~ ("format" -> "double")
case "string" => (name -> "string") ~ ("format" -> JNothing)
case "byte" => (name -> "string") ~ ("format" -> "byte")
case "boolean" => (name -> "boolean") ~ ("format" -> JNothing)
case "Date" => (name -> "string") ~ ("format" -> "date-time")
case "date" => (name -> "string") ~ ("format" -> "date")
case "date-time" => (name -> "string") ~ ("format" -> "date-time")
case _ => {
val ComplexTypeMatcher = "([a-zA-Z]*)\\[([a-zA-Z\\.\\-]*)\\].*".r
`type` match {
case ComplexTypeMatcher(container, value) =>
toJsonSchemaContainer(container) ~ {
("items" -> {if(isSimpleType(value))
toJsonSchema("type", value)
else
toJsonSchema("$ref", value)})
}
case _ => (name -> `type`) ~ ("format" -> JNothing)
}
}
}
}
def toJsonSchemaContainer(name: String): JObject = {
name match {
case "List" => ("type" -> "array") ~ ("format" -> JNothing)
case "Array" => ("type" -> "array") ~ ("format" -> JNothing)
case "Set" => ("type" -> "array") ~ ("uniqueItems" -> true)
case _ => ("type" -> JNothing)
}
}
def isSimpleType(name: String) = {
Set("int", "long", "float", "double", "string", "byte", "boolean", "Date", "date", "date-time", "array").contains(name)
}
def formats(version: String) = { def formats(version: String) = {
version match { version match {
case "1.1" => LegacySerializers.formats case "1.1" => LegacySerializers.formats
@ -205,6 +246,21 @@ object SwaggerSerializers {
case json => case json =>
implicit val fmts: Formats = formats implicit val fmts: Formats = formats
val responseClass = (json \ "items") match {
case e: JObject => {
val inner = {
(e \ "type").extractOrElse({
(e \ "$ref").extract[String]
})
}
"%s[%s]".format((json \ "type").extract[String], inner)
}
case _ => (json \ "type").extractOrElse({
!!(json, OPERATION, "responseClass", "missing required field", ERROR)
""
})
}
Operation( Operation(
(json \ "httpMethod").extractOrElse( (json \ "httpMethod").extractOrElse(
(json \ "method").extractOrElse({ (json \ "method").extractOrElse({
@ -214,10 +270,7 @@ object SwaggerSerializers {
), ),
(json \ "summary").extract[String], (json \ "summary").extract[String],
(json \ "notes").extractOrElse(""), (json \ "notes").extractOrElse(""),
(json \ "responseClass").extractOrElse({ responseClass,
!!(json, OPERATION, "responseClass", "missing required field", ERROR)
""
}),
(json \ "nickname").extractOrElse({ (json \ "nickname").extractOrElse({
!!(json, OPERATION, "nickname", "missing required field", ERROR) !!(json, OPERATION, "nickname", "missing required field", ERROR)
"" ""
@ -233,11 +286,24 @@ object SwaggerSerializers {
) )
}, { }, {
case x: Operation => case x: Operation =>
val ComplexTypeMatcher = "([a-zA-Z]*)\\[([a-zA-Z\\.\\-]*)\\].*".r
val output = x.responseClass match {
case ComplexTypeMatcher(container, value) =>
toJsonSchemaContainer(container) ~ {
("items" -> {if(isSimpleType(value))
toJsonSchema("type", value)
else
toJsonSchema("$ref", value)})
}
case _ => toJsonSchema("type", x.responseClass) ~ ("format" -> JNothing)
}
implicit val fmts = formats implicit val fmts = formats
("method" -> x.method) ~ ("method" -> x.method) ~
("summary" -> x.summary) ~ ("summary" -> x.summary) ~
("notes" -> x.notes) ~ ("notes" -> x.notes) ~
("responseClass" -> x.responseClass) ~ output ~
("nickname" -> x.nickname) ~ ("nickname" -> x.nickname) ~
("parameters" -> Extraction.decompose(x.parameters)) ~ ("parameters" -> Extraction.decompose(x.parameters)) ~
("responseMessages" -> { ("responseMessages" -> {

View File

@ -12,13 +12,12 @@
"apis": [ "apis": [
{ {
"path": "/pet/{petId}", "path": "/pet/{petId}",
"description":"Operations about pets",
"operations": [ "operations": [
{ {
"method": "GET", "method": "GET",
"summary": "Find pet by ID", "summary": "Find pet by ID",
"notes": "Returns a pet based on ID", "notes": "Returns a pet based on ID",
"responseClass": "Pet", "type": "Pet",
"nickname": "getPetById", "nickname": "getPetById",
"produces": [ "produces": [
"application/json", "application/json",
@ -52,7 +51,7 @@
"method": "DELETE", "method": "DELETE",
"summary": "Deletes a pet", "summary": "Deletes a pet",
"notes": "", "notes": "",
"responseClass": "void", "type": "void",
"nickname": "deletePet", "nickname": "deletePet",
"parameters": [ "parameters": [
{ {
@ -76,11 +75,34 @@
{ {
"path": "/pet", "path": "/pet",
"operations": [ "operations": [
{
"method": "POST",
"summary": "Add a new pet to the store",
"notes": "",
"type": "void",
"nickname": "addPet",
"parameters": [
{
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"allowMultiple": false,
"type": "Pet",
"paramType": "body"
}
],
"responseMessages": [
{
"code": 405,
"message": "Invalid input"
}
]
},
{ {
"method": "PUT", "method": "PUT",
"summary": "Update an existing pet", "summary": "Update an existing pet",
"notes": "", "notes": "",
"responseClass": "void", "type": "void",
"nickname": "updatePet", "nickname": "updatePet",
"parameters": [ "parameters": [
{ {
@ -106,29 +128,6 @@
"message": "Validation exception" "message": "Validation exception"
} }
] ]
},
{
"method": "POST",
"summary": "Add a new pet to the store",
"notes": "",
"responseClass": "void",
"nickname": "addPet",
"parameters": [
{
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"allowMultiple": false,
"type": "Pet",
"paramType": "body"
}
],
"responseMessages": [
{
"code": 405,
"message": "Invalid input"
}
]
} }
] ]
}, },
@ -139,7 +138,10 @@
"method": "GET", "method": "GET",
"summary": "Finds Pets by status", "summary": "Finds Pets by status",
"notes": "Multiple status values can be provided with comma seperated strings", "notes": "Multiple status values can be provided with comma seperated strings",
"responseClass": "List[Pet]", "type": "array",
"items": {
"$ref": "Pet"
},
"nickname": "findPetsByStatus", "nickname": "findPetsByStatus",
"produces": [ "produces": [
"application/json", "application/json",
@ -177,7 +179,10 @@
"method": "GET", "method": "GET",
"summary": "Finds Pets by tags", "summary": "Finds Pets by tags",
"notes": "Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.", "notes": "Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.",
"responseClass": "List[Pet]", "type": "array",
"items": {
"$ref": "Pet"
},
"nickname": "findPetsByTags", "nickname": "findPetsByTags",
"produces": [ "produces": [
"application/json", "application/json",
@ -221,10 +226,14 @@
"id": "Pet", "id": "Pet",
"description": "A pet is a person's best friend", "description": "A pet is a person's best friend",
"required": [ "required": [
"name", "id",
"id" "name"
], ],
"properties": { "properties": {
"id": {
"type": "integer",
"format": "int64"
},
"tags": { "tags": {
"type": "array", "type": "array",
"items": { "items": {
@ -234,10 +243,6 @@
"name": { "name": {
"type": "string" "type": "string"
}, },
"id": {
"type": "integer",
"format": "int64"
},
"status": { "status": {
"type": "string", "type": "string",
"description": "pet status in the store", "description": "pet status in the store",

View File

@ -15,7 +15,7 @@
"method": "GET", "method": "GET",
"summary": "Find purchase order by ID", "summary": "Find purchase order by ID",
"notes": "For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors", "notes": "For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors",
"responseClass": "Order", "type": "Order",
"nickname": "getOrderById", "nickname": "getOrderById",
"produces": [ "produces": [
"application/json", "application/json",
@ -46,7 +46,7 @@
"method": "DELETE", "method": "DELETE",
"summary": "Delete purchase order by ID", "summary": "Delete purchase order by ID",
"notes": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", "notes": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors",
"responseClass": "void", "type": "void",
"nickname": "deleteOrder", "nickname": "deleteOrder",
"parameters": [ "parameters": [
{ {
@ -78,7 +78,7 @@
"method": "POST", "method": "POST",
"summary": "Place an order for a pet", "summary": "Place an order for a pet",
"notes": "", "notes": "",
"responseClass": "void", "type": "void",
"nickname": "placeOrder", "nickname": "placeOrder",
"parameters": [ "parameters": [
{ {
@ -104,6 +104,10 @@
"Order": { "Order": {
"id": "Order", "id": "Order",
"properties": { "properties": {
"id": {
"type": "integer",
"format": "int64"
},
"status": { "status": {
"type": "string", "type": "string",
"description": "Order Status", "description": "Order Status",
@ -113,14 +117,6 @@
"delivered" "delivered"
] ]
}, },
"id": {
"type": "integer",
"format": "int64"
},
"shipDate": {
"type": "string",
"format": "date-time"
},
"petId": { "petId": {
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
@ -128,6 +124,10 @@
"quantity": { "quantity": {
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
},
"shipDate": {
"type": "string",
"format": "date-time"
} }
} }
} }

View File

@ -9,44 +9,85 @@
], ],
"apis": [ "apis": [
{ {
"path": "/user/{username}", "path": "/user",
"operations": [ "operations": [
{ {
"method": "GET", "method": "POST",
"summary": "Get user by user name", "summary": "Create user",
"notes": "", "notes": "This can only be done by the logged in user.",
"responseClass": "User", "type": "void",
"nickname": "getUserByName", "nickname": "createUser",
"produces": [
"application/json",
"application/xml"
],
"parameters": [ "parameters": [
{ {
"name": "username", "name": "body",
"description": "The name that needs to be fetched. Use user1 for testing.", "description": "Created user object",
"required": true, "required": true,
"allowMultiple": false, "allowMultiple": false,
"type": "string", "type": "User",
"paramType": "path" "paramType": "body"
} }
], ]
"responseMessages": [
{
"code": 400,
"message": "Invalid username supplied"
},
{
"code": 404,
"message": "User not found"
} }
] ]
}, },
{
"path": "/user/createWithArray",
"operations": [
{
"method": "POST",
"summary": "Creates list of users with given input array",
"notes": "",
"type": "void",
"nickname": "createUsersWithArrayInput",
"parameters": [
{
"name": "body",
"description": "List of user object",
"required": true,
"allowMultiple": false,
"type": "array",
"items": {
"$ref": "User"
},
"paramType": "body"
}
]
}
]
},
{
"path": "/user/createWithList",
"operations": [
{
"method": "POST",
"summary": "Creates list of users with given list input",
"notes": "",
"type": "void",
"nickname": "createUsersWithListInput",
"parameters": [
{
"name": "body",
"description": "List of user object",
"required": true,
"allowMultiple": false,
"type": "array",
"items": {
"$ref": "User"
},
"paramType": "body"
}
]
}
]
},
{
"path": "/user/{username}",
"operations": [
{ {
"method": "PUT", "method": "PUT",
"summary": "Updated user", "summary": "Updated user",
"notes": "This can only be done by the logged in user.", "notes": "This can only be done by the logged in user.",
"responseClass": "void", "type": "void",
"nickname": "updateUser", "nickname": "updateUser",
"parameters": [ "parameters": [
{ {
@ -81,7 +122,7 @@
"method": "DELETE", "method": "DELETE",
"summary": "Delete user", "summary": "Delete user",
"notes": "This can only be done by the logged in user.", "notes": "This can only be done by the logged in user.",
"responseClass": "void", "type": "void",
"nickname": "deleteUser", "nickname": "deleteUser",
"parameters": [ "parameters": [
{ {
@ -103,6 +144,37 @@
"message": "User not found" "message": "User not found"
} }
] ]
},
{
"method": "GET",
"summary": "Get user by user name",
"notes": "",
"type": "User",
"nickname": "getUserByName",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"name": "username",
"description": "The name that needs to be fetched. Use user1 for testing.",
"required": true,
"allowMultiple": false,
"type": "string",
"paramType": "path"
}
],
"responseMessages": [
{
"code": 400,
"message": "Invalid username supplied"
},
{
"code": 404,
"message": "User not found"
}
]
} }
] ]
}, },
@ -113,7 +185,7 @@
"method": "GET", "method": "GET",
"summary": "Logs user into the system", "summary": "Logs user into the system",
"notes": "", "notes": "",
"responseClass": "string", "type": "string",
"nickname": "loginUser", "nickname": "loginUser",
"produces": [ "produces": [
"text/plain" "text/plain"
@ -152,7 +224,7 @@
"method": "GET", "method": "GET",
"summary": "Logs out current logged in user session", "summary": "Logs out current logged in user session",
"notes": "", "notes": "",
"responseClass": "void", "type": "void",
"nickname": "logoutUser", "nickname": "logoutUser",
"produces": [ "produces": [
"text/plain" "text/plain"
@ -160,84 +232,16 @@
"parameters": [] "parameters": []
} }
] ]
},
{
"path": "/user",
"operations": [
{
"method": "POST",
"summary": "Create user",
"notes": "This can only be done by the logged in user.",
"responseClass": "void",
"nickname": "createUser",
"parameters": [
{
"name": "body",
"description": "Created user object",
"required": true,
"allowMultiple": false,
"type": "User",
"paramType": "body"
}
]
}
]
},
{
"path": "/user/createWithArray",
"operations": [
{
"method": "POST",
"summary": "Creates list of users with given input array",
"notes": "",
"responseClass": "void",
"nickname": "createUsersWithArrayInput",
"parameters": [
{
"name": "body",
"description": "List of user object",
"required": true,
"allowMultiple": false,
"type": "array",
"items": {
"$ref": "User"
},
"paramType": "body"
}
]
}
]
},
{
"path": "/user/createWithList",
"operations": [
{
"method": "POST",
"summary": "Creates list of users with given list input",
"notes": "",
"responseClass": "void",
"nickname": "createUsersWithListInput",
"parameters": [
{
"name": "body",
"description": "List of user object",
"required": true,
"allowMultiple": false,
"type": "array",
"items": {
"$ref": "User"
},
"paramType": "body"
}
]
}
]
} }
], ],
"models": { "models": {
"User": { "User": {
"id": "User", "id": "User",
"properties": { "properties": {
"id": {
"type": "integer",
"format": "int64"
},
"username": { "username": {
"type": "string" "type": "string"
}, },
@ -247,9 +251,8 @@
"email": { "email": {
"type": "string" "type": "string"
}, },
"id": { "firstName": {
"type": "integer", "type": "string"
"format": "int64"
}, },
"lastName": { "lastName": {
"type": "string" "type": "string"
@ -266,9 +269,6 @@
"2-active", "2-active",
"3-closed" "3-closed"
] ]
},
"firstName": {
"type": "string"
} }
} }
} }

View File

@ -145,7 +145,7 @@ class OperationValidationTest extends FlatSpec with ShouldMatchers {
"httpMethod":"GET", "httpMethod":"GET",
"summary":"the summary", "summary":"the summary",
"notes":"the notes", "notes":"the notes",
"responseClass":"string", "type":"string",
"nickname":"getMeSomeStrings", "nickname":"getMeSomeStrings",
"parameters":[ "parameters":[
{ {
@ -183,7 +183,7 @@ class OperationValidationTest extends FlatSpec with ShouldMatchers {
List.empty, List.empty,
List(Parameter("id", Some("the id"), Some("-1"), false, true, "string", AllowableListValues(List("a","b","c")), "query")) List(Parameter("id", Some("the id"), Some("-1"), false, true, "string", AllowableListValues(List("a","b","c")), "query"))
) )
write(op) should be ("""{"method":"get","summary":"the summary","notes":"the notes","responseClass":"string","nickname":"getMeSomeStrings","parameters":[{"name":"id","description":"the id","defaultValue":"-1","required":false,"allowMultiple":true,"type":"string","allowableValues":{"valueType":"LIST","values":["a","b","c"]},"paramType":"query"}]}""") write(op) should be ("""{"method":"get","summary":"the summary","notes":"the notes","type":"string","nickname":"getMeSomeStrings","parameters":[{"name":"id","description":"the id","defaultValue":"-1","required":false,"allowMultiple":true,"type":"string","allowableValues":{"valueType":"LIST","values":["a","b","c"]},"paramType":"query"}]}""")
} }
} }
@ -225,13 +225,10 @@ class ParameterValidationTest extends FlatSpec with ShouldMatchers {
"defaultValue":"false", "defaultValue":"false",
"description":"Show duplicate examples from different sources", "description":"Show duplicate examples from different sources",
"required":"false", "required":"false",
"allowableValues":{ "enum":[
"values":[
false, false,
true true
], ],
"valueType":"LIST"
},
"type":"string", "type":"string",
"allowMultiple":false, "allowMultiple":false,
"paramType":"query" "paramType":"query"

View File

@ -138,7 +138,7 @@ class ApiDescriptionSerializersTest extends FlatSpec with ShouldMatchers {
"method":"GET", "method":"GET",
"summary":"the summary", "summary":"the summary",
"notes":"the notes", "notes":"the notes",
"responseClass":"string", "type":"string",
"nickname":"getMeSomeStrings", "nickname":"getMeSomeStrings",
"parameters":[ "parameters":[
{ {
@ -203,7 +203,7 @@ class ApiDescriptionSerializersTest extends FlatSpec with ShouldMatchers {
List(Parameter("id", Some("the id"), Some("-1"), false, true, "string", AllowableListValues(List("a","b","c")), "query")) List(Parameter("id", Some("the id"), Some("-1"), false, true, "string", AllowableListValues(List("a","b","c")), "query"))
)) ))
) )
write(l) should be ("""{"path":"/foo/bar","description":"the description","operations":[{"method":"get","summary":"the summary","notes":"the notes","responseClass":"string","nickname":"getMeSomeStrings","parameters":[{"name":"id","description":"the id","defaultValue":"-1","required":false,"allowMultiple":true,"type":"string","allowableValues":{"valueType":"LIST","values":["a","b","c"]},"paramType":"query"}]}]}""") write(l) should be ("""{"path":"/foo/bar","description":"the description","operations":[{"method":"get","summary":"the summary","notes":"the notes","type":"string","nickname":"getMeSomeStrings","parameters":[{"name":"id","description":"the id","defaultValue":"-1","required":false,"allowMultiple":true,"type":"string","allowableValues":{"valueType":"LIST","values":["a","b","c"]},"paramType":"query"}]}]}""")
} }
} }
@ -217,7 +217,7 @@ class OperationSerializersTest extends FlatSpec with ShouldMatchers {
"method":"GET", "method":"GET",
"summary":"the summary", "summary":"the summary",
"notes":"the notes", "notes":"the notes",
"responseClass":"string", "type":"string",
"nickname":"getMeSomeStrings", "nickname":"getMeSomeStrings",
"parameters":[ "parameters":[
{ {
@ -271,7 +271,7 @@ class OperationSerializersTest extends FlatSpec with ShouldMatchers {
List.empty, List.empty,
List(Parameter("id", Some("the id"), Some("-1"), false, true, "string", AllowableListValues(List("a","b","c")), "query")) List(Parameter("id", Some("the id"), Some("-1"), false, true, "string", AllowableListValues(List("a","b","c")), "query"))
) )
write(op) should be ("""{"method":"get","summary":"the summary","notes":"the notes","responseClass":"string","nickname":"getMeSomeStrings","parameters":[{"name":"id","description":"the id","defaultValue":"-1","required":false,"allowMultiple":true,"type":"string","allowableValues":{"valueType":"LIST","values":["a","b","c"]},"paramType":"query"}]}""") write(op) should be ("""{"method":"get","summary":"the summary","notes":"the notes","type":"string","nickname":"getMeSomeStrings","parameters":[{"name":"id","description":"the id","defaultValue":"-1","required":false,"allowMultiple":true,"type":"string","allowableValues":{"valueType":"LIST","values":["a","b","c"]},"paramType":"query"}]}""")
} }
} }