mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-07-01 05:00:55 +00:00
Merge branch 'master' of github.com:wordnik/swagger-codegen
This commit is contained in:
commit
3cbf2abc5c
@ -11,7 +11,7 @@
|
|||||||
* @param string $className the class to attempt to load
|
* @param string $className the class to attempt to load
|
||||||
*/
|
*/
|
||||||
function swagger_autoloader($className) {
|
function swagger_autoloader($className) {
|
||||||
$currentDir = substr(__FILE__, 0, strrpos(__FILE__, '/'));
|
$currentDir = dirname(__FILE__);
|
||||||
if (file_exists($currentDir . '/' . $className . '.php')) {
|
if (file_exists($currentDir . '/' . $className . '.php')) {
|
||||||
include $currentDir . '/' . $className . '.php';
|
include $currentDir . '/' . $className . '.php';
|
||||||
} elseif (file_exists($currentDir . '/models/' . $className . '.php')) {
|
} elseif (file_exists($currentDir . '/models/' . $className . '.php')) {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* @param string $className the class to attempt to load
|
* @param string $className the class to attempt to load
|
||||||
*/
|
*/
|
||||||
function swagger_autoloader($className) {
|
function swagger_autoloader($className) {
|
||||||
$currentDir = substr(__FILE__, 0, strrpos(__FILE__, '/'));
|
$currentDir = dirname(__FILE__);
|
||||||
if (file_exists($currentDir . '/' . $className . '.php')) {
|
if (file_exists($currentDir . '/' . $className . '.php')) {
|
||||||
include $currentDir . '/' . $className . '.php';
|
include $currentDir . '/' . $className . '.php';
|
||||||
} elseif (file_exists($currentDir . '/models/' . $className . '.php')) {
|
} elseif (file_exists($currentDir . '/models/' . $className . '.php')) {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* @param string $className the class to attempt to load
|
* @param string $className the class to attempt to load
|
||||||
*/
|
*/
|
||||||
function swagger_autoloader($className) {
|
function swagger_autoloader($className) {
|
||||||
$currentDir = substr(__FILE__, 0, strrpos(__FILE__, '/'));
|
$currentDir = dirname(__FILE__);
|
||||||
if (file_exists($currentDir . '/' . $className . '.php')) {
|
if (file_exists($currentDir . '/' . $className . '.php')) {
|
||||||
include $currentDir . '/' . $className . '.php';
|
include $currentDir . '/' . $className . '.php';
|
||||||
} elseif (file_exists($currentDir . '/models/' . $className . '.php')) {
|
} elseif (file_exists($currentDir . '/models/' . $className . '.php')) {
|
||||||
|
@ -44,15 +44,18 @@ class ApiClient:
|
|||||||
|
|
||||||
data = None
|
data = None
|
||||||
|
|
||||||
if method == 'GET':
|
if queryParams:
|
||||||
|
# Need to remove None values, these should not be sent
|
||||||
|
sentQueryParams = {}
|
||||||
|
for param, value in queryParams.items():
|
||||||
|
if value != None:
|
||||||
|
sentQueryParams[param] = value
|
||||||
|
url = url + '?' + urllib.urlencode(sentQueryParams)
|
||||||
|
|
||||||
if queryParams:
|
if method in ['GET']:
|
||||||
# Need to remove None values, these should not be sent
|
|
||||||
sentQueryParams = {}
|
#Options to add statements later on and for compatibility
|
||||||
for param, value in queryParams.items():
|
pass
|
||||||
if value != None:
|
|
||||||
sentQueryParams[param] = value
|
|
||||||
url = url + '?' + urllib.urlencode(sentQueryParams)
|
|
||||||
|
|
||||||
elif method in ['POST', 'PUT', 'DELETE']:
|
elif method in ['POST', 'PUT', 'DELETE']:
|
||||||
|
|
||||||
@ -95,7 +98,7 @@ class ApiClient:
|
|||||||
def sanitizeForSerialization(self, obj):
|
def sanitizeForSerialization(self, obj):
|
||||||
"""Dump an object into JSON for POSTing."""
|
"""Dump an object into JSON for POSTing."""
|
||||||
|
|
||||||
if not obj:
|
if type(obj) == type(None):
|
||||||
return None
|
return None
|
||||||
elif type(obj) in [str, int, long, float, bool]:
|
elif type(obj) in [str, int, long, float, bool]:
|
||||||
return obj
|
return obj
|
||||||
@ -164,6 +167,8 @@ class ApiClient:
|
|||||||
value = attrType(value)
|
value = attrType(value)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
value = unicode(value)
|
value = unicode(value)
|
||||||
|
except TypeError:
|
||||||
|
value = value
|
||||||
setattr(instance, attr, value)
|
setattr(instance, attr, value)
|
||||||
elif (attrType == 'datetime'):
|
elif (attrType == 'datetime'):
|
||||||
setattr(instance, attr, datetime.datetime.strptime(value[:-5],
|
setattr(instance, attr, datetime.datetime.strptime(value[:-5],
|
||||||
|
@ -43,15 +43,19 @@ class ApiClient:
|
|||||||
|
|
||||||
data = None
|
data = None
|
||||||
|
|
||||||
if method == 'GET':
|
|
||||||
|
|
||||||
if queryParams:
|
if queryParams:
|
||||||
# Need to remove None values, these should not be sent
|
# Need to remove None values, these should not be sent
|
||||||
sentQueryParams = {}
|
sentQueryParams = {}
|
||||||
for param, value in queryParams.items():
|
for param, value in queryParams.items():
|
||||||
if value != None:
|
if value != None:
|
||||||
sentQueryParams[param] = value
|
sentQueryParams[param] = value
|
||||||
url = url + '?' + urllib.parse.urlencode(sentQueryParams)
|
url = url + '?' + urllib.parse.urlencode(sentQueryParams)
|
||||||
|
|
||||||
|
if method in ['GET']:
|
||||||
|
|
||||||
|
#Options to add statements later on and for compatibility
|
||||||
|
pass
|
||||||
|
|
||||||
elif method in ['POST', 'PUT', 'DELETE']:
|
elif method in ['POST', 'PUT', 'DELETE']:
|
||||||
|
|
||||||
@ -98,7 +102,7 @@ class ApiClient:
|
|||||||
def sanitizeForSerialization(self, obj):
|
def sanitizeForSerialization(self, obj):
|
||||||
"""Dump an object into JSON for POSTing."""
|
"""Dump an object into JSON for POSTing."""
|
||||||
|
|
||||||
if not obj:
|
if type(obj) == type(None):
|
||||||
return None
|
return None
|
||||||
elif type(obj) in [str, int, float, bool]:
|
elif type(obj) in [str, int, float, bool]:
|
||||||
return obj
|
return obj
|
||||||
@ -159,6 +163,8 @@ class ApiClient:
|
|||||||
value = attrType(value)
|
value = attrType(value)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
value = unicode(value)
|
value = unicode(value)
|
||||||
|
except TypeError:
|
||||||
|
value = value
|
||||||
setattr(instance, attr, value)
|
setattr(instance, attr, value)
|
||||||
elif (attrType == 'datetime'):
|
elif (attrType == 'datetime'):
|
||||||
setattr(instance, attr, datetime.datetime.strptime(value[:-5],
|
setattr(instance, attr, datetime.datetime.strptime(value[:-5],
|
||||||
|
1092
src/main/resources/swagger-static/assets/css/bootstrap-responsive.css
vendored
Normal file
1092
src/main/resources/swagger-static/assets/css/bootstrap-responsive.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6057
src/main/resources/swagger-static/assets/css/bootstrap.css
vendored
Normal file
6057
src/main/resources/swagger-static/assets/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
src/main/resources/swagger-static/assets/css/site.css
Normal file
1
src/main/resources/swagger-static/assets/css/site.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
site.css
|
135
src/main/resources/swagger-static/assets/css/style.css
Normal file
135
src/main/resources/swagger-static/assets/css/style.css
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
.line-numbers {
|
||||||
|
margin-right: 1.0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding-bottom: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column_header_name {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column_header_path {
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column_header_name .column_header_param_type .column_header_data_type .column_header_return_type {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expandable {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main_content {
|
||||||
|
margin-top: 80px;
|
||||||
|
margin-left: 25px;
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: fixed;
|
||||||
|
text-align: left;
|
||||||
|
background-color: black;
|
||||||
|
float: left;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 70px auto;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.2) 0 2px 8px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar h1 a {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar h1#logo a {
|
||||||
|
width: auto;
|
||||||
|
display: block;
|
||||||
|
clear: none;
|
||||||
|
float: left;
|
||||||
|
background-position: left;;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar h1#logo span {
|
||||||
|
display: block;
|
||||||
|
clear: none;
|
||||||
|
float: left;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar h1#logo a span.light {
|
||||||
|
color: #ffc97a;
|
||||||
|
color: #666666;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav {
|
||||||
|
float: none;
|
||||||
|
clear: both;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: block;
|
||||||
|
float: right;
|
||||||
|
clear: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav li {
|
||||||
|
float: left;
|
||||||
|
clear: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px 10px;
|
||||||
|
border-right: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav li:first-child, .top-bar ul#nav li.first {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav li:last-child, .top-bar ul#nav li.last {
|
||||||
|
padding-right: 0;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav li {
|
||||||
|
border: none;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav li a {
|
||||||
|
display: block;
|
||||||
|
padding: 8px 10px 8px 10px;
|
||||||
|
color: #999999;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav li a.strong {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav li a:active, .top-bar ul#nav li a.active, .top-bar ul#nav li a:hover {
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-o-border-radius: 4px;
|
||||||
|
-ms-border-radius: 4px;
|
||||||
|
-khtml-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-image: -webkit-gradient(linear, 0% 100%, 0% 0%, color-stop(0%, #ff5401), color-stop(100%, #ffa014));
|
||||||
|
background-image: -moz-linear-gradient(bottom, #ff5401 0%, #ffa014 100%);
|
||||||
|
background-image: linear-gradient(bottom, #ff5401 0%, #ffa014 100%);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar ul#nav:hover li {
|
||||||
|
border-color: #222222;
|
||||||
|
}
|
BIN
src/main/resources/swagger-static/assets/images/logo.png
Normal file
BIN
src/main/resources/swagger-static/assets/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
2159
src/main/resources/swagger-static/assets/js/bootstrap.js
vendored
Normal file
2159
src/main/resources/swagger-static/assets/js/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
src/main/resources/swagger-static/assets/js/jquery-1.8.3.min.js
vendored
Normal file
2
src/main/resources/swagger-static/assets/js/jquery-1.8.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
41
src/main/resources/swagger-static/index.mustache
Normal file
41
src/main/resources/swagger-static/index.mustache
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="assets/css/bootstrap.css" media="screen">
|
||||||
|
<link rel="stylesheet" type="text/css" href="assets/css/bootstrap-responsive.css" media="screen">
|
||||||
|
<link rel="stylesheet" type="text/css" href="assets/css/style.css">
|
||||||
|
|
||||||
|
<title>REST API v1.1 Resources | Twitter Developers</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<div class="top-bar">
|
||||||
|
<h1 id="logo"><a class="logo" href="/"><span>Swagger</span><span class="light">API Docs</span></a></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="main_content">
|
||||||
|
<h1>API Documentation</h1>
|
||||||
|
{{#apis}}
|
||||||
|
<h2>{{className}}</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th class="column_header_name">Name</th>
|
||||||
|
<th class="column_header_path">Resource</th>
|
||||||
|
<th class="column_header_notes">Notes</th>
|
||||||
|
</tr>
|
||||||
|
{{#operations}}
|
||||||
|
{{#operation}}
|
||||||
|
<tr>
|
||||||
|
<td><a href="operations/{{{className}}}.html#{{{nickname}}}">{{{nickname}}}</a></td>
|
||||||
|
<td>{{path}}</td>
|
||||||
|
<td>{{{summary}}}{{#notes}}<div id="{{className}}_{{nickname}}" class="operation expandable">{{notes}}</div>{{/notes}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/operation}}
|
||||||
|
{{/operations}}
|
||||||
|
</table>
|
||||||
|
{{/apis}}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
82
src/main/resources/swagger-static/operation.mustache
Normal file
82
src/main/resources/swagger-static/operation.mustache
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="../assets/css/bootstrap.css" media="screen">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../assets/css/bootstrap-responsive.css" media="screen">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../assets/css/style.css">
|
||||||
|
|
||||||
|
<title>REST API v1.1 Resources | Twitter Developers</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<div class="top-bar">
|
||||||
|
<h1 id="logo"><a class="logo" href="/"><span>Swagger</span><span class="light">API Docs</span></a></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="main_content">
|
||||||
|
<h1>{{classname}}</h1>
|
||||||
|
{{#operations}}
|
||||||
|
{{#operation}}
|
||||||
|
<a name="{{nickname}}"></a>
|
||||||
|
<h2>{{nickname}}</h2>
|
||||||
|
<h3>{{httpMethod}}: {{path}}</h3>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th class="column_header_name">parameter</th>
|
||||||
|
<th class="column_header_param_type">param type</th>
|
||||||
|
<th class="column_header_data_type">data type</th>
|
||||||
|
<th class="column_header_return_type">response type</th>
|
||||||
|
<th class="column_header_notes">Description</th>
|
||||||
|
</tr>
|
||||||
|
<!-- body params -->
|
||||||
|
{{#bodyParams}}
|
||||||
|
<tr>
|
||||||
|
<td>{{paramName}}<br/>{{#required}}required{{/required}}{{^required}}optional{{/required}}</td>
|
||||||
|
<td>body</td>
|
||||||
|
<td>{{swaggerDataType}}{{#allowMultiple}}*{{/allowMultiple}}</td>
|
||||||
|
<td>{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}-{{/returnType}}</td>
|
||||||
|
<td>{{description}}{{#notes}}<br/><div id="{{className}}_{{nickname}}" class="operation expandable">{{notes}}</div>{{/notes}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/bodyParams}}
|
||||||
|
|
||||||
|
<!-- path params -->
|
||||||
|
{{#pathParams}}
|
||||||
|
<tr>
|
||||||
|
<td>{{paramName}}<br/>{{#required}}required{{/required}}{{^required}}optional{{/required}}</td>
|
||||||
|
<td>path</td>
|
||||||
|
<td>{{swaggerDataType}}{{#allowMultiple}}*{{/allowMultiple}}</td>
|
||||||
|
<td>{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}-{{/returnType}}</td>
|
||||||
|
<td>{{description}}{{#notes}}<br/><div id="{{className}}_{{nickname}}" class="operation expandable">{{notes}}</div>{{/notes}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/pathParams}}
|
||||||
|
|
||||||
|
<!-- query params -->
|
||||||
|
{{#queryParams}}
|
||||||
|
<tr>
|
||||||
|
<td>{{paramName}}<br/>{{#required}}required{{/required}}{{^required}}optional{{/required}}</td>
|
||||||
|
<td>query</td>
|
||||||
|
<td>{{swaggerDataType}}{{#allowMultiple}}*{{/allowMultiple}}</td>
|
||||||
|
<td>{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}-{{/returnType}}</td>
|
||||||
|
<td>{{description}}{{#notes}}<br/><div id="{{className}}_{{nickname}}" class="operation expandable">{{notes}}</div>{{/notes}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/queryParams}}
|
||||||
|
|
||||||
|
<!-- header params -->
|
||||||
|
{{#headerParams}}
|
||||||
|
<tr>
|
||||||
|
<td>{{paramName}}<br/>{{#required}}required{{/required}}{{^required}}optional{{/required}}</td>
|
||||||
|
<td>header</td>
|
||||||
|
<td>{{swaggerDataType}}{{#allowMultiple}}*{{/allowMultiple}}</td>
|
||||||
|
<td>{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}-{{/returnType}}</td>
|
||||||
|
<td>{{description}}{{#notes}}<br/><div id="{{className}}_{{nickname}}" class="operation expandable">{{notes}}</div>{{/notes}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/headerParams}}
|
||||||
|
</table>
|
||||||
|
{{/operation}}
|
||||||
|
{{/operations}}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -55,15 +55,15 @@ class BasicJavaGenerator extends BasicGenerator {
|
|||||||
// location of templates
|
// location of templates
|
||||||
override def templateDir = "Java"
|
override def templateDir = "Java"
|
||||||
|
|
||||||
|
// where to write generated code
|
||||||
|
override def destinationDir = "generated-code/java/src/main/java"
|
||||||
|
|
||||||
// template used for models
|
// template used for models
|
||||||
modelTemplateFiles += "model.mustache" -> ".java"
|
modelTemplateFiles += "model.mustache" -> ".java"
|
||||||
|
|
||||||
// template used for models
|
// template used for models
|
||||||
apiTemplateFiles += "api.mustache" -> ".java"
|
apiTemplateFiles += "api.mustache" -> ".java"
|
||||||
|
|
||||||
// where to write generated code
|
|
||||||
override def destinationDir = "src/test/java"
|
|
||||||
|
|
||||||
override def reservedWords = Set("abstract", "continue", "for", "new", "switch", "assert",
|
override def reservedWords = Set("abstract", "continue", "for", "new", "switch", "assert",
|
||||||
"default", "if", "package", "synchronized", "boolean", "do", "goto", "private",
|
"default", "if", "package", "synchronized", "boolean", "do", "goto", "private",
|
||||||
"this", "break", "double", "implements", "protected", "throw", "byte", "else",
|
"this", "break", "double", "implements", "protected", "throw", "byte", "else",
|
||||||
@ -168,4 +168,12 @@ class BasicJavaGenerator extends BasicGenerator {
|
|||||||
throw new Exception("reserved word " + "\"" + word + "\" not allowed")
|
throw new Exception("reserved word " + "\"" + word + "\" not allowed")
|
||||||
else word
|
else word
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// supporting classes
|
||||||
|
// supporting classes
|
||||||
|
override def supportingFiles =
|
||||||
|
List(
|
||||||
|
("apiInvoker.mustache", destinationDir + java.io.File.separator + invokerPackage.get.replaceAll("\\.", java.io.File.separator) + java.io.File.separator, "ApiInvoker.java"),
|
||||||
|
("apiException.mustache", destinationDir + java.io.File.separator + invokerPackage.get.replaceAll("\\.", java.io.File.separator) + java.io.File.separator, "ApiException.java"),
|
||||||
|
("pom.mustache", "generated-code/java", "pom.xml"))
|
||||||
}
|
}
|
@ -62,7 +62,7 @@ class SwaggerSpecValidator(private val doc: ResourceListing,
|
|||||||
}
|
}
|
||||||
|
|
||||||
def validateResponseModels(subDocs: List[ApiListing]) = {
|
def validateResponseModels(subDocs: List[ApiListing]) = {
|
||||||
val validModelNames = CoreUtils.extractAllModels2(subDocs).map(m => m._1).toSet
|
val validModelNames = CoreUtils.extractAllModels(subDocs).map(m => m._1).toSet
|
||||||
val requiredModels = new HashSet[String]
|
val requiredModels = new HashSet[String]
|
||||||
subDocs.foreach(subDoc => {
|
subDocs.foreach(subDoc => {
|
||||||
if (subDoc.apis != null) {
|
if (subDoc.apis != null) {
|
||||||
|
@ -25,11 +25,11 @@ import com.wordnik.swagger.codegen.spec.SwaggerSpec._
|
|||||||
import scala.io.Source
|
import scala.io.Source
|
||||||
|
|
||||||
object CoreUtils {
|
object CoreUtils {
|
||||||
def extractAllModels2(apis: List[ApiListing]): Map[String, Model] = {
|
def extractAllModels(apis: List[ApiListing]): Map[String, Model] = {
|
||||||
val modelObjects = new HashMap[String, Model]
|
val modelObjects = new HashMap[String, Model]
|
||||||
apis.foreach(api => {
|
apis.foreach(api => {
|
||||||
for ((nm, model) <- extractApiModels(api)) modelObjects += nm -> model
|
for ((nm, model) <- extractApiModels(api)) modelObjects += nm -> model
|
||||||
if (api.models != null) api.models.foreach(model => modelObjects += model._1 -> model._2)
|
api.models.foreach(model => modelObjects += model._1 -> model._2)
|
||||||
})
|
})
|
||||||
modelObjects.toMap
|
modelObjects.toMap
|
||||||
}
|
}
|
||||||
@ -38,49 +38,13 @@ object CoreUtils {
|
|||||||
val modelNames = new HashSet[String]
|
val modelNames = new HashSet[String]
|
||||||
modelNames += op.responseClass
|
modelNames += op.responseClass
|
||||||
// POST, PUT, DELETE body
|
// POST, PUT, DELETE body
|
||||||
if (op.parameters != null) {
|
op.parameters.filter(p => p.paramType == "body")
|
||||||
op.parameters.filter(p => p.paramType == "body")
|
.foreach(p => modelNames += p.dataType)
|
||||||
.foreach(p => modelNames += p.dataType)
|
|
||||||
}
|
|
||||||
val baseNames = (for (modelName <- (modelNames.toList))
|
val baseNames = (for (modelName <- (modelNames.toList))
|
||||||
yield (extractBasePartFromType(modelName))).toSet
|
yield (extractBasePartFromType(modelName))).toSet
|
||||||
baseNames.toSet
|
baseNames.toSet
|
||||||
}
|
}
|
||||||
|
|
||||||
def extractModelNames2(modelObjects: Map[String, Model], ep: Operation): Set[String] = {
|
|
||||||
val modelNames = new HashSet[String]
|
|
||||||
|
|
||||||
modelNames += ep.responseClass
|
|
||||||
// POST, PUT, DELETE body
|
|
||||||
if (ep.parameters != null)
|
|
||||||
ep.parameters.filter(p => p.paramType == "body")
|
|
||||||
.foreach(p => modelNames += p.dataType)
|
|
||||||
|
|
||||||
val baseNames = (for (modelName <- (modelNames.toList))
|
|
||||||
yield (extractBasePartFromType(modelName))).toSet
|
|
||||||
|
|
||||||
// get complex models from base
|
|
||||||
val requiredModels = modelObjects.filter(obj => baseNames.contains(obj._1))
|
|
||||||
|
|
||||||
val subNames = new HashSet[String]
|
|
||||||
// look inside top-level models
|
|
||||||
requiredModels.map(model => {
|
|
||||||
// add top level model
|
|
||||||
subNames += model._1
|
|
||||||
model._2.properties.foreach(prop => {
|
|
||||||
val subObject = prop._2
|
|
||||||
if (containers.contains(subObject.`type`)) {
|
|
||||||
subObject.items match {
|
|
||||||
case Some(item) => subNames += item.ref.getOrElse(item.`type`)
|
|
||||||
case None =>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else subNames += subObject.`type`
|
|
||||||
})
|
|
||||||
})
|
|
||||||
subNames.toSet
|
|
||||||
}
|
|
||||||
|
|
||||||
def extractBasePartFromType(datatype: String): String = {
|
def extractBasePartFromType(datatype: String): String = {
|
||||||
val ComplexTypeMatcher = ".*\\[(.*)\\].*".r
|
val ComplexTypeMatcher = ".*\\[(.*)\\].*".r
|
||||||
datatype match {
|
datatype match {
|
||||||
@ -93,21 +57,16 @@ object CoreUtils {
|
|||||||
val modelNames = new HashSet[String]
|
val modelNames = new HashSet[String]
|
||||||
val modelObjects = new HashMap[String, Model]
|
val modelObjects = new HashMap[String, Model]
|
||||||
// return types
|
// return types
|
||||||
if(sd.apis != null){
|
sd.apis.foreach(api =>
|
||||||
sd.apis.foreach(api => {
|
api.operations.foreach(op => {
|
||||||
if (api.operations != null)
|
modelNames += op.responseClass
|
||||||
api.operations.foreach(op => {
|
// POST, PUT, DELETE body
|
||||||
modelNames += op.responseClass
|
op.parameters.filter(p => p.paramType == "body")
|
||||||
// POST, PUT, DELETE body
|
.foreach(p => modelNames += p.dataType)
|
||||||
if(op.parameters != null)
|
|
||||||
op.parameters.filter(p => p.paramType == "body")
|
|
||||||
.foreach(p => modelNames += p.dataType)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
)
|
||||||
if(sd.models != null)
|
for ((name, m) <- sd.models)
|
||||||
for ((name, m) <- sd.models)
|
modelObjects += name -> m
|
||||||
modelObjects += name -> m
|
|
||||||
|
|
||||||
// extract all base model names, strip away Containers like List[] and primitives
|
// extract all base model names, strip away Containers like List[] and primitives
|
||||||
val baseNames = (for (modelName <- (modelNames.toList filterNot primitives.contains))
|
val baseNames = (for (modelName <- (modelNames.toList filterNot primitives.contains))
|
||||||
@ -118,40 +77,47 @@ object CoreUtils {
|
|||||||
|
|
||||||
val subNames = new HashSet[String]
|
val subNames = new HashSet[String]
|
||||||
// look inside top-level models
|
// look inside top-level models
|
||||||
requiredModels.map(model => {
|
recurseModels(requiredModels.toMap, modelObjects.toMap, subNames)
|
||||||
model._2.properties.foreach(prop => {
|
|
||||||
val subObject = prop._2
|
|
||||||
if (containers.contains(subObject.`type`)) {
|
|
||||||
subObject.items match {
|
|
||||||
case Some(subItem) => {
|
|
||||||
val sn = subItem.ref.getOrElse(subItem.`type`)
|
|
||||||
if(sn != null)
|
|
||||||
subNames += sn
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
} else subNames += subObject.`type`
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// look inside submodels
|
|
||||||
modelObjects.filter(obj => subNames.contains(obj._1)).foreach(model => {
|
|
||||||
model._2.properties.foreach(prop => {
|
|
||||||
val subObject = prop._2
|
|
||||||
if (containers.contains(subObject.`type`)) {
|
|
||||||
subObject.items match {
|
|
||||||
case Some(subItem) => {
|
|
||||||
val sn = subItem.ref.getOrElse(subItem.`type`)
|
|
||||||
if(sn != null)
|
|
||||||
subNames += sn
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
} else subNames += subObject.`type`
|
|
||||||
})
|
|
||||||
})
|
|
||||||
val subModels = modelObjects.filter(obj => subNames.contains(obj._1))
|
val subModels = modelObjects.filter(obj => subNames.contains(obj._1))
|
||||||
val allModels = requiredModels ++ subModels
|
val allModels = requiredModels ++ subModels
|
||||||
allModels.filter(m => primitives.contains(m._1) == false).toMap
|
allModels.filter(m => primitives.contains(m._1) == false).toMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def recurseModels(requiredModels: Map[String, Model], allModels: Map[String, Model], subNames: HashSet[String]) = {
|
||||||
|
requiredModels.map(m => recurseModel(m._2, allModels, subNames))
|
||||||
|
}
|
||||||
|
|
||||||
|
def recurseModel(model: Model, allModels: Map[String, Model], subNames: HashSet[String]): Unit = {
|
||||||
|
model.properties.foreach(prop => {
|
||||||
|
val subObject = prop._2
|
||||||
|
val propertyName = containers.contains(subObject.`type`) match {
|
||||||
|
case true => subObject.items match {
|
||||||
|
case Some(subItem) => {
|
||||||
|
Option(subItem.ref.getOrElse(subItem.`type`)) match {
|
||||||
|
case Some(sn) => Some(sn)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
case false => Some(subObject.`type`)
|
||||||
|
}
|
||||||
|
propertyName match {
|
||||||
|
case Some(property) => subNames.contains(property) match {
|
||||||
|
case false => {
|
||||||
|
allModels.containsKey(property) match {
|
||||||
|
case true => {
|
||||||
|
recurseModel(allModels(property), allModels, subNames)
|
||||||
|
}
|
||||||
|
case false =>
|
||||||
|
}
|
||||||
|
subNames += property
|
||||||
|
}
|
||||||
|
case true =>
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
@ -233,7 +233,6 @@ class BasicScalaGeneratorTest extends FlatSpec with ShouldMatchers {
|
|||||||
m("returnBaseType") should be (Some("Pet"))
|
m("returnBaseType") should be (Some("Pet"))
|
||||||
|
|
||||||
// problem here
|
// problem here
|
||||||
println("the operation has response class " + operation.responseClass)
|
|
||||||
m("returnType") should be (Some("List[Pet]"))
|
m("returnType") should be (Some("List[Pet]"))
|
||||||
m("returnTypeIsPrimitive") should be (None)
|
m("returnTypeIsPrimitive") should be (None)
|
||||||
m("pathParams").asInstanceOf[List[_]].size should be (0)
|
m("pathParams").asInstanceOf[List[_]].size should be (0)
|
||||||
|
265
src/test/scala/CoreUtilsTest.scala
Normal file
265
src/test/scala/CoreUtilsTest.scala
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
import com.wordnik.swagger.codegen.util.CoreUtils
|
||||||
|
|
||||||
|
import com.wordnik.swagger.model._
|
||||||
|
import com.wordnik.swagger.codegen.util._
|
||||||
|
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.scalatest.junit.JUnitRunner
|
||||||
|
import org.scalatest.FlatSpec
|
||||||
|
import org.scalatest.matchers.ShouldMatchers
|
||||||
|
|
||||||
|
import org.json4s.jackson.JsonMethods._
|
||||||
|
import org.json4s.jackson.Serialization.read
|
||||||
|
|
||||||
|
import scala.collection.mutable.LinkedHashMap
|
||||||
|
|
||||||
|
@RunWith(classOf[JUnitRunner])
|
||||||
|
class CoreUtilsTest extends FlatSpec with ShouldMatchers {
|
||||||
|
sys.props += "fileMap" -> "src/test/resources/petstore"
|
||||||
|
|
||||||
|
behavior of "CoreUtils"
|
||||||
|
|
||||||
|
it should "verify models are extracted" in {
|
||||||
|
val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json")
|
||||||
|
val apis = ApiExtractor.extractApiOperations("src/test/resources/petstore", resourceListing.apis)
|
||||||
|
|
||||||
|
val cu = CoreUtils.extractAllModels(apis)
|
||||||
|
cu.size should be (5)
|
||||||
|
|
||||||
|
(cu.keys.toSet & Set("User", "Tag", "Pet", "Category", "Order")).size should be (5)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "verify operation names" in {
|
||||||
|
val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json")
|
||||||
|
val apis = ApiExtractor.extractApiOperations("src/test/resources/petstore", resourceListing.apis)
|
||||||
|
|
||||||
|
val petApi = apis.filter(api => api.resourcePath == "/pet").head
|
||||||
|
val eps = petApi.apis.map(api => (api.path, api)).toMap
|
||||||
|
val ops = eps("/pet.{format}").operations.map(ep => (ep.nickname, ep)).toMap
|
||||||
|
|
||||||
|
ops.size should be (2)
|
||||||
|
|
||||||
|
(ops.keys.toSet & Set("addPet", "updatePet")).size should be (2)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "find required models" in {
|
||||||
|
val apis = CoreUtilsTest.sampleApis1
|
||||||
|
val models = CoreUtils.extractApiModels(apis.head)
|
||||||
|
models.size should be (5)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "find required models from a nested list" in {
|
||||||
|
val apis = CoreUtilsTest.sampleApis2
|
||||||
|
val models = CoreUtils.extractApiModels(apis.head)
|
||||||
|
models.size should be (5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CoreUtilsTest {
|
||||||
|
implicit val formats = SwaggerSerializers.formats
|
||||||
|
|
||||||
|
def sampleApis1 = {
|
||||||
|
parse("""
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"apiVersion": "0.2",
|
||||||
|
"swaggerVersion": "1.1",
|
||||||
|
"basePath": "http://api.helloreverb.com/api",
|
||||||
|
"resourcePath": "/mysteries",
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "/mysteries.{format}/{petId}",
|
||||||
|
"description": "As the name suggests",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"httpMethod": "GET",
|
||||||
|
"summary": "You find amazing htings here",
|
||||||
|
"responseClass": "DeepMystery",
|
||||||
|
"nickname": "getMysteryById",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"description": "ID of mystery",
|
||||||
|
"paramType": "path",
|
||||||
|
"required": true,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"MysteryList": {
|
||||||
|
"id": "MysteryList",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
|
"mysteries": {
|
||||||
|
"items":{
|
||||||
|
"$ref":"Mystery1"
|
||||||
|
},
|
||||||
|
"type":"Array"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DeepMystery": {
|
||||||
|
"id": "DeepMystery",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "Mystery1"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery1": {
|
||||||
|
"id": "Mystery1",
|
||||||
|
"properties": {
|
||||||
|
"mystery2": {
|
||||||
|
"type": "Mystery2"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery2": {
|
||||||
|
"id": "Mystery2",
|
||||||
|
"properties": {
|
||||||
|
"mystery3": {
|
||||||
|
"type": "Mystery3"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery3": {
|
||||||
|
"id": "Mystery3",
|
||||||
|
"properties": {
|
||||||
|
"mystery4": {
|
||||||
|
"type": "Mystery4"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery4": {
|
||||||
|
"id": "Mystery4",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
""").extract[List[ApiListing]]
|
||||||
|
}
|
||||||
|
|
||||||
|
def sampleApis2 = {
|
||||||
|
parse("""
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"apiVersion": "0.2",
|
||||||
|
"swaggerVersion": "1.1",
|
||||||
|
"basePath": "http://api.helloreverb.com/api",
|
||||||
|
"resourcePath": "/mysteries",
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "/mysteries.{format}/{petId}",
|
||||||
|
"description": "As the name suggests",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"httpMethod": "GET",
|
||||||
|
"summary": "You find amazing htings here",
|
||||||
|
"responseClass": "MysteryList",
|
||||||
|
"nickname": "getMysteryById",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"description": "ID of mystery",
|
||||||
|
"paramType": "path",
|
||||||
|
"required": true,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"MysteryList": {
|
||||||
|
"id": "MysteryList",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
|
"mystery1": {
|
||||||
|
"type":"Mystery1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery1": {
|
||||||
|
"id": "Mystery1",
|
||||||
|
"properties": {
|
||||||
|
"mystery2": {
|
||||||
|
"type": "Mystery2"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery2": {
|
||||||
|
"id": "Mystery2",
|
||||||
|
"properties": {
|
||||||
|
"mystery3List": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "Mystery3"
|
||||||
|
},
|
||||||
|
"type": "List"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery3": {
|
||||||
|
"id": "Mystery3",
|
||||||
|
"properties": {
|
||||||
|
"mystery4": {
|
||||||
|
"type": "Mystery4"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mystery4": {
|
||||||
|
"id": "Mystery4",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
""").extract[List[ApiListing]]
|
||||||
|
}
|
||||||
|
}
|
@ -59,7 +59,6 @@ class ResourceListingValidationTest extends FlatSpec with ShouldMatchers {
|
|||||||
"""
|
"""
|
||||||
parse(jsonString).extract[ResourceListing] match {
|
parse(jsonString).extract[ResourceListing] match {
|
||||||
case e: ResourceListing => {
|
case e: ResourceListing => {
|
||||||
println(e)
|
|
||||||
e.apis.size should be (2)
|
e.apis.size should be (2)
|
||||||
}
|
}
|
||||||
case _ => fail("didn't parse the underlying apis")
|
case _ => fail("didn't parse the underlying apis")
|
||||||
|
@ -62,33 +62,3 @@ class ApiExtractorTest extends FlatSpec with ShouldMatchers {
|
|||||||
getOrderById.errorResponses.size should be (2)
|
getOrderById.errorResponses.size should be (2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RunWith(classOf[JUnitRunner])
|
|
||||||
class CoreUtilsTest extends FlatSpec with ShouldMatchers {
|
|
||||||
sys.props += "fileMap" -> "src/test/resources/petstore"
|
|
||||||
|
|
||||||
behavior of "CoreUtils"
|
|
||||||
|
|
||||||
it should "verify models are extracted" in {
|
|
||||||
val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json")
|
|
||||||
val apis = ApiExtractor.extractApiOperations("src/test/resources/petstore", resourceListing.apis)
|
|
||||||
|
|
||||||
val cu = CoreUtils.extractAllModels2(apis)
|
|
||||||
cu.size should be (5)
|
|
||||||
|
|
||||||
(cu.keys.toSet & Set("User", "Tag", "Pet", "Category", "Order")).size should be (5)
|
|
||||||
}
|
|
||||||
|
|
||||||
it should "verify operation names" in {
|
|
||||||
val resourceListing = ResourceExtractor.fetchListing("src/test/resources/petstore/resources.json")
|
|
||||||
val apis = ApiExtractor.extractApiOperations("src/test/resources/petstore", resourceListing.apis)
|
|
||||||
|
|
||||||
val petApi = apis.filter(api => api.resourcePath == "/pet").head
|
|
||||||
val eps = petApi.apis.map(api => (api.path, api)).toMap
|
|
||||||
val ops = eps("/pet.{format}").operations.map(ep => (ep.nickname, ep)).toMap
|
|
||||||
|
|
||||||
ops.size should be (2)
|
|
||||||
|
|
||||||
(ops.keys.toSet & Set("addPet", "updatePet")).size should be (2)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user