Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04fed3d4d5 | ||
|
|
1ead6614ba | ||
|
|
887e63464d | ||
|
|
47e5d5e56e | ||
|
|
c505c1e88e | ||
|
|
6a8c04c031 | ||
|
|
33f68a7f41 | ||
|
|
c5af8676e5 | ||
|
|
618898cb09 | ||
|
|
36bdcc57d9 | ||
|
|
eb418c07f5 | ||
|
|
9a265fbbc3 | ||
|
|
cf32d6cf29 | ||
|
|
9d216e3dc2 |
27
README.adoc
@@ -9,25 +9,22 @@ image:https://travis-ci.org/Swagger2Markup/swagger2markup.svg?branch=master["Bui
|
||||
|
||||
The primary goal of this project is to *simplify the generation of an up-to-date RESTful API documentation by combining documentation that's been hand-written with auto-generated API documentation* produced by https://github.com/swagger-api[Swagger]. The result is intended to be an *up-to-date, easy-to-read, on- and offline user guide*, comparable to https://developer.github.com/v3/[GitHub's API documentation]. The output of Swagger2Markup can be used as an alternative to https://github.com/swagger-api/swagger-ui[swagger-ui] and can be served as static content.
|
||||
|
||||
Swagger2Markup converts a Swagger JSON or YAML file into several *AsciiDoc* or *GitHub Flavored Markdown* documents which can be combined with hand-written documentation. The Swagger source file can be located locally or remotely via HTTP. Swagger2Markup supports the Swagger 1.2 and 2.0 specification. Internally it uses the _official_ https://github.com/swagger-api/swagger-parser[swagger-parser] and my https://github.com/RobWin/markup-document-builder[markup-document-builder].
|
||||
Swagger2Markup converts a Swagger JSON or YAML file into several *AsciiDoc* or *GitHub Flavored Markdown* documents which can be combined with hand-written documentation. The Swagger source file can be located locally or remotely via HTTP. Swagger2Markup supports the Swagger 1.2 and 2.0 specification. Internally it uses the _official_ https://github.com/swagger-api/swagger-parser[swagger-parser] and my https://github.com/RobWin/markup-document-builder[markup-document-builder].
|
||||
|
||||
You can use Swagger2Markup to convert your contract-first Swagger YAML file into a human-readable format and combine it with hand-written documentation. As an alternative, you can choose the code-first approach and use Swagger2Markup together with https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-JAX-RS-Project-Setup-1.5.X[Swagger JAX-RS], https://github.com/springfox/springfox[springfox] or https://github.com/spring-projects/spring-restdocs[spring-restdocs]. If you are Gradle or Maven user, you can also use the https://github.com/RobWin/swagger2markup-gradle-plugin[Swagger2Markup Gradle Plugin] or https://github.com/redowl/swagger2markup-maven-plugin[Swagger2markup Maven Plugin].
|
||||
|
||||
http://asciidoctor.org/docs/asciidoc-writers-guide/[AsciiDoc] is preferable to Markdown as it has more features. AsciiDoc is a text document format for writing documentation, articles, books, ebooks, slideshows, web pages and blogs. AsciiDoc files can be converted to *HTML*, *PDF* and *EPUB*. AsciiDoc is much better suited for describing public APIs than *JavaDoc* or *Annotations*.
|
||||
|
||||
You can generate your HTML5, PDF and EPUB documentation via https://github.com/asciidoctor/asciidoctorj[asciidoctorj] or even better via the https://github.com/asciidoctor/asciidoctor-gradle-plugin[asciidoctor-gradle-plugin] or https://github.com/asciidoctor/asciidoctor-maven-plugin[asciidoctor-maven-plugin]. You can publish your AsciiDoc documentation using https://github.com/RobWin/asciidocular[Asciidocular]. Asciidocular is a small AngularJS web app that loads your AsciiDoc files via Ajax and renders them as a full web site.
|
||||
|
||||
Advantages:
|
||||
|
||||
* No server-side components needed to convert your AsciiDoc files into HTML
|
||||
* No build process and tools needed
|
||||
* Deployable via GitHub Pages
|
||||
* Responsive Bootswatch (Bootstrap) theme
|
||||
|
||||
You can publish your Markdown documentation using https://github.com/jbake-org/jbake[JBake], https://github.com/tomchristie/mkdocs[MkDocs] or https://github.com/rtfd/readthedocs.org[ReadTheDocs].
|
||||
You can generate your HTML5, PDF and EPUB documentation via https://github.com/asciidoctor/asciidoctorj[asciidoctorj] or even better via the https://github.com/asciidoctor/asciidoctor-gradle-plugin[asciidoctor-gradle-plugin] or https://github.com/asciidoctor/asciidoctor-maven-plugin[asciidoctor-maven-plugin].
|
||||
|
||||
The project requires at least JDK 7.
|
||||
|
||||
== Example
|
||||
|
||||
image::images/Swagger2Markup.PNG[]
|
||||
|
||||
image::images/Swagger2Markup_definitions.PNG[]
|
||||
|
||||
== Reference documentation
|
||||
- http://swagger2markup.readme.io/[Reference Documentation]
|
||||
- https://github.com/Swagger2Markup/swagger2markup/blob/master/RELEASENOTES.adoc[Release notes]
|
||||
@@ -38,11 +35,13 @@ The project requires at least JDK 7.
|
||||
|
||||
Pull requests are welcome.
|
||||
|
||||
* New feature https://github.com/Swagger2Markup/swagger2markup/issues/18[RobWin/Swagger2Markup#18] by https://github.com/sg-ad[@sg-ad]: In addition to the definitions.adoc you can also generate separate files for each definition model (ex: person.adoc, address.adoc, purchase.adoc).
|
||||
* New feature https://github.com/Swagger2Markup/swagger2markup/issues/18[Swagger2Markup/swagger2Markup#18] by https://github.com/sg-ad[@sg-ad]: In addition to the definitions.adoc you can also generate separate files for each definition model (ex: person.adoc, address.adoc, purchase.adoc).
|
||||
|
||||
* New feature https://github.com/Swagger2Markup/swagger2markup/issues/21[RobWin/Swagger2Markup#21] by https://github.com/redowl[@redowl]: Support for both reference models and composed models.
|
||||
* New feature https://github.com/Swagger2Markup/swagger2markup/issues/21[Swagger2Markup/swagger2Markup#21] by https://github.com/redowl[@redowl]: Support for both reference models and composed models.
|
||||
|
||||
* New feature https://github.com/Swagger2Markup/swagger2markup/issues/27[RobWin/Swagger2Markup#27] by https://github.com/zmitrok[@zmitrok]: Added a hook to preprocess a Swagger Model before it is converted.
|
||||
* New feature https://github.com/Swagger2Markup/swagger2markup/issues/27[Swagger2Markup/swagger2Markup#27] by https://github.com/zmitrok[@zmitrok]: Added a hook to preprocess a Swagger Model before it is converted.
|
||||
|
||||
* New feature https://github.com/Swagger2Markup/swagger2markup/issues/48[Swagger2Markup/swagger2Markup#48] by https://github.com/MeteorBoom[@MeteorBoom]: Multi language support.
|
||||
|
||||
=== Questions
|
||||
You can ask questions about Swagger2Markup in https://gitter.im/Swagger2Markup/swagger2markup[Gitter].
|
||||
|
||||
@@ -65,6 +65,13 @@
|
||||
* Enhancement #26 and #27: Added a pre-process hook to modify a Swagger Model before it is converted.
|
||||
* Bugfix #29: Tags are rendered twice
|
||||
|
||||
=== Version 0.9.0
|
||||
== Version 0.9.0
|
||||
* Updated swagger-parser from v1.0.8 to v1.0.13
|
||||
* Support for global responses and parameters
|
||||
* Support for global responses and parameters
|
||||
|
||||
=== Version 0.9.1
|
||||
* Added support to group the paths by tags or as-is
|
||||
* Added support to order the definitions by natural ordering or as-is
|
||||
|
||||
=== Version 0.9.2
|
||||
* Multi language support. Added russian.
|
||||
@@ -13,7 +13,7 @@ buildscript {
|
||||
}
|
||||
}
|
||||
description = 'swagger2markup Build'
|
||||
version = '0.9.0'
|
||||
version = '0.9.2'
|
||||
group = 'io.github.robwin'
|
||||
|
||||
apply plugin: 'java'
|
||||
@@ -53,14 +53,14 @@ dependencies {
|
||||
|
||||
dependencyManagement {
|
||||
dependencies {
|
||||
dependency "io.github.robwin:markup-document-builder:0.1.4"
|
||||
dependency "io.github.robwin:markup-document-builder:0.1.5"
|
||||
dependency "io.swagger:swagger-compat-spec-parser:1.0.13"
|
||||
dependency "commons-collections:commons-collections:3.2.1"
|
||||
dependency "commons-io:commons-io:2.4"
|
||||
dependency "junit:junit:4.11"
|
||||
dependency "org.slf4j:slf4j-api:1.7.12"
|
||||
dependency "ch.qos.logback:logback-classic:1.1.2"
|
||||
dependency "org.assertj:assertj-core:2.0.0"
|
||||
dependency "org.assertj:assertj-core:2.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ bintray {
|
||||
pkg {
|
||||
repo = 'maven'
|
||||
name = 'swagger2markup'
|
||||
websiteUrl = 'https://github.com/RobWin/swagger2markup'
|
||||
issueTrackerUrl = 'https://github.com/RobWin/swagger2markup/issues'
|
||||
vcsUrl = 'https://github.com/RobWin/swagger2markup.git'
|
||||
websiteUrl = 'https://github.com/Swagger2Markup/swagger2markup'
|
||||
issueTrackerUrl = 'https://github.com/Swagger2Markup/swagger2markup/issues'
|
||||
vcsUrl = 'https://github.com/Swagger2Markup/swagger2markup.git'
|
||||
desc = 'A Swagger to Markup (AsciiDoc and Markdown) converter.'
|
||||
licenses = ['Apache-2.0']
|
||||
version {
|
||||
@@ -76,15 +76,15 @@ publishing {
|
||||
|
||||
root.appendNode('name', 'swagger2markup')
|
||||
root.appendNode('packaging', 'jar')
|
||||
root.appendNode('url', 'https://github.com/RobWin/swagger2markup')
|
||||
root.appendNode('url', 'https://github.com/Swagger2Markup/swagger2markup')
|
||||
root.appendNode('description', 'A Swagger to Markup (AsciiDoc and Markdown) converter.')
|
||||
|
||||
def license = root.appendNode('licenses').appendNode('license')
|
||||
license.appendNode('name', 'Apache-2.0')
|
||||
license.appendNode('url', 'https://github.com/RobWin/swagger2markup/blob/master/LICENSE.txt')
|
||||
license.appendNode('url', 'https://github.com/Swagger2Markup/swagger2markup/blob/master/LICENSE.txt')
|
||||
license.appendNode('distribution', 'repo')
|
||||
|
||||
root.appendNode('scm').appendNode('url', 'https://github.com/RobWin/swagger2markup.git')
|
||||
root.appendNode('scm').appendNode('url', 'https://github.com/Swagger2Markup/swagger2markup.git')
|
||||
|
||||
def developers = root.appendNode('developers')
|
||||
devs.each {
|
||||
|
||||
BIN
images/Swagger2Markup.PNG
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
images/Swagger2Markup_definitions.PNG
Normal file
|
After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 26 KiB |
24
src/main/java/io/github/robwin/swagger2markup/GroupBy.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015 Robert Winkler
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package io.github.robwin.swagger2markup;
|
||||
|
||||
public enum GroupBy {
|
||||
AS_IS,
|
||||
TAGS
|
||||
}
|
||||
21
src/main/java/io/github/robwin/swagger2markup/Language.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package io.github.robwin.swagger2markup;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Maksim Myshkin
|
||||
*/
|
||||
public enum Language {
|
||||
EN(new Locale("en")),
|
||||
RU(new Locale("ru"));
|
||||
|
||||
private final Locale lang;
|
||||
|
||||
Language(final Locale lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
public Locale toLocale() {
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
23
src/main/java/io/github/robwin/swagger2markup/OrderBy.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015 Robert Winkler
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package io.github.robwin.swagger2markup;
|
||||
public enum OrderBy {
|
||||
AS_IS,
|
||||
NATURAL
|
||||
}
|
||||
@@ -17,16 +17,12 @@
|
||||
*
|
||||
*/
|
||||
package io.github.robwin.swagger2markup;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig;
|
||||
import io.github.robwin.swagger2markup.builder.document.*;
|
||||
import io.github.robwin.swagger2markup.utils.Consumer;
|
||||
import io.swagger.models.Swagger;
|
||||
import io.swagger.parser.SwaggerParser;
|
||||
import io.swagger.util.Json;
|
||||
import io.swagger.util.Yaml;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -40,31 +36,16 @@ import java.nio.charset.StandardCharsets;
|
||||
public class Swagger2MarkupConverter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Swagger2MarkupConverter.class);
|
||||
|
||||
private final Swagger swagger;
|
||||
private final MarkupLanguage markupLanguage;
|
||||
private final String examplesFolderPath;
|
||||
private final String schemasFolderPath;
|
||||
private final String descriptionsFolderPath;
|
||||
private final boolean separatedDefinitions;
|
||||
private final Swagger2MarkupConfig swagger2MarkupConfig;
|
||||
private static final String OVERVIEW_DOCUMENT = "overview";
|
||||
private static final String PATHS_DOCUMENT = "paths";
|
||||
private static final String DEFINITIONS_DOCUMENT = "definitions";
|
||||
|
||||
/**
|
||||
* @param markupLanguage the markup language which is used to generate the files
|
||||
* @param swagger the Swagger object
|
||||
* @param examplesFolderPath the folderPath where examples are stored
|
||||
* @param schemasFolderPath the folderPath where (XML, JSON)-Schema files are stored
|
||||
* @param descriptionsFolderPath the folderPath where descriptions are stored
|
||||
* @param separatedDefinitions create separate definition files for each model definition.
|
||||
* @param swagger2MarkupConfig the configuration
|
||||
*/
|
||||
Swagger2MarkupConverter(MarkupLanguage markupLanguage, Swagger swagger, String examplesFolderPath, String schemasFolderPath, String descriptionsFolderPath, boolean separatedDefinitions){
|
||||
this.markupLanguage = markupLanguage;
|
||||
this.swagger = swagger;
|
||||
this.examplesFolderPath = examplesFolderPath;
|
||||
this.schemasFolderPath = schemasFolderPath;
|
||||
this.descriptionsFolderPath = descriptionsFolderPath;
|
||||
this.separatedDefinitions = separatedDefinitions;
|
||||
Swagger2MarkupConverter(Swagger2MarkupConfig swagger2MarkupConfig){
|
||||
this.swagger2MarkupConfig = swagger2MarkupConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,33 +66,24 @@ public class Swagger2MarkupConverter {
|
||||
* @return a Swagger2MarkupConverter
|
||||
*/
|
||||
public static Builder from(Swagger swagger){
|
||||
Validate.notNull(swagger, "swagger must not be null!");
|
||||
Validate.notNull(swagger, "Swagger must not be null!");
|
||||
return new Builder(swagger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Swagger2MarkupConverter.Builder from a given Swagger YAML or JSON String.
|
||||
*
|
||||
* @param swagger the Swagger YAML or JSON String.
|
||||
* @param swaggerAsString the Swagger YAML or JSON String.
|
||||
* @return a Swagger2MarkupConverter
|
||||
* @throws java.io.IOException if String can not be parsed
|
||||
*/
|
||||
public static Builder fromString(String swagger) throws IOException {
|
||||
Validate.notEmpty(swagger, "swagger must not be null!");
|
||||
ObjectMapper mapper;
|
||||
if(swagger.trim().startsWith("{")) {
|
||||
mapper = Json.mapper();
|
||||
}else {
|
||||
mapper = Yaml.mapper();
|
||||
}
|
||||
JsonNode rootNode = mapper.readTree(swagger);
|
||||
|
||||
// must have swagger node set
|
||||
JsonNode swaggerNode = rootNode.get("swagger");
|
||||
if(swaggerNode == null)
|
||||
public static Builder fromString(String swaggerAsString) throws IOException {
|
||||
Validate.notEmpty(swaggerAsString, "Swagger String must not be null!");
|
||||
Swagger swagger = new SwaggerParser().parse(swaggerAsString);
|
||||
if(swagger == null)
|
||||
throw new IllegalArgumentException("Swagger String is in the wrong format");
|
||||
|
||||
return new Builder(mapper.convertValue(rootNode, Swagger.class));
|
||||
return new Builder(swagger);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,9 +115,9 @@ public class Swagger2MarkupConverter {
|
||||
* @throws IOException if a file cannot be written
|
||||
*/
|
||||
private void buildDocuments(String directory) throws IOException {
|
||||
new OverviewDocument(swagger, markupLanguage).build().writeToFile(directory, OVERVIEW_DOCUMENT, StandardCharsets.UTF_8);
|
||||
new PathsDocument(swagger, markupLanguage, examplesFolderPath, descriptionsFolderPath).build().writeToFile(directory, PATHS_DOCUMENT, StandardCharsets.UTF_8);
|
||||
new DefinitionsDocument(swagger, markupLanguage, schemasFolderPath, descriptionsFolderPath, separatedDefinitions, directory).build().writeToFile(directory, DEFINITIONS_DOCUMENT, StandardCharsets.UTF_8);
|
||||
new OverviewDocument(swagger2MarkupConfig).build().writeToFile(directory, OVERVIEW_DOCUMENT, StandardCharsets.UTF_8);
|
||||
new PathsDocument(swagger2MarkupConfig).build().writeToFile(directory, PATHS_DOCUMENT, StandardCharsets.UTF_8);
|
||||
new DefinitionsDocument(swagger2MarkupConfig, directory).build().writeToFile(directory, DEFINITIONS_DOCUMENT, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,10 +125,10 @@ public class Swagger2MarkupConverter {
|
||||
|
||||
* @return a the document as a String
|
||||
*/
|
||||
private String buildDocuments() throws IOException {
|
||||
return new OverviewDocument(swagger, markupLanguage).build().toString()
|
||||
.concat(new PathsDocument(swagger, markupLanguage, examplesFolderPath, schemasFolderPath).build().toString()
|
||||
.concat(new DefinitionsDocument(swagger, markupLanguage, schemasFolderPath, schemasFolderPath, false, null).build().toString()));
|
||||
private String buildDocuments() {
|
||||
return new OverviewDocument(swagger2MarkupConfig).build().toString()
|
||||
.concat(new PathsDocument(swagger2MarkupConfig).build().toString()
|
||||
.concat(new DefinitionsDocument(swagger2MarkupConfig, null).build().toString()));
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +138,10 @@ public class Swagger2MarkupConverter {
|
||||
private String schemasFolderPath;
|
||||
private String descriptionsFolderPath;
|
||||
private boolean separatedDefinitions;
|
||||
private GroupBy pathsGroupedBy = GroupBy.AS_IS;
|
||||
private OrderBy definitionsOrderedBy = OrderBy.NATURAL;
|
||||
private MarkupLanguage markupLanguage = MarkupLanguage.ASCIIDOC;
|
||||
private Language outputLanguage = Language.EN;
|
||||
|
||||
/**
|
||||
* Creates a Builder using a given Swagger source.
|
||||
@@ -190,7 +165,9 @@ public class Swagger2MarkupConverter {
|
||||
}
|
||||
|
||||
public Swagger2MarkupConverter build(){
|
||||
return new Swagger2MarkupConverter(markupLanguage, swagger, examplesFolderPath, schemasFolderPath, descriptionsFolderPath, separatedDefinitions);
|
||||
return new Swagger2MarkupConverter(new Swagger2MarkupConfig(swagger, markupLanguage, examplesFolderPath,
|
||||
schemasFolderPath, descriptionsFolderPath, separatedDefinitions, pathsGroupedBy, definitionsOrderedBy,
|
||||
outputLanguage));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,6 +225,7 @@ public class Swagger2MarkupConverter {
|
||||
|
||||
/**
|
||||
* Customize the Swagger data in any useful way
|
||||
*
|
||||
* @param preProcessor function object to mutate the swagger object
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
@@ -255,6 +233,39 @@ public class Swagger2MarkupConverter {
|
||||
preProcessor.accept(this.swagger);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the paths should be grouped by tags or stay as-is.
|
||||
*
|
||||
* @param pathsGroupedBy the GroupBy enum
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
public Builder withPathsGroupedBy(GroupBy pathsGroupedBy) {
|
||||
this.pathsGroupedBy = pathsGroupedBy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the definitions should be ordered by natural ordering or stay as-is.
|
||||
*
|
||||
* @param definitionsOrderedBy the OrderBy enum
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
public Builder withDefinitionsOrderedBy(OrderBy definitionsOrderedBy) {
|
||||
this.definitionsOrderedBy = definitionsOrderedBy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies labels language of output files
|
||||
*
|
||||
* @param language the enum
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
public Builder withOutputLanguage(Language language) {
|
||||
this.outputLanguage = language;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,16 +21,16 @@ package io.github.robwin.swagger2markup.builder.document;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.github.robwin.markup.builder.MarkupDocBuilder;
|
||||
import io.github.robwin.markup.builder.MarkupDocBuilders;
|
||||
import io.github.robwin.swagger2markup.OrderBy;
|
||||
import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig;
|
||||
import io.github.robwin.swagger2markup.utils.PropertyUtils;
|
||||
import io.swagger.models.ComposedModel;
|
||||
import io.swagger.models.Model;
|
||||
import io.swagger.models.RefModel;
|
||||
import io.swagger.models.Swagger;
|
||||
import io.swagger.models.properties.Property;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import io.github.robwin.swagger2markup.utils.PropertyUtils;
|
||||
import io.swagger.models.refs.RefFormat;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -39,15 +39,17 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public class DefinitionsDocument extends MarkupDocument {
|
||||
|
||||
private static final String DEFINITIONS = "Definitions";
|
||||
private final String DEFINITIONS;
|
||||
private static final List<String> IGNORED_DEFINITIONS = Collections.singletonList("Void");
|
||||
private static final String JSON_SCHEMA = "JSON Schema";
|
||||
private static final String XML_SCHEMA = "XML Schema";
|
||||
private final String JSON_SCHEMA;
|
||||
private final String XML_SCHEMA;
|
||||
private static final String JSON_SCHEMA_EXTENSION = ".json";
|
||||
private static final String XML_SCHEMA_EXTENSION = ".xsd";
|
||||
private static final String JSON = "json";
|
||||
@@ -59,16 +61,25 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
private String descriptionsFolderPath;
|
||||
private boolean separatedDefinitionsEnabled;
|
||||
private String outputDirectory;
|
||||
private final OrderBy definitionsOrderedBy;
|
||||
|
||||
public DefinitionsDocument(Swagger swagger, MarkupLanguage markupLanguage, String schemasFolderPath, String descriptionsFolderPath, boolean separatedDefinitionsEnabled, String outputDirectory){
|
||||
super(swagger, markupLanguage);
|
||||
if(StringUtils.isNotBlank(schemasFolderPath)){
|
||||
public DefinitionsDocument(Swagger2MarkupConfig swagger2MarkupConfig, String outputDirectory){
|
||||
super(swagger2MarkupConfig);
|
||||
|
||||
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
|
||||
swagger2MarkupConfig.getOutputLanguage().toLocale());
|
||||
DEFINITIONS = labels.getString("definitions");
|
||||
JSON_SCHEMA = labels.getString("json_schema");
|
||||
XML_SCHEMA = labels.getString("xml_schema");
|
||||
|
||||
this.definitionsOrderedBy = swagger2MarkupConfig.getDefinitionsOrderedBy();
|
||||
if(isNotBlank(swagger2MarkupConfig.getSchemasFolderPath())){
|
||||
this.schemasEnabled = true;
|
||||
this.schemasFolderPath = schemasFolderPath;
|
||||
this.schemasFolderPath = swagger2MarkupConfig.getSchemasFolderPath();
|
||||
}
|
||||
if(StringUtils.isNotBlank(descriptionsFolderPath)){
|
||||
if(isNotBlank(swagger2MarkupConfig.getDescriptionsFolderPath())){
|
||||
this.handWrittenDescriptionsEnabled = true;
|
||||
this.descriptionsFolderPath = descriptionsFolderPath + "/" + DEFINITIONS.toLowerCase();
|
||||
this.descriptionsFolderPath = swagger2MarkupConfig.getDescriptionsFolderPath() + "/" + DEFINITIONS.toLowerCase();
|
||||
}
|
||||
if(schemasEnabled){
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -88,7 +99,7 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
logger.debug("Include hand-written descriptions is disabled.");
|
||||
}
|
||||
}
|
||||
this.separatedDefinitionsEnabled = separatedDefinitionsEnabled;
|
||||
this.separatedDefinitionsEnabled = swagger2MarkupConfig.isSeparatedDefinitions();
|
||||
if(this.separatedDefinitionsEnabled){
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Create separated definition files is enabled.");
|
||||
@@ -103,7 +114,7 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkupDocument build() throws IOException {
|
||||
public MarkupDocument build(){
|
||||
definitions(swagger.getDefinitions(), this.markupDocBuilder);
|
||||
return this;
|
||||
}
|
||||
@@ -114,20 +125,32 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
* @param definitions the Swagger definitions
|
||||
* @param docBuilder the doc builder to use for output
|
||||
*/
|
||||
private void definitions(Map<String, Model> definitions, MarkupDocBuilder docBuilder) throws IOException {
|
||||
private void definitions(Map<String, Model> definitions, MarkupDocBuilder docBuilder){
|
||||
if(MapUtils.isNotEmpty(definitions)){
|
||||
docBuilder.sectionTitleLevel1(DEFINITIONS);
|
||||
for(Map.Entry<String, Model> definitionsEntry : definitions.entrySet()){
|
||||
String definitionName = definitionsEntry.getKey();
|
||||
if(StringUtils.isNotBlank(definitionName)) {
|
||||
Set<String> definitionNames;
|
||||
if(definitionsOrderedBy.equals(OrderBy.AS_IS)){
|
||||
definitionNames = definitions.keySet();
|
||||
}else{
|
||||
definitionNames = new TreeSet<>(definitions.keySet());
|
||||
}
|
||||
for(String definitionName : definitionNames){
|
||||
Model model = definitions.get(definitionName);
|
||||
if(isNotBlank(definitionName)) {
|
||||
if (checkThatDefinitionIsNotInIgnoreList(definitionName)) {
|
||||
definition(definitions, definitionName, definitionsEntry.getValue(), docBuilder);
|
||||
definition(definitions, definitionName, model, docBuilder);
|
||||
definitionSchema(definitionName, docBuilder);
|
||||
if (separatedDefinitionsEnabled) {
|
||||
MarkupDocBuilder defDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage);
|
||||
definition(definitions, definitionName, definitionsEntry.getValue(), defDocBuilder);
|
||||
definition(definitions, definitionName, model, defDocBuilder);
|
||||
definitionSchema(definitionName, defDocBuilder);
|
||||
defDocBuilder.writeToFile(outputDirectory, definitionName.toLowerCase(), StandardCharsets.UTF_8);
|
||||
try {
|
||||
defDocBuilder.writeToFile(outputDirectory, definitionName.toLowerCase(), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(String.format("Failed to write definition file: %s", definitionName), e);
|
||||
}
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Separate definition file produced: {}", definitionName);
|
||||
}
|
||||
@@ -162,17 +185,17 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
* @param model the Swagger Model of the definition
|
||||
* @param docBuilder the docbuilder do use for output
|
||||
*/
|
||||
private void definition(Map<String, Model> definitions, String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
private void definition(Map<String, Model> definitions, String definitionName, Model model, MarkupDocBuilder docBuilder){
|
||||
docBuilder.sectionTitleLevel2(definitionName);
|
||||
descriptionSection(definitionName, model, docBuilder);
|
||||
propertiesSection(definitions, definitionName, model, docBuilder);
|
||||
}
|
||||
|
||||
private void propertiesSection(Map<String, Model> definitions, String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
private void propertiesSection(Map<String, Model> definitions, String definitionName, Model model, MarkupDocBuilder docBuilder){
|
||||
Map<String, Property> properties = getAllProperties(definitions, model);
|
||||
List<String> headerAndContent = new ArrayList<>();
|
||||
List<String> header = Arrays.asList(NAME_COLUMN, DESCRIPTION_COLUMN, REQUIRED_COLUMN, SCHEMA_COLUMN, DEFAULT_COLUMN);
|
||||
headerAndContent.add(StringUtils.join(header, DELIMITER));
|
||||
headerAndContent.add(join(header, DELIMITER));
|
||||
if(MapUtils.isNotEmpty(properties)){
|
||||
for (Map.Entry<String, Property> propertyEntry : properties.entrySet()) {
|
||||
Property property = propertyEntry.getValue();
|
||||
@@ -183,7 +206,7 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
Boolean.toString(property.getRequired()),
|
||||
PropertyUtils.getType(property, markupLanguage),
|
||||
PropertyUtils.getDefaultValue(property));
|
||||
headerAndContent.add(StringUtils.join(content, DELIMITER));
|
||||
headerAndContent.add(join(content, DELIMITER));
|
||||
}
|
||||
docBuilder.tableWithHeaderRow(headerAndContent);
|
||||
}
|
||||
@@ -191,9 +214,15 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
|
||||
private Map<String, Property> getAllProperties(Map<String, Model> definitions, Model model) {
|
||||
if(model instanceof RefModel) {
|
||||
final String ref = model.getReference();
|
||||
RefModel refModel = (RefModel)model;
|
||||
String ref;
|
||||
if(refModel.getRefFormat().equals(RefFormat.INTERNAL)){
|
||||
ref = refModel.getSimpleRef();
|
||||
}else{
|
||||
ref = model.getReference();
|
||||
}
|
||||
return definitions.containsKey(ref)
|
||||
? getAllProperties(definitions, definitions.get(model.getReference()))
|
||||
? getAllProperties(definitions, definitions.get(ref))
|
||||
: null;
|
||||
}
|
||||
if(model instanceof ComposedModel) {
|
||||
@@ -214,10 +243,10 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
}
|
||||
}
|
||||
|
||||
private void descriptionSection(String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
private void descriptionSection(String definitionName, Model model, MarkupDocBuilder docBuilder){
|
||||
if(handWrittenDescriptionsEnabled){
|
||||
String description = handWrittenPathDescription(definitionName.toLowerCase(), DESCRIPTION_FILE_NAME);
|
||||
if(StringUtils.isNotBlank(description)){
|
||||
if(isNotBlank(description)){
|
||||
docBuilder.paragraph(description);
|
||||
}else{
|
||||
if (logger.isInfoEnabled()) {
|
||||
@@ -233,24 +262,24 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
|
||||
private void modelDescription(Model model, MarkupDocBuilder docBuilder) {
|
||||
String description = model.getDescription();
|
||||
if (StringUtils.isNotBlank(description)) {
|
||||
if (isNotBlank(description)) {
|
||||
docBuilder.paragraph(description);
|
||||
}
|
||||
}
|
||||
|
||||
private String propertyDescription(String definitionName, String propertyName, Property property) throws IOException {
|
||||
private String propertyDescription(String definitionName, String propertyName, Property property) {
|
||||
String description;
|
||||
if(handWrittenDescriptionsEnabled){
|
||||
description = handWrittenPathDescription(definitionName.toLowerCase() + "/" + propertyName.toLowerCase(), DESCRIPTION_FILE_NAME);
|
||||
if(StringUtils.isBlank(description)) {
|
||||
if(isBlank(description)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Hand-written description file cannot be read. Trying to use description from Swagger source.");
|
||||
}
|
||||
description = StringUtils.defaultString(property.getDescription());
|
||||
description = defaultString(property.getDescription());
|
||||
}
|
||||
}
|
||||
else{
|
||||
description = StringUtils.defaultString(property.getDescription());
|
||||
description = defaultString(property.getDescription());
|
||||
}
|
||||
return description;
|
||||
}
|
||||
@@ -262,16 +291,21 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
* @param descriptionFolder the name of the folder where the description file resides
|
||||
* @param descriptionFileName the name of the description file
|
||||
* @return the content of the file
|
||||
* @throws IOException
|
||||
*/
|
||||
private String handWrittenPathDescription(String descriptionFolder, String descriptionFileName) throws IOException {
|
||||
private String handWrittenPathDescription(String descriptionFolder, String descriptionFileName){
|
||||
for (String fileNameExtension : markupLanguage.getFileNameExtensions()) {
|
||||
java.nio.file.Path path = Paths.get(descriptionsFolderPath, descriptionFolder, descriptionFileName + fileNameExtension);
|
||||
if (Files.isReadable(path)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Description file processed: {}", path);
|
||||
}
|
||||
return FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim();
|
||||
try {
|
||||
return FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim();
|
||||
} catch (IOException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(String.format("Failed to read description file: %s", path), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Description file is not readable: {}", path);
|
||||
@@ -284,20 +318,26 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void definitionSchema(String definitionName, MarkupDocBuilder docBuilder) throws IOException {
|
||||
private void definitionSchema(String definitionName, MarkupDocBuilder docBuilder) {
|
||||
if(schemasEnabled) {
|
||||
if (StringUtils.isNotBlank(definitionName)) {
|
||||
if (isNotBlank(definitionName)) {
|
||||
schema(JSON_SCHEMA, schemasFolderPath, definitionName + JSON_SCHEMA_EXTENSION, JSON, docBuilder);
|
||||
schema(XML_SCHEMA, schemasFolderPath, definitionName + XML_SCHEMA_EXTENSION, XML, docBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void schema(String title, String schemasFolderPath, String schemaName, String language, MarkupDocBuilder docBuilder) throws IOException {
|
||||
private void schema(String title, String schemasFolderPath, String schemaName, String language, MarkupDocBuilder docBuilder) {
|
||||
java.nio.file.Path path = Paths.get(schemasFolderPath, schemaName);
|
||||
if (Files.isReadable(path)) {
|
||||
docBuilder.sectionTitleLevel3(title);
|
||||
docBuilder.source(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim(), language);
|
||||
try {
|
||||
docBuilder.source(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim(), language);
|
||||
} catch (IOException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(String.format("Failed to read schema file: %s", path), e);
|
||||
}
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Schema file processed: {}", path);
|
||||
}
|
||||
|
||||
@@ -18,15 +18,17 @@
|
||||
*/
|
||||
package io.github.robwin.swagger2markup.builder.document;
|
||||
|
||||
import io.swagger.models.Swagger;
|
||||
import io.github.robwin.markup.builder.MarkupDocBuilder;
|
||||
import io.github.robwin.markup.builder.MarkupDocBuilders;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig;
|
||||
import io.swagger.models.Swagger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
@@ -34,24 +36,36 @@ import java.nio.charset.Charset;
|
||||
public abstract class MarkupDocument {
|
||||
|
||||
protected static final String DELIMITER = "|";
|
||||
protected static final String DEFAULT_COLUMN = "Default";
|
||||
protected static final String REQUIRED_COLUMN = "Required";
|
||||
protected static final String SCHEMA_COLUMN = "Schema";
|
||||
protected static final String NAME_COLUMN = "Name";
|
||||
protected static final String DESCRIPTION_COLUMN = "Description";
|
||||
protected static final String DESCRIPTION = DESCRIPTION_COLUMN;
|
||||
protected static final String PRODUCES = "Produces";
|
||||
protected static final String CONSUMES = "Consumes";
|
||||
protected static final String TAGS = "Tags";
|
||||
protected final String DEFAULT_COLUMN;
|
||||
protected final String REQUIRED_COLUMN;
|
||||
protected final String SCHEMA_COLUMN;
|
||||
protected final String NAME_COLUMN;
|
||||
protected final String DESCRIPTION_COLUMN;
|
||||
protected final String DESCRIPTION;
|
||||
protected final String PRODUCES;
|
||||
protected final String CONSUMES;
|
||||
protected final String TAGS;
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
protected Swagger swagger;
|
||||
protected MarkupLanguage markupLanguage;
|
||||
protected MarkupDocBuilder markupDocBuilder;
|
||||
|
||||
MarkupDocument(Swagger swagger, MarkupLanguage markupLanguage){
|
||||
this.swagger = swagger;
|
||||
this.markupLanguage = markupLanguage;
|
||||
MarkupDocument(Swagger2MarkupConfig swagger2MarkupConfig){
|
||||
this.swagger = swagger2MarkupConfig.getSwagger();
|
||||
this.markupLanguage = swagger2MarkupConfig.getMarkupLanguage();
|
||||
this.markupDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage);
|
||||
|
||||
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
|
||||
swagger2MarkupConfig.getOutputLanguage().toLocale());
|
||||
DEFAULT_COLUMN = labels.getString("default_column");
|
||||
REQUIRED_COLUMN = labels.getString("required_column");
|
||||
SCHEMA_COLUMN = labels.getString("schema_column");
|
||||
NAME_COLUMN = labels.getString("name_column");
|
||||
DESCRIPTION_COLUMN = labels.getString("description_column");
|
||||
DESCRIPTION = DESCRIPTION_COLUMN;
|
||||
PRODUCES = labels.getString("produces");
|
||||
CONSUMES = labels.getString("consumes");
|
||||
TAGS = labels.getString("tags");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,44 +18,61 @@
|
||||
*/
|
||||
package io.github.robwin.swagger2markup.builder.document;
|
||||
|
||||
import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig;
|
||||
import io.swagger.models.*;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
public class OverviewDocument extends MarkupDocument {
|
||||
|
||||
private static final String OVERVIEW = "Overview";
|
||||
private static final String CURRENT_VERSION = "Version information";
|
||||
private static final String VERSION = "Version: ";
|
||||
private static final String CONTACT_INFORMATION = "Contact information";
|
||||
private static final String CONTACT_NAME = "Contact: ";
|
||||
private static final String CONTACT_EMAIL = "Contact Email: ";
|
||||
private static final String LICENSE_INFORMATION = "License information";
|
||||
private static final String LICENSE = "License: ";
|
||||
private static final String LICENSE_URL = "License URL: ";
|
||||
private static final String TERMS_OF_SERVICE = "Terms of service: ";
|
||||
private static final String URI_SCHEME = "URI scheme";
|
||||
private static final String HOST = "Host: ";
|
||||
private static final String BASE_PATH = "BasePath: ";
|
||||
private static final String SCHEMES = "Schemes: ";
|
||||
private final String OVERVIEW;
|
||||
private final String CURRENT_VERSION;
|
||||
private final String VERSION;
|
||||
private final String CONTACT_INFORMATION;
|
||||
private final String CONTACT_NAME;
|
||||
private final String CONTACT_EMAIL;
|
||||
private final String LICENSE_INFORMATION;
|
||||
private final String LICENSE;
|
||||
private final String LICENSE_URL;
|
||||
private final String TERMS_OF_SERVICE;
|
||||
private final String URI_SCHEME;
|
||||
private final String HOST;
|
||||
private final String BASE_PATH;
|
||||
private final String SCHEMES;
|
||||
|
||||
public OverviewDocument(Swagger swagger, MarkupLanguage markupLanguage){
|
||||
super(swagger, markupLanguage);
|
||||
public OverviewDocument(Swagger2MarkupConfig swagger2MarkupConfig){
|
||||
super(swagger2MarkupConfig);
|
||||
|
||||
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
|
||||
swagger2MarkupConfig.getOutputLanguage().toLocale());
|
||||
OVERVIEW = labels.getString("overview");
|
||||
CURRENT_VERSION = labels.getString("current_version");
|
||||
VERSION = labels.getString("version");
|
||||
CONTACT_INFORMATION = labels.getString("contact_information");
|
||||
CONTACT_NAME = labels.getString("contact_name");
|
||||
CONTACT_EMAIL = labels.getString("contact_email");
|
||||
LICENSE_INFORMATION = labels.getString("license_information");
|
||||
LICENSE = labels.getString("license");
|
||||
LICENSE_URL = labels.getString("license_url");
|
||||
TERMS_OF_SERVICE = labels.getString("terms_of_service");
|
||||
URI_SCHEME = labels.getString("uri_scheme");
|
||||
HOST = labels.getString("host");
|
||||
BASE_PATH = labels.getString("base_path");
|
||||
SCHEMES = labels.getString("schemes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the MarkupDocument.
|
||||
*
|
||||
* @return the built MarkupDocument
|
||||
* @throws java.io.IOException if the files to include are not readable
|
||||
*/
|
||||
@Override
|
||||
public MarkupDocument build() throws IOException {
|
||||
public MarkupDocument build(){
|
||||
overview();
|
||||
return this;
|
||||
}
|
||||
@@ -68,11 +85,11 @@ public class OverviewDocument extends MarkupDocument {
|
||||
Info info = swagger.getInfo();
|
||||
this.markupDocBuilder.documentTitle(info.getTitle());
|
||||
this.markupDocBuilder.sectionTitleLevel1(OVERVIEW);
|
||||
if(StringUtils.isNotBlank(info.getDescription())){
|
||||
if(isNotBlank(info.getDescription())){
|
||||
this.markupDocBuilder.textLine(info.getDescription());
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
if(StringUtils.isNotBlank(info.getVersion())){
|
||||
if(isNotBlank(info.getVersion())){
|
||||
this.markupDocBuilder.sectionTitleLevel2(CURRENT_VERSION);
|
||||
this.markupDocBuilder.textLine(VERSION + info.getVersion());
|
||||
this.markupDocBuilder.newLine();
|
||||
@@ -80,56 +97,56 @@ public class OverviewDocument extends MarkupDocument {
|
||||
Contact contact = info.getContact();
|
||||
if(contact != null){
|
||||
this.markupDocBuilder.sectionTitleLevel2(CONTACT_INFORMATION);
|
||||
if(StringUtils.isNotBlank(contact.getName())){
|
||||
if(isNotBlank(contact.getName())){
|
||||
this.markupDocBuilder.textLine(CONTACT_NAME + contact.getName());
|
||||
}
|
||||
if(StringUtils.isNotBlank(contact.getEmail())){
|
||||
if(isNotBlank(contact.getEmail())){
|
||||
this.markupDocBuilder.textLine(CONTACT_EMAIL + contact.getEmail());
|
||||
}
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
|
||||
License license = info.getLicense();
|
||||
if(license != null && (StringUtils.isNotBlank(license.getName()) || StringUtils.isNotBlank(license.getUrl()))) {
|
||||
if(license != null && (isNotBlank(license.getName()) || isNotBlank(license.getUrl()))) {
|
||||
this.markupDocBuilder.sectionTitleLevel2(LICENSE_INFORMATION);
|
||||
if (StringUtils.isNotBlank(license.getName())) {
|
||||
if (isNotBlank(license.getName())) {
|
||||
this.markupDocBuilder.textLine(LICENSE + license.getName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(license.getUrl())) {
|
||||
if (isNotBlank(license.getUrl())) {
|
||||
this.markupDocBuilder.textLine(LICENSE_URL + license.getUrl());
|
||||
}
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
if(StringUtils.isNotBlank(info.getTermsOfService())){
|
||||
if(isNotBlank(info.getTermsOfService())){
|
||||
this.markupDocBuilder.textLine(TERMS_OF_SERVICE + info.getTermsOfService());
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
|
||||
if(StringUtils.isNotBlank(swagger.getHost()) || StringUtils.isNotBlank(swagger.getBasePath()) || CollectionUtils.isNotEmpty(swagger.getSchemes())) {
|
||||
if(isNotBlank(swagger.getHost()) || isNotBlank(swagger.getBasePath()) || isNotEmpty(swagger.getSchemes())) {
|
||||
this.markupDocBuilder.sectionTitleLevel2(URI_SCHEME);
|
||||
if (StringUtils.isNotBlank(swagger.getHost())) {
|
||||
if (isNotBlank(swagger.getHost())) {
|
||||
this.markupDocBuilder.textLine(HOST + swagger.getHost());
|
||||
}
|
||||
if (StringUtils.isNotBlank(swagger.getBasePath())) {
|
||||
if (isNotBlank(swagger.getBasePath())) {
|
||||
this.markupDocBuilder.textLine(BASE_PATH + swagger.getBasePath());
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(swagger.getSchemes())) {
|
||||
if (isNotEmpty(swagger.getSchemes())) {
|
||||
List<String> schemes = new ArrayList<>();
|
||||
for (Scheme scheme : swagger.getSchemes()) {
|
||||
schemes.add(scheme.toString());
|
||||
}
|
||||
this.markupDocBuilder.textLine(SCHEMES + StringUtils.join(schemes, ", "));
|
||||
this.markupDocBuilder.textLine(SCHEMES + join(schemes, ", "));
|
||||
}
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
|
||||
if(CollectionUtils.isNotEmpty(swagger.getTags())){
|
||||
if(isNotEmpty(swagger.getTags())){
|
||||
this.markupDocBuilder.sectionTitleLevel2(TAGS);
|
||||
List<String> tags = new ArrayList<>();
|
||||
for(Tag tag : swagger.getTags()){
|
||||
String name = tag.getName();
|
||||
String description = tag.getDescription();
|
||||
if(StringUtils.isNoneBlank(description)){
|
||||
if(isNoneBlank(description)){
|
||||
tags.add(name + ": " + description);
|
||||
}else{
|
||||
tags.add(name);
|
||||
@@ -139,13 +156,13 @@ public class OverviewDocument extends MarkupDocument {
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
|
||||
if(CollectionUtils.isNotEmpty(swagger.getConsumes())){
|
||||
if(isNotEmpty(swagger.getConsumes())){
|
||||
this.markupDocBuilder.sectionTitleLevel2(CONSUMES);
|
||||
this.markupDocBuilder.unorderedList(swagger.getConsumes());
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
|
||||
if(CollectionUtils.isNotEmpty(swagger.getProduces())){
|
||||
if(isNotEmpty(swagger.getProduces())){
|
||||
this.markupDocBuilder.sectionTitleLevel2(PRODUCES);
|
||||
this.markupDocBuilder.unorderedList(swagger.getProduces());
|
||||
this.markupDocBuilder.newLine();
|
||||
|
||||
@@ -18,63 +18,84 @@
|
||||
*/
|
||||
package io.github.robwin.swagger2markup.builder.document;
|
||||
|
||||
import io.swagger.models.Operation;
|
||||
import io.swagger.models.Path;
|
||||
import io.swagger.models.Response;
|
||||
import io.swagger.models.Swagger;
|
||||
import io.swagger.models.parameters.Parameter;
|
||||
import io.swagger.models.properties.Property;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Multimap;
|
||||
import io.github.robwin.swagger2markup.GroupBy;
|
||||
import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig;
|
||||
import io.github.robwin.swagger2markup.utils.ParameterUtils;
|
||||
import io.github.robwin.swagger2markup.utils.PropertyUtils;
|
||||
import io.swagger.models.*;
|
||||
import io.swagger.models.parameters.Parameter;
|
||||
import io.swagger.models.properties.Property;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static io.github.robwin.swagger2markup.utils.TagUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public class PathsDocument extends MarkupDocument {
|
||||
|
||||
private static final String PATHS = "Paths";
|
||||
private static final String PARAMETERS = "Parameters";
|
||||
private static final String RESPONSES = "Responses";
|
||||
private static final String EXAMPLE_CURL = "Example CURL request";
|
||||
private static final String EXAMPLE_REQUEST = "Example HTTP request";
|
||||
private static final String EXAMPLE_RESPONSE = "Example HTTP response";
|
||||
private static final String TYPE_COLUMN = "Type";
|
||||
private static final String HTTP_CODE_COLUMN = "HTTP Code";
|
||||
private static final String REQUEST_EXAMPLE_FILE_NAME = "http-request";
|
||||
private static final String RESPONSE_EXAMPLE_FILE_NAME = "http-response";
|
||||
private static final String CURL_EXAMPLE_FILE_NAME = "curl-request";
|
||||
private static final String DESCRIPTION_FILE_NAME = "description";
|
||||
private static final String PARAMETER = "Parameter";
|
||||
private final String PATHS;
|
||||
private final String RESOURCES;
|
||||
private final String PARAMETERS;
|
||||
private final String RESPONSES;
|
||||
private final String EXAMPLE_CURL;
|
||||
private final String EXAMPLE_REQUEST;
|
||||
private final String EXAMPLE_RESPONSE;
|
||||
private final String TYPE_COLUMN;
|
||||
private final String HTTP_CODE_COLUMN;
|
||||
private final String REQUEST_EXAMPLE_FILE_NAME;
|
||||
private final String RESPONSE_EXAMPLE_FILE_NAME;
|
||||
private final String CURL_EXAMPLE_FILE_NAME;
|
||||
private final String DESCRIPTION_FILE_NAME;
|
||||
private final String PARAMETER;
|
||||
|
||||
private boolean examplesEnabled;
|
||||
private String examplesFolderPath;
|
||||
private boolean handWrittenDescriptionsEnabled;
|
||||
private String descriptionsFolderPath;
|
||||
private final GroupBy pathsGroupedBy;
|
||||
|
||||
public PathsDocument(Swagger swagger, MarkupLanguage markupLanguage, String examplesFolderPath, String descriptionsFolderPath){
|
||||
super(swagger, markupLanguage);
|
||||
if(StringUtils.isNotBlank(examplesFolderPath)){
|
||||
public PathsDocument(Swagger2MarkupConfig swagger2MarkupConfig){
|
||||
super(swagger2MarkupConfig);
|
||||
|
||||
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
|
||||
swagger2MarkupConfig.getOutputLanguage().toLocale());
|
||||
PATHS = labels.getString("paths");
|
||||
RESOURCES = labels.getString("resources");
|
||||
PARAMETERS = labels.getString("parameters");
|
||||
RESPONSES = labels.getString("responses");
|
||||
EXAMPLE_CURL = labels.getString("example_curl");
|
||||
EXAMPLE_REQUEST = labels.getString("example_request");
|
||||
EXAMPLE_RESPONSE = labels.getString("example_response");
|
||||
TYPE_COLUMN = labels.getString("type_column");
|
||||
HTTP_CODE_COLUMN = labels.getString("http_code_column");
|
||||
REQUEST_EXAMPLE_FILE_NAME = labels.getString("request_example_file_name");
|
||||
RESPONSE_EXAMPLE_FILE_NAME = labels.getString("response_example_file_name");
|
||||
CURL_EXAMPLE_FILE_NAME = labels.getString("curl_example_file_name");
|
||||
DESCRIPTION_FILE_NAME = labels.getString("description_file_name");
|
||||
PARAMETER = labels.getString("parameter");
|
||||
|
||||
this.pathsGroupedBy = swagger2MarkupConfig.getPathsGroupedBy();
|
||||
if(isNotBlank(swagger2MarkupConfig.getExamplesFolderPath())){
|
||||
this.examplesEnabled = true;
|
||||
this.examplesFolderPath = examplesFolderPath;
|
||||
this.examplesFolderPath = swagger2MarkupConfig.getExamplesFolderPath();
|
||||
}
|
||||
if(StringUtils.isNotBlank(descriptionsFolderPath)){
|
||||
if(isNotBlank(swagger2MarkupConfig.getDescriptionsFolderPath())){
|
||||
this.handWrittenDescriptionsEnabled = true;
|
||||
this.descriptionsFolderPath = descriptionsFolderPath + "/" + PATHS.toLowerCase();
|
||||
this.descriptionsFolderPath = swagger2MarkupConfig.getDescriptionsFolderPath() + "/" + PATHS.toLowerCase();
|
||||
}
|
||||
if(examplesEnabled){
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -96,42 +117,69 @@ public class PathsDocument extends MarkupDocument {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the paths markup document.
|
||||
*
|
||||
* @return the the paths markup document
|
||||
*/
|
||||
@Override
|
||||
public MarkupDocument build() throws IOException {
|
||||
public MarkupDocument build(){
|
||||
paths();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all paths of the Swagger model
|
||||
* Builds all paths of the Swagger model. Either grouped as-is or by tags.
|
||||
*/
|
||||
private void paths() throws IOException {
|
||||
private void paths(){
|
||||
Map<String, Path> paths = swagger.getPaths();
|
||||
if(MapUtils.isNotEmpty(paths)) {
|
||||
this.markupDocBuilder.sectionTitleLevel1(PATHS);
|
||||
for (Map.Entry<String, Path> entry : paths.entrySet()) {
|
||||
Path path = entry.getValue();
|
||||
if(path != null) {
|
||||
path("GET", entry.getKey(), path.getGet());
|
||||
path("PUT", entry.getKey(), path.getPut());
|
||||
path("DELETE", entry.getKey(), path.getDelete());
|
||||
path("POST", entry.getKey(), path.getPost());
|
||||
path("PATCH", entry.getKey(), path.getPatch());
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel1(PATHS);
|
||||
for (Map.Entry<String, Path> pathEntry : paths.entrySet()) {
|
||||
Path path = pathEntry.getValue();
|
||||
if(path != null) {
|
||||
createPathSections(pathEntry.getKey(), path);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel1(RESOURCES);
|
||||
Multimap<String, Pair<String, Path>> pathsGroupedByTag = groupPathsByTag(paths);
|
||||
Map<String, Tag> tagsMap = convertTagsListToMap(swagger.getTags());
|
||||
for(String tagName : pathsGroupedByTag.keySet()){
|
||||
this.markupDocBuilder.sectionTitleLevel2(WordUtils.capitalize(tagName));
|
||||
Optional<String> tagDescription = getTagDescription(tagsMap, tagName);
|
||||
if(tagDescription.isPresent()) {
|
||||
this.markupDocBuilder.paragraph(tagDescription.get());
|
||||
}
|
||||
Collection<Pair<String, Path>> pathsOfTag = pathsGroupedByTag.get(tagName);
|
||||
for(Pair<String, Path> pathPair : pathsOfTag){
|
||||
Path path = pathPair.getValue();
|
||||
if(path != null) {
|
||||
createPathSections(pathPair.getKey(), path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createPathSections(String pathUrl, Path path){
|
||||
for(Map.Entry<HttpMethod, Operation> operationEntry : path.getOperationMap().entrySet()){
|
||||
String methodAndPath = operationEntry.getKey() + " " + pathUrl;
|
||||
path(methodAndPath, operationEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a path
|
||||
* Builds a path.
|
||||
*
|
||||
* @param httpMethod the HTTP method of the path
|
||||
* @param resourcePath the URL of the path
|
||||
* @param methodAndPath the Method of the operation and the URL of the path
|
||||
* @param operation the Swagger Operation
|
||||
*/
|
||||
private void path(String httpMethod, String resourcePath, Operation operation) throws IOException {
|
||||
private void path(String methodAndPath, Operation operation) {
|
||||
if(operation != null){
|
||||
pathTitle(httpMethod, resourcePath, operation);
|
||||
pathTitle(methodAndPath, operation);
|
||||
descriptionSection(operation);
|
||||
parametersSection(operation);
|
||||
responsesSection(operation);
|
||||
@@ -142,63 +190,89 @@ public class PathsDocument extends MarkupDocument {
|
||||
}
|
||||
}
|
||||
|
||||
private void pathTitle(String httpMethod, String resourcePath, Operation operation) {
|
||||
/**
|
||||
* Adds the path title to the document. If the operation has a summary, the title is the summary.
|
||||
* Otherwise the title is the method of the operation and the URL of the path.
|
||||
*
|
||||
* @param methodAndPath the Method of the operation and the URL of the path
|
||||
* @param operation the Swagger Operation
|
||||
*/
|
||||
private void pathTitle(String methodAndPath, Operation operation) {
|
||||
String summary = operation.getSummary();
|
||||
String title;
|
||||
if(StringUtils.isNotBlank(summary)) {
|
||||
if(isNotBlank(summary)) {
|
||||
title = summary;
|
||||
this.markupDocBuilder.sectionTitleLevel2(title);
|
||||
this.markupDocBuilder.listing(httpMethod + " " + resourcePath);
|
||||
addPathTitle(title);
|
||||
this.markupDocBuilder.listing(methodAndPath);
|
||||
}else{
|
||||
title = httpMethod + " " + resourcePath;
|
||||
this.markupDocBuilder.sectionTitleLevel2(title);
|
||||
addPathTitle(methodAndPath);
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Path processed: {}", title);
|
||||
logger.info("Path processed: {}", methodAndPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void descriptionSection(Operation operation) throws IOException {
|
||||
/**
|
||||
* Adds a path title to the document.
|
||||
*
|
||||
* @param title the path title
|
||||
*/
|
||||
private void addPathTitle(String title) {
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel2(title);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel3(title);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a path description to the document.
|
||||
*
|
||||
* @param operation the Swagger Operation
|
||||
*/
|
||||
private void descriptionSection(Operation operation) {
|
||||
if(handWrittenDescriptionsEnabled){
|
||||
String summary = operation.getSummary();
|
||||
if(StringUtils.isNotBlank(summary)) {
|
||||
if(isNotBlank(summary)) {
|
||||
String operationFolder = summary.replace(".", "").replace(" ", "_").toLowerCase();
|
||||
String description = handWrittenPathDescription(operationFolder, DESCRIPTION_FILE_NAME);
|
||||
if(StringUtils.isNotBlank(description)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(DESCRIPTION);
|
||||
this.markupDocBuilder.paragraph(description);
|
||||
Optional<String> description = handWrittenPathDescription(operationFolder, DESCRIPTION_FILE_NAME);
|
||||
if(description.isPresent()){
|
||||
pathDescription(description.get());
|
||||
}else{
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Hand-written description cannot be read. Trying to use description from Swagger source.");
|
||||
}
|
||||
pathDescription(operation);
|
||||
pathDescription(operation.getDescription());
|
||||
}
|
||||
}else{
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Hand-written description cannot be read, because summary of operation is empty. Trying to use description from Swagger source.");
|
||||
}
|
||||
pathDescription(operation);
|
||||
pathDescription(operation.getDescription());
|
||||
}
|
||||
}else {
|
||||
pathDescription(operation);
|
||||
pathDescription(operation.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
private void pathDescription(Operation operation) {
|
||||
String description = operation.getDescription();
|
||||
if (StringUtils.isNotBlank(description)) {
|
||||
this.markupDocBuilder.sectionTitleLevel3(DESCRIPTION);
|
||||
private void pathDescription(String description) {
|
||||
if (isNotBlank(description)) {
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(DESCRIPTION);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(DESCRIPTION);
|
||||
}
|
||||
this.markupDocBuilder.paragraph(description);
|
||||
}
|
||||
}
|
||||
|
||||
private void parametersSection(Operation operation) throws IOException {
|
||||
private void parametersSection(Operation operation) {
|
||||
List<Parameter> parameters = operation.getParameters();
|
||||
if(CollectionUtils.isNotEmpty(parameters)){
|
||||
List<String> headerAndContent = new ArrayList<>();
|
||||
// Table header row
|
||||
List<String> header = Arrays.asList(TYPE_COLUMN, NAME_COLUMN, DESCRIPTION_COLUMN, REQUIRED_COLUMN, SCHEMA_COLUMN, DEFAULT_COLUMN);
|
||||
headerAndContent.add(StringUtils.join(header, DELIMITER));
|
||||
headerAndContent.add(join(header, DELIMITER));
|
||||
for(Parameter parameter : parameters){
|
||||
String type = ParameterUtils.getType(parameter, markupLanguage);
|
||||
String parameterType = WordUtils.capitalize(parameter.getIn() + PARAMETER);
|
||||
@@ -209,43 +283,61 @@ public class PathsDocument extends MarkupDocument {
|
||||
parameterDescription(operation, parameter),
|
||||
Boolean.toString(parameter.getRequired()), type,
|
||||
ParameterUtils.getDefaultValue(parameter));
|
||||
headerAndContent.add(StringUtils.join(content, DELIMITER));
|
||||
headerAndContent.add(join(content, DELIMITER));
|
||||
}
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(PARAMETERS);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(PARAMETERS);
|
||||
}
|
||||
this.markupDocBuilder.sectionTitleLevel3(PARAMETERS);
|
||||
this.markupDocBuilder.tableWithHeaderRow(headerAndContent);
|
||||
}
|
||||
}
|
||||
|
||||
private String parameterDescription(Operation operation, Parameter parameter) throws IOException {
|
||||
String description;
|
||||
/**
|
||||
* Retrieves the description of a parameter, or otherwise an empty String.
|
||||
* If hand-written descriptions are enabled, it tries to load the description from a file.
|
||||
* If the file cannot be read, the description the parameter is returned.
|
||||
*
|
||||
* @param operation the Swagger Operation
|
||||
* @param parameter the Swagger Parameter
|
||||
* @return the description of a parameter.
|
||||
*/
|
||||
private String parameterDescription(Operation operation, Parameter parameter){
|
||||
if(handWrittenDescriptionsEnabled){
|
||||
String summary = operation.getSummary();
|
||||
String operationFolder = summary.replace(".", "").replace(" ", "_").toLowerCase();
|
||||
String parameterName = parameter.getName();
|
||||
if(StringUtils.isNotBlank(operationFolder) && StringUtils.isNotBlank(parameterName)) {
|
||||
description = handWrittenPathDescription(operationFolder + "/" + parameterName, DESCRIPTION_FILE_NAME);
|
||||
if(StringUtils.isBlank(description)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Hand-written description file cannot be read. Trying to use description from Swagger source.");
|
||||
if(isNotBlank(operationFolder) && isNotBlank(parameterName)) {
|
||||
Optional<String> description = handWrittenPathDescription(operationFolder + "/" + parameterName, DESCRIPTION_FILE_NAME);
|
||||
if(description.isPresent()){
|
||||
return description.get();
|
||||
}
|
||||
else{
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Hand-written description file cannot be read. Trying to use description from Swagger source.");
|
||||
}
|
||||
description = StringUtils.defaultString(parameter.getDescription());
|
||||
return defaultString(parameter.getDescription());
|
||||
}
|
||||
}else{
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Hand-written description file cannot be read, because summary of operation or name of parameter is empty. Trying to use description from Swagger source.");
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Hand-written description file cannot be read, because summary of operation or name of parameter is empty. Trying to use description from Swagger source.");
|
||||
}
|
||||
description = StringUtils.defaultString(parameter.getDescription());
|
||||
return defaultString(parameter.getDescription());
|
||||
}
|
||||
}else {
|
||||
description = StringUtils.defaultString(parameter.getDescription());
|
||||
return defaultString(parameter.getDescription());
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
private void consumesSection(Operation operation) {
|
||||
List<String> consumes = operation.getConsumes();
|
||||
if(CollectionUtils.isNotEmpty(consumes)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(CONSUMES);
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(CONSUMES);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(CONSUMES);
|
||||
}
|
||||
this.markupDocBuilder.unorderedList(consumes);
|
||||
}
|
||||
|
||||
@@ -254,45 +346,64 @@ public class PathsDocument extends MarkupDocument {
|
||||
private void producesSection(Operation operation) {
|
||||
List<String> produces = operation.getProduces();
|
||||
if(CollectionUtils.isNotEmpty(produces)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(PRODUCES);
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(PRODUCES);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(PRODUCES);
|
||||
}
|
||||
this.markupDocBuilder.unorderedList(produces);
|
||||
}
|
||||
}
|
||||
|
||||
private void tagsSection(Operation operation) {
|
||||
List<String> tags = operation.getTags();
|
||||
if(CollectionUtils.isNotEmpty(tags)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(TAGS);
|
||||
this.markupDocBuilder.unorderedList(tags);
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)) {
|
||||
List<String> tags = operation.getTags();
|
||||
if (CollectionUtils.isNotEmpty(tags)) {
|
||||
this.markupDocBuilder.sectionTitleLevel3(TAGS);
|
||||
this.markupDocBuilder.unorderedList(tags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the example section of a Swagger Operation
|
||||
* Builds the example section of a Swagger Operation. Tries to load the examples from
|
||||
* curl-request.adoc, http-request.adoc and http-response.adoc or
|
||||
* curl-request.md, http-request.md and http-response.md.
|
||||
*
|
||||
* @param operation the Swagger Operation
|
||||
* @throws IOException if the example file is not readable
|
||||
*/
|
||||
private void examplesSection(Operation operation) throws IOException {
|
||||
private void examplesSection(Operation operation) {
|
||||
if(examplesEnabled){
|
||||
String summary = operation.getSummary();
|
||||
if(StringUtils.isNotBlank(summary)) {
|
||||
if(isNotBlank(summary)) {
|
||||
String exampleFolder = summary.replace(".", "").replace(" ", "_").toLowerCase();
|
||||
String curlExample = example(exampleFolder, CURL_EXAMPLE_FILE_NAME);
|
||||
if(StringUtils.isNotBlank(curlExample)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_CURL);
|
||||
this.markupDocBuilder.paragraph(curlExample);
|
||||
Optional<String> curlExample = example(exampleFolder, CURL_EXAMPLE_FILE_NAME);
|
||||
if(curlExample.isPresent()){
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_CURL);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(EXAMPLE_CURL);
|
||||
}
|
||||
this.markupDocBuilder.paragraph(curlExample.get());
|
||||
}
|
||||
|
||||
String requestExample = example(exampleFolder, REQUEST_EXAMPLE_FILE_NAME);
|
||||
if(StringUtils.isNotBlank(requestExample)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_REQUEST);
|
||||
this.markupDocBuilder.paragraph(requestExample);
|
||||
Optional<String> requestExample = example(exampleFolder, REQUEST_EXAMPLE_FILE_NAME);
|
||||
if(requestExample.isPresent()){
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_REQUEST);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(EXAMPLE_REQUEST);
|
||||
}
|
||||
this.markupDocBuilder.paragraph(requestExample.get());
|
||||
}
|
||||
String responseExample = example(exampleFolder, RESPONSE_EXAMPLE_FILE_NAME);
|
||||
if(StringUtils.isNotBlank(responseExample)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_RESPONSE);
|
||||
this.markupDocBuilder.paragraph(responseExample);
|
||||
Optional<String> responseExample = example(exampleFolder, RESPONSE_EXAMPLE_FILE_NAME);
|
||||
if(responseExample.isPresent()){
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_RESPONSE);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(EXAMPLE_RESPONSE);
|
||||
}
|
||||
this.markupDocBuilder.paragraph(responseExample.get());
|
||||
}
|
||||
}else{
|
||||
if (logger.isWarnEnabled()) {
|
||||
@@ -308,26 +419,31 @@ public class PathsDocument extends MarkupDocument {
|
||||
* @param exampleFolder the name of the folder where the example file resides
|
||||
* @param exampleFileName the name of the example file
|
||||
* @return the content of the file
|
||||
* @throws IOException
|
||||
*/
|
||||
private String example(String exampleFolder, String exampleFileName) throws IOException {
|
||||
private Optional<String> example(String exampleFolder, String exampleFileName) {
|
||||
for (String fileNameExtension : markupLanguage.getFileNameExtensions()) {
|
||||
java.nio.file.Path path = Paths.get(examplesFolderPath, exampleFolder, exampleFileName + fileNameExtension);
|
||||
if (Files.isReadable(path)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Example file processed: {}", path);
|
||||
}
|
||||
return FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim();
|
||||
try {
|
||||
return Optional.fromNullable(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim());
|
||||
} catch (IOException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(String.format("Failed to read example file: %s", path), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Example file is not readable: {}", path);
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Example file is not readable: {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.info("No example file found with correct file name extension in folder: {}", Paths.get(examplesFolderPath, exampleFolder));
|
||||
logger.warn("No example file found with correct file name extension in folder: {}", Paths.get(examplesFolderPath, exampleFolder));
|
||||
}
|
||||
return null;
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,26 +452,31 @@ public class PathsDocument extends MarkupDocument {
|
||||
* @param descriptionFolder the name of the folder where the description file resides
|
||||
* @param descriptionFileName the name of the description file
|
||||
* @return the content of the file
|
||||
* @throws IOException
|
||||
*/
|
||||
private String handWrittenPathDescription(String descriptionFolder, String descriptionFileName) throws IOException {
|
||||
private Optional<String> handWrittenPathDescription(String descriptionFolder, String descriptionFileName){
|
||||
for (String fileNameExtension : markupLanguage.getFileNameExtensions()) {
|
||||
java.nio.file.Path path = Paths.get(descriptionsFolderPath, descriptionFolder, descriptionFileName + fileNameExtension);
|
||||
if (Files.isReadable(path)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Description file processed: {}", path);
|
||||
}
|
||||
return FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim();
|
||||
try {
|
||||
return Optional.fromNullable(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim());
|
||||
} catch (IOException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(String.format("Failed to read description file: %s", path), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Description file is not readable: {}", path);
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Description file is not readable: {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.info("No description file found with correct file name extension in folder: {}", Paths.get(descriptionsFolderPath, descriptionFolder));
|
||||
logger.warn("No description file found with correct file name extension in folder: {}", Paths.get(descriptionsFolderPath, descriptionFolder));
|
||||
}
|
||||
return null;
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
private void responsesSection(Operation operation) {
|
||||
@@ -373,7 +494,11 @@ public class PathsDocument extends MarkupDocument {
|
||||
csvContent.add(entry.getKey() + DELIMITER + response.getDescription() + DELIMITER + "No Content");
|
||||
}
|
||||
}
|
||||
this.markupDocBuilder.sectionTitleLevel3(RESPONSES);
|
||||
if(pathsGroupedBy.equals(GroupBy.AS_IS)){
|
||||
this.markupDocBuilder.sectionTitleLevel3(RESPONSES);
|
||||
}else{
|
||||
this.markupDocBuilder.sectionTitleLevel4(RESPONSES);
|
||||
}
|
||||
this.markupDocBuilder.tableWithHeaderRow(csvContent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015 Robert Winkler
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package io.github.robwin.swagger2markup.config;
|
||||
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import io.github.robwin.swagger2markup.GroupBy;
|
||||
import io.github.robwin.swagger2markup.Language;
|
||||
import io.github.robwin.swagger2markup.OrderBy;
|
||||
import io.swagger.models.Swagger;
|
||||
|
||||
public class Swagger2MarkupConfig {
|
||||
|
||||
private final Swagger swagger;
|
||||
private final MarkupLanguage markupLanguage;
|
||||
private final String examplesFolderPath;
|
||||
private final String schemasFolderPath;
|
||||
private final String descriptionsFolderPath;
|
||||
private final boolean separatedDefinitions;
|
||||
private final GroupBy pathsGroupedBy;
|
||||
private final OrderBy definitionsOrderedBy;
|
||||
private final Language outputLanguage;
|
||||
|
||||
/**
|
||||
* @param swagger the Swagger source
|
||||
* @param markupLanguage the markup language which is used to generate the files
|
||||
* @param examplesFolderPath examplesFolderPath the path to the folder where the example documents reside
|
||||
* @param schemasFolderPath the path to the folder where the schema documents reside
|
||||
* @param descriptionsFolderPath the path to the folder where the description documents reside
|
||||
* @param separatedDefinitions specified if in addition to the definitions file, also separate definition files for each model definition should be created
|
||||
* @param pathsGroupedBy specifies if the paths should be grouped by tags or stay as-is
|
||||
* @param definitionsOrderedBy specifies if the definitions should be ordered by natural ordering or stay as-is
|
||||
* @param outputLanguage specifies language of labels in output files
|
||||
*/
|
||||
public Swagger2MarkupConfig(Swagger swagger, MarkupLanguage markupLanguage, String examplesFolderPath,
|
||||
String schemasFolderPath, String descriptionsFolderPath, boolean separatedDefinitions,
|
||||
GroupBy pathsGroupedBy, OrderBy definitionsOrderedBy, Language outputLanguage) {
|
||||
this.swagger = swagger;
|
||||
this.markupLanguage = markupLanguage;
|
||||
this.examplesFolderPath = examplesFolderPath;
|
||||
this.schemasFolderPath = schemasFolderPath;
|
||||
this.descriptionsFolderPath = descriptionsFolderPath;
|
||||
this.separatedDefinitions = separatedDefinitions;
|
||||
this.pathsGroupedBy = pathsGroupedBy;
|
||||
this.definitionsOrderedBy = definitionsOrderedBy;
|
||||
this.outputLanguage = outputLanguage;
|
||||
}
|
||||
|
||||
public Swagger getSwagger() {
|
||||
return swagger;
|
||||
}
|
||||
|
||||
public MarkupLanguage getMarkupLanguage() {
|
||||
return markupLanguage;
|
||||
}
|
||||
|
||||
public String getExamplesFolderPath() {
|
||||
return examplesFolderPath;
|
||||
}
|
||||
|
||||
public String getSchemasFolderPath() {
|
||||
return schemasFolderPath;
|
||||
}
|
||||
|
||||
public String getDescriptionsFolderPath() {
|
||||
return descriptionsFolderPath;
|
||||
}
|
||||
|
||||
public boolean isSeparatedDefinitions() {
|
||||
return separatedDefinitions;
|
||||
}
|
||||
|
||||
public GroupBy getPathsGroupedBy() {
|
||||
return pathsGroupedBy;
|
||||
}
|
||||
|
||||
public OrderBy getDefinitionsOrderedBy() {
|
||||
return definitionsOrderedBy;
|
||||
}
|
||||
|
||||
public Language getOutputLanguage() {
|
||||
return outputLanguage;
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,13 @@ import org.apache.commons.lang3.Validate;
|
||||
|
||||
public final class ModelUtils {
|
||||
|
||||
/**
|
||||
* Retrieves the type of a model, or otherwise "NOT FOUND"
|
||||
*
|
||||
* @param model the model
|
||||
* @param markupLanguage the markup language which is used to generate the files
|
||||
* @return the type of the model, or otherwise "NOT FOUND"
|
||||
*/
|
||||
public static String getType(Model model, MarkupLanguage markupLanguage) {
|
||||
Validate.notNull(model, "model must not be null!");
|
||||
if (model instanceof ModelImpl) {
|
||||
|
||||
@@ -18,21 +18,29 @@
|
||||
*/
|
||||
package io.github.robwin.swagger2markup.utils;
|
||||
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import io.swagger.models.Model;
|
||||
import io.swagger.models.parameters.AbstractSerializableParameter;
|
||||
import io.swagger.models.parameters.BodyParameter;
|
||||
import io.swagger.models.parameters.Parameter;
|
||||
import io.swagger.models.parameters.RefParameter;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
|
||||
public final class ParameterUtils {
|
||||
|
||||
/**
|
||||
* Retrieves the type of a parameter, or otherwise an empty String
|
||||
*
|
||||
* @param parameter the parameter
|
||||
* @param markupLanguage the markup language which is used to generate the files
|
||||
* @return the type of the parameter, or otherwise an empty String
|
||||
*/
|
||||
public static String getType(Parameter parameter, MarkupLanguage markupLanguage){
|
||||
Validate.notNull(parameter, "property must not be null!");
|
||||
String type = "NOT FOUND";
|
||||
@@ -50,7 +58,7 @@ public final class ParameterUtils {
|
||||
AbstractSerializableParameter serializableParameter = (AbstractSerializableParameter)parameter;
|
||||
List enums = serializableParameter.getEnum();
|
||||
if(CollectionUtils.isNotEmpty(enums)){
|
||||
type = "enum" + " (" + StringUtils.join(enums, ", ") + ")";
|
||||
type = "enum" + " (" + join(enums, ", ") + ")";
|
||||
}else{
|
||||
type = getTypeWithFormat(serializableParameter.getType(), serializableParameter.getFormat());
|
||||
}
|
||||
@@ -66,19 +74,32 @@ public final class ParameterUtils {
|
||||
default: return refParameter.getSimpleRef();
|
||||
}
|
||||
}
|
||||
return StringUtils.defaultString(type);
|
||||
return defaultString(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the format to the type, if a format is available
|
||||
*
|
||||
* @param typeWithoutFormat the type
|
||||
* @param format the format
|
||||
* @return returns the type and format, if a format is available
|
||||
*/
|
||||
private static String getTypeWithFormat(String typeWithoutFormat, String format) {
|
||||
String type;
|
||||
if(StringUtils.isNotBlank(format)){
|
||||
type = StringUtils.defaultString(typeWithoutFormat) + " (" + format + ")";
|
||||
if(isNotBlank(format)){
|
||||
type = defaultString(typeWithoutFormat) + " (" + format + ")";
|
||||
}else{
|
||||
type = StringUtils.defaultString(typeWithoutFormat);
|
||||
type = defaultString(typeWithoutFormat);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default value of a parameter, or otherwise an empty String
|
||||
*
|
||||
* @param parameter the parameter
|
||||
* @return the default value of the parameter, or otherwise an empty String
|
||||
*/
|
||||
public static String getDefaultValue(Parameter parameter){
|
||||
Validate.notNull(parameter, "property must not be null!");
|
||||
String defaultValue = "";
|
||||
@@ -86,7 +107,7 @@ public final class ParameterUtils {
|
||||
AbstractSerializableParameter serializableParameter = (AbstractSerializableParameter)parameter;
|
||||
defaultValue = serializableParameter.getDefaultValue();
|
||||
}
|
||||
return StringUtils.defaultString(defaultValue);
|
||||
return defaultString(defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,17 +18,25 @@
|
||||
*/
|
||||
package io.github.robwin.swagger2markup.utils;
|
||||
|
||||
import io.swagger.models.properties.*;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import io.swagger.models.properties.*;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
public final class PropertyUtils {
|
||||
|
||||
/**
|
||||
* Retrieves the type and format of a property.
|
||||
*
|
||||
* @param property the property
|
||||
* @param markupLanguage the markup language which is used to generate the files
|
||||
* @return the type of the property
|
||||
*/
|
||||
public static String getType(Property property, MarkupLanguage markupLanguage){
|
||||
Validate.notNull(property, "property must not be null!");
|
||||
String type;
|
||||
@@ -46,21 +54,27 @@ public final class PropertyUtils {
|
||||
StringProperty stringProperty = (StringProperty)property;
|
||||
List<String> enums = stringProperty.getEnum();
|
||||
if(CollectionUtils.isNotEmpty(enums)){
|
||||
type = "enum" + " (" + StringUtils.join(enums, ", ") + ")";
|
||||
type = "enum" + " (" + join(enums, ", ") + ")";
|
||||
}else{
|
||||
type = property.getType();
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(StringUtils.isNotBlank(property.getFormat())){
|
||||
type = StringUtils.defaultString(property.getType()) + " (" + property.getFormat() + ")";
|
||||
if(isNotBlank(property.getFormat())){
|
||||
type = defaultString(property.getType()) + " (" + property.getFormat() + ")";
|
||||
}else{
|
||||
type = property.getType();
|
||||
}
|
||||
}
|
||||
return StringUtils.defaultString(type);
|
||||
return defaultString(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default value of a property, or otherwise returns an empty String.
|
||||
*
|
||||
* @param property the property
|
||||
* @return the default value of the property, or otherwise an empty String
|
||||
*/
|
||||
public static String getDefaultValue(Property property){
|
||||
Validate.notNull(property, "property must not be null!");
|
||||
String defaultValue = "";
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015 Robert Winkler
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package io.github.robwin.swagger2markup.utils;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import io.swagger.models.HttpMethod;
|
||||
import io.swagger.models.Operation;
|
||||
import io.swagger.models.Path;
|
||||
import io.swagger.models.Tag;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TagUtils {
|
||||
|
||||
private static Logger LOG = LoggerFactory.getLogger(TagUtils.class);
|
||||
|
||||
/**
|
||||
* Converts the global Tag list into a Map where the tag name is the key and the Tag the value.
|
||||
*
|
||||
* @param tags the List of tags
|
||||
* @return the Map of tags
|
||||
*/
|
||||
public static Map<String, Tag> convertTagsListToMap(List<Tag> tags) {
|
||||
if (tags == null) {
|
||||
tags = new ArrayList<>();
|
||||
}
|
||||
Map<String, Tag> tagsMap = new HashMap<>();
|
||||
for (Tag tag : tags) tagsMap.put(tag.getName(), tag);
|
||||
return tagsMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the optional description of a tag.
|
||||
*
|
||||
* @param tagsMap the Map of tags
|
||||
* @param tagName the name of the tag
|
||||
* @return the optional description of the tag
|
||||
*/
|
||||
public static Optional<String> getTagDescription(Map<String, Tag> tagsMap, String tagName) {
|
||||
Tag tag = tagsMap.get(tagName);
|
||||
if(tag != null){
|
||||
return Optional.fromNullable(tag.getDescription());
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups the paths by tag. The key of the Multimap is the tag name.
|
||||
* The value of the Multimap is a Pair which contains the Method and the Path.
|
||||
*
|
||||
* @param paths the Paths
|
||||
* @return Paths grouped by Tag
|
||||
*/
|
||||
public static Multimap<String, Pair<String, Path>> groupPathsByTag(Map<String, Path> paths) {
|
||||
Multimap<String, Pair<String, Path>> pathsGroupedByTag = MultimapBuilder.SortedSetMultimapBuilder.treeKeys().hashSetValues().build();
|
||||
for (Map.Entry<String, Path> pathEntry : paths.entrySet()) {
|
||||
String resourcePath = pathEntry.getKey();
|
||||
Path path = pathEntry.getValue();
|
||||
for(Map.Entry<HttpMethod, Operation> operationEntry : path.getOperationMap().entrySet()){
|
||||
HttpMethod httpMethod = operationEntry.getKey();
|
||||
Operation operation = operationEntry.getValue();
|
||||
if(operation != null) {
|
||||
List<String> tags = operation.getTags();
|
||||
Validate.notEmpty(tags, "Path operations must have tags, if you want to group by tags! The operation '%s %s' has not tags.", httpMethod, resourcePath);
|
||||
for (String tag : tags) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Added path operation '{} {}' to tag '{}'", httpMethod, resourcePath, tag);
|
||||
}
|
||||
pathsGroupedByTag.put(tag, Pair.of(resourcePath, pathEntry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pathsGroupedByTag;
|
||||
}
|
||||
}
|
||||
42
src/main/resources/lang/labels_en.properties
Normal file
@@ -0,0 +1,42 @@
|
||||
definitions=Definitions
|
||||
json_schema=JSON Schema
|
||||
xml_schema=XML Schema
|
||||
|
||||
default_column=Default
|
||||
required_column=Required
|
||||
schema_column=Schema
|
||||
name_column=Name
|
||||
description_column=Description
|
||||
produces=Produces
|
||||
consumes=Consumes
|
||||
tags=Tags
|
||||
|
||||
overview=Overview
|
||||
current_version=Version information
|
||||
version=Version\:\u0020
|
||||
contact_information=Contact information
|
||||
contact_name=Contact\:\u0020
|
||||
contact_email=Contact Email\:\u0020
|
||||
license_information=License information
|
||||
license=License\:\u0020
|
||||
license_url=License URL\:\u0020
|
||||
terms_of_service=Terms of service\:\u0020
|
||||
uri_scheme=URI scheme
|
||||
host=Host\:\u0020
|
||||
base_path=BasePath\:\u0020
|
||||
schemes=Schemes\:\u0020
|
||||
|
||||
paths=Paths
|
||||
resources=Resources
|
||||
parameters=Parameters
|
||||
responses=Responses
|
||||
example_curl=Example CURL request
|
||||
example_request=Example HTTP request
|
||||
example_response=Example HTTP response
|
||||
type_column=Type
|
||||
http_code_column=HTTP Code
|
||||
request_example_file_name=http-request
|
||||
response_example_file_name=http-response
|
||||
curl_example_file_name=curl-request
|
||||
description_file_name=description
|
||||
parameter=Parameter
|
||||
42
src/main/resources/lang/labels_ru.properties
Normal file
@@ -0,0 +1,42 @@
|
||||
definitions=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u044F
|
||||
json_schema=JSON \u0441\u0445\u0435\u043C\u0430
|
||||
xml_schema=XML \u0441\u0445\u0435\u043C\u0430
|
||||
|
||||
default_column=\u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
|
||||
required_column=\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E
|
||||
schema_column=\u0421\u0445\u0435\u043C\u0430
|
||||
name_column=\u0418\u043C\u044F
|
||||
description_column=\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435
|
||||
produces=\u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442
|
||||
consumes=\u041F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442
|
||||
tags=\u0422\u044D\u0433\u0438
|
||||
|
||||
overview=\u041E\u0431\u0437\u043E\u0440
|
||||
current_version=\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E \u0432\u0435\u0440\u0441\u0438\u0438
|
||||
version=\u0412\u0435\u0440\u0441\u0438\u044F\:\u0020
|
||||
contact_information=\u041A\u043E\u043D\u0442\u0430\u043A\u0442\u043D\u0430\u044F \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F
|
||||
contact_name=\u041A\u043E\u043D\u0442\u0430\u043A\u0442\:\u0020
|
||||
contact_email=Email \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u0430\:\u0020
|
||||
license_information=\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E \u043B\u0438\u0446\u0435\u043D\u0446\u0438\u0438
|
||||
license=\u041B\u0438\u0446\u0435\u043D\u0437\u0438\u044F\:\u0020
|
||||
license_url=URL \u043B\u0438\u0446\u0435\u043D\u0437\u0438\u0438\:\u0020
|
||||
terms_of_service=\u0423\u0441\u043B\u043E\u0432\u0438\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F\:\u0020
|
||||
uri_scheme=\u0421\u0445\u0435\u043C\u0430 URI
|
||||
host=\u0423\u0437\u0435\u043B\:\u0020
|
||||
base_path=\u041E\u0441\u043D\u043E\u0432\u043D\u043E\u0439 \u043F\u0443\u0442\u044C\:\u0020
|
||||
schemes=\u0421\u0445\u0435\u043C\u044B\:\u0020
|
||||
|
||||
paths=\u041F\u0443\u0442\u0438
|
||||
resources=\u041E\u0442\u0432\u0435\u0442\u044B
|
||||
parameters=\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B
|
||||
responses=\u041E\u0442\u0432\u0435\u0442\u044B
|
||||
example_curl=\u041F\u0440\u0438\u043C\u0435\u0440 CURL \u0437\u0430\u043F\u0440\u043E\u0441\u0430
|
||||
example_request=\u041F\u0440\u0438\u043C\u0435\u0440 HTTP \u0437\u0430\u043F\u0440\u043E\u0441\u0430
|
||||
example_response=\u041F\u0440\u0438\u043C\u0435\u0440 HTTP \u0437\u0430\u043F\u0440\u043E\u0441\u0430
|
||||
type_column=\u0422\u0438\u043F
|
||||
http_code_column=HTTP \u043A\u043E\u0434
|
||||
request_example_file_name=http-request
|
||||
response_example_file_name=http-response
|
||||
curl_example_file_name=curl-request
|
||||
description_file_name=\u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435
|
||||
parameter=\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440
|
||||
@@ -24,6 +24,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import io.github.robwin.markup.builder.MarkupLanguage;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
@@ -37,10 +38,29 @@ import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
|
||||
import static org.assertj.core.api.BDDAssertions.assertThat;
|
||||
|
||||
public class Swagger2MarkupConverterTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConversionFromString() throws IOException {
|
||||
//Given
|
||||
String swaggerJsonString = IOUtils.toString(getClass().getResourceAsStream("/json/swagger.json"));
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
Swagger2MarkupConverter.fromString(swaggerJsonString).build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
|
||||
//Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConversion() throws IOException {
|
||||
//Given
|
||||
@@ -57,11 +77,46 @@ public class Swagger2MarkupConverterTest {
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocGroupedByTags() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger.json").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
//When
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath())
|
||||
.withPathsGroupedBy(GroupBy.TAGS)
|
||||
.build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
|
||||
//Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocGroupedByTagsWithMissingTag() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger_missing_tag.json").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
//When
|
||||
try {
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath())
|
||||
.withPathsGroupedBy(GroupBy.TAGS)
|
||||
.build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
// If NullPointerException was not thrown, test would fail the specified message
|
||||
failBecauseExceptionWasNotThrown(NullPointerException.class);
|
||||
} catch (Exception e) {
|
||||
assertThat(e).hasMessage("Path operations must have tags, if you want to group by tags! The operation 'PUT /pets' has not tags.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOldSwaggerSpec2AsciiDocConversion() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger_12.json").getFile());
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/error_swagger_12.json").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
@@ -187,7 +242,7 @@ public class Swagger2MarkupConverterTest {
|
||||
public void testSwagger2MarkdownConversionWithSeparatedDefinitions() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger.json").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
File outputDirectory = new File("build/docs/markdown/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
@@ -208,7 +263,7 @@ public class Swagger2MarkupConverterTest {
|
||||
public void testSwagger2MarkdownConversionHandlesComposition() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger.json").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
File outputDirectory = new File("build/docs/markdown/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
@@ -238,6 +293,24 @@ public class Swagger2MarkupConverterTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConversionWithRussianOutputLanguage() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger.json").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath())
|
||||
.withOutputLanguage(Language.RU)
|
||||
.build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
|
||||
//Then
|
||||
assertThat(new String(Files.readAllBytes(Paths.get(outputDirectory + File.separator + "definitions.adoc"))))
|
||||
.contains("== Определения");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a markdown document to search, this checks to see if the specified tables
|
||||
* have all of the expected fields listed.
|
||||
|
||||
108
src/test/resources/json/error_swagger_12.json
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"apiVersion": "1",
|
||||
"swaggerVersion": "1.2",
|
||||
"basePath": "http://localhost:8082/query-rs",
|
||||
"resourcePath": "/query-services",
|
||||
"apis": [
|
||||
{
|
||||
"path": "/query-services/timesheet",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "testTimesheet",
|
||||
"responseClass": "void",
|
||||
"nickname": "testTimeSheet",
|
||||
"position": 0,
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"required": false,
|
||||
"allowMultiple": false,
|
||||
"dataType": "TimesheetEntryWireBase",
|
||||
"paramType": "body"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"models": {
|
||||
"TimesheetEntryWireBase": {
|
||||
"id": "TimesheetEntryWireBase",
|
||||
"name": "TimesheetEntryWireBase",
|
||||
"qualifiedType": "com.yt.nss.rest.domain.test.TimesheetEntryWireBase",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"qualifiedType": "java.lang.String",
|
||||
"position": 0,
|
||||
"allowableValues": {
|
||||
"values": [
|
||||
"STRING"
|
||||
],
|
||||
"valueType": "LIST"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Basic class for timesheet entry",
|
||||
"baseModel": "java.lang.Void",
|
||||
"discriminator": "type",
|
||||
"subTypes": [
|
||||
"com.yt.nss.rest.domain.test.TimesheetProjectEntryWire",
|
||||
"com.yt.nss.rest.domain.test.TimesheetAdminEntryWire"
|
||||
]
|
||||
},
|
||||
"TimesheetProjectEntryWire": {
|
||||
"id": "TimesheetProjectEntryWire",
|
||||
"name": "TimesheetProjectEntryWire",
|
||||
"qualifiedType": "com.yt.nss.rest.domain.test.TimesheetProjectEntryWire",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"qualifiedType": "java.lang.String",
|
||||
"position": 0,
|
||||
"allowableValues": {
|
||||
"values": [
|
||||
"STRING"
|
||||
],
|
||||
"valueType": "LIST"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"TimesheetAdminEntryWire": {
|
||||
"id": "TimesheetAdminEntryWire",
|
||||
"name": "TimesheetAdminEntryWire",
|
||||
"qualifiedType": "com.yt.nss.rest.domain.test.TimesheetAdminEntryWire",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"qualifiedType": "java.lang.String",
|
||||
"position": 0,
|
||||
"allowableValues": {
|
||||
"values": [
|
||||
"STRING"
|
||||
],
|
||||
"valueType": "LIST"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"position": 1
|
||||
}
|
||||
@@ -18,6 +18,20 @@
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "pet",
|
||||
"description": "Pet resource"
|
||||
},
|
||||
{
|
||||
"name": "store",
|
||||
"description": "Store resource"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"description": "User resource"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"post": {
|
||||
|
||||
883
src/test/resources/json/swagger_missing_tag.json
Normal file
@@ -0,0 +1,883 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is a sample server Petstore server.\n\n[Learn about Swagger](http://swagger.wordnik.com) or join the IRC channel `#swagger` on irc.freenode.net.\n\nFor this sample, you can use the api key `special-key` to test the authorization filters\n",
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore API",
|
||||
"termsOfService": "http://helloreverb.com/terms/",
|
||||
"contact": {
|
||||
"name": "apiteam@wordnik.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
}
|
||||
},
|
||||
"host": "petstore.swagger.wordnik.com",
|
||||
"basePath": "/v2",
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "pet",
|
||||
"description": "Pet resource"
|
||||
},
|
||||
{
|
||||
"name": "store",
|
||||
"description": "Store resource"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"description": "User resource"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"pet"
|
||||
],
|
||||
"summary": "Add a new pet to the store",
|
||||
"description": "",
|
||||
"operationId": "addPet",
|
||||
"consumes": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "Pet object that needs to be added to the store",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"405": {
|
||||
"description": "Invalid input"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"petstore_auth": [
|
||||
"write_pets",
|
||||
"read_pets"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"summary": "Update an existing pet",
|
||||
"description": "",
|
||||
"operationId": "updatePet",
|
||||
"consumes": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "Pet object that needs to be added to the store",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Invalid ID supplied"
|
||||
},
|
||||
"404": {
|
||||
"description": "Pet not found"
|
||||
},
|
||||
"405": {
|
||||
"description": "Validation exception"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"petstore_auth": [
|
||||
"write_pets",
|
||||
"read_pets"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/pets/findByStatus": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"pet"
|
||||
],
|
||||
"summary": "Finds Pets by status",
|
||||
"description": "Multiple status values can be provided with comma seperated strings",
|
||||
"operationId": "findPetsByStatus",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "status",
|
||||
"description": "Status values that need to be considered for filter",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/FoundPets"
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid status value"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"petstore_auth": [
|
||||
"write_pets",
|
||||
"read_pets"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/pets/findByTags": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"pet"
|
||||
],
|
||||
"summary": "Finds Pets by tags",
|
||||
"description": "Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.",
|
||||
"operationId": "findPetsByTags",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "tags",
|
||||
"description": "Tags to filter by",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/FoundPets"
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid tag value"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"petstore_auth": [
|
||||
"write_pets",
|
||||
"read_pets"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/pets/{petId}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"pet"
|
||||
],
|
||||
"summary": "Find pet by ID",
|
||||
"description": "Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions",
|
||||
"operationId": "getPetById",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/parameters/petId"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid ID supplied"
|
||||
},
|
||||
"404": {
|
||||
"description": "Pet not found"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"api_key": []
|
||||
},
|
||||
{
|
||||
"petstore_auth": [
|
||||
"write_pets",
|
||||
"read_pets"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"pet"
|
||||
],
|
||||
"summary": "Updates a pet in the store with form data",
|
||||
"description": "",
|
||||
"operationId": "updatePetWithForm",
|
||||
"consumes": [
|
||||
"application/x-www-form-urlencoded"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "petId",
|
||||
"description": "ID of pet that needs to be updated",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "formData",
|
||||
"name": "name",
|
||||
"description": "Updated name of the pet",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "formData",
|
||||
"name": "status",
|
||||
"description": "Updated status of the pet",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"405": {
|
||||
"description": "Invalid input"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"petstore_auth": [
|
||||
"write_pets",
|
||||
"read_pets"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"pet"
|
||||
],
|
||||
"summary": "Deletes a pet",
|
||||
"description": "",
|
||||
"operationId": "deletePet",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "header",
|
||||
"name": "api_key",
|
||||
"description": "",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "petId",
|
||||
"description": "Pet id to delete",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Invalid pet value"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"petstore_auth": [
|
||||
"write_pets",
|
||||
"read_pets"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/stores/order": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"store"
|
||||
],
|
||||
"summary": "Place an order for a pet",
|
||||
"description": "",
|
||||
"operationId": "placeOrder",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "order placed for purchasing the pet",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Order"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Order"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid Order"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/stores/order/{orderId}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"store"
|
||||
],
|
||||
"summary": "Find purchase order by ID",
|
||||
"description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions",
|
||||
"operationId": "getOrderById",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "orderId",
|
||||
"description": "ID of pet that needs to be fetched",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Order"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid ID supplied"
|
||||
},
|
||||
"404": {
|
||||
"description": "Order not found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"store"
|
||||
],
|
||||
"summary": "Delete purchase order by ID",
|
||||
"description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors",
|
||||
"operationId": "deleteOrder",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "orderId",
|
||||
"description": "ID of the order that needs to be deleted",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Invalid ID supplied"
|
||||
},
|
||||
"404": {
|
||||
"description": "Order not found"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Create user",
|
||||
"description": "This can only be done by the logged in user.",
|
||||
"operationId": "createUser",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "Created user object",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "successful operation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/createWithArray": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Creates list of users with given input array",
|
||||
"description": "",
|
||||
"operationId": "createUsersWithArrayInput",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "List of user object",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "successful operation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/createWithList": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Creates list of users with given input array",
|
||||
"description": "",
|
||||
"operationId": "createUsersWithListInput",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "List of user object",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "successful operation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/login": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Logs user into the system",
|
||||
"description": "",
|
||||
"operationId": "loginUser",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "username",
|
||||
"description": "The user name for login",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"default": "testUser"
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "password",
|
||||
"description": "The password for login in clear text",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"default": "testPassword"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid username/password supplied"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/logout": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Logs out current logged in user session",
|
||||
"description": "",
|
||||
"operationId": "logoutUser",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "successful operation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{username}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Get user by user name",
|
||||
"description": "",
|
||||
"operationId": "getUserByName",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "username",
|
||||
"description": "The name that needs to be fetched. Use user1 for testing.",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"default": "testUser"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid username supplied"
|
||||
},
|
||||
"404": {
|
||||
"description": "User not found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Updated user",
|
||||
"description": "This can only be done by the logged in user.",
|
||||
"operationId": "updateUser",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "username",
|
||||
"description": "name that need to be deleted",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "Updated user object",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Invalid user supplied"
|
||||
},
|
||||
"404": {
|
||||
"description": "User not found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Delete user",
|
||||
"description": "This can only be done by the logged in user.",
|
||||
"operationId": "deleteUser",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "username",
|
||||
"description": "The name that needs to be deleted",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Invalid username supplied"
|
||||
},
|
||||
"404": {
|
||||
"description": "User not found"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"api_key": {
|
||||
"type": "apiKey",
|
||||
"name": "api_key",
|
||||
"in": "header"
|
||||
},
|
||||
"petstore_auth": {
|
||||
"type": "oauth2",
|
||||
"authorizationUrl": "http://petstore.swagger.wordnik.com/api/oauth/dialog",
|
||||
"flow": "implicit",
|
||||
"scopes": {
|
||||
"write_pets": "modify pets in your account",
|
||||
"read_pets": "read your pets"
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses":{
|
||||
"FoundPets": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters":{
|
||||
"petId": {
|
||||
"in": "path",
|
||||
"name": "petId",
|
||||
"description": "ID of the pet",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Identified": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"User": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Identified"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"firstName": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastName": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"userStatus": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "User Status"
|
||||
},
|
||||
"pictures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "byte"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Category": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pet": {
|
||||
"description" : "Test description",
|
||||
"required": [
|
||||
"name",
|
||||
"photoUrls"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/Category"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "doggie"
|
||||
},
|
||||
"photoUrls": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Tag"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "pet status in the store"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Tag": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Order": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"petId": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"quantity": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"shipDate": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Order Status"
|
||||
},
|
||||
"complete": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/test/resources/yaml/swagger_overwrites.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
description: TODO
|
||||
version: 0.0.1
|
||||
title: API Spec
|
||||
termsOfService: TODO
|
||||
basePath: /v1
|
||||
schemes:
|
||||
- http
|
||||
paths:
|
||||
/aaa:
|
||||
post:
|
||||
tags:
|
||||
- AAA
|
||||
summary: TODO
|
||||
description: TODO
|
||||
operationId: aaa
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: body
|
||||
name: body
|
||||
description: TODO
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/AAA'
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
'405':
|
||||
description: Invalid data
|
||||
definitions:
|
||||
AAA:
|
||||
allOf:
|
||||
- $ref: '#/definitions/BBB'
|
||||
- type: object
|
||||
properties:
|
||||
propA:
|
||||
type: string
|
||||
propB:
|
||||
type: string
|
||||
BBB:
|
||||
type: object
|
||||
properties:
|
||||
propA:
|
||||
type: string
|
||||