Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d387b3e80 | ||
|
|
1e6be2f26d | ||
|
|
e56f824cd2 | ||
|
|
d38014f4b5 | ||
|
|
b331062fa6 | ||
|
|
88df748451 | ||
|
|
5384197bd1 | ||
|
|
2b5d4b7fe9 | ||
|
|
c15d074488 | ||
|
|
b0c3aa71b9 | ||
|
|
32d85ffb55 | ||
|
|
59fcd61738 | ||
|
|
7ce969882d | ||
|
|
ee70cdb94f | ||
|
|
f21fce7730 | ||
|
|
c426c7b341 | ||
|
|
1231d1e0c2 | ||
|
|
66073aebb8 | ||
|
|
882d9e5709 | ||
|
|
ba9ec45d9e | ||
|
|
f2787a41ae | ||
|
|
3469523225 | ||
|
|
1dc9a07cb9 | ||
|
|
a34807e5c9 | ||
|
|
85ef33a720 | ||
|
|
3163c077a1 | ||
|
|
fbb446875d | ||
|
|
e8cdcabffe | ||
|
|
832813d40a | ||
|
|
e2f28bca7d | ||
|
|
3ed894688c | ||
|
|
bb7422d755 | ||
|
|
b2f3f4a6c7 | ||
|
|
f21794a253 | ||
|
|
ffa96e56a5 | ||
|
|
38e50dfe77 | ||
|
|
1d3ec2d5a3 | ||
|
|
495751433b | ||
|
|
de7d73eae9 | ||
|
|
f825cf9613 | ||
|
|
6e32056c26 | ||
|
|
85bc2aa8f9 | ||
|
|
d56de83368 | ||
|
|
065e65a31c | ||
|
|
a68980bc76 |
395
README.adoc
395
README.adoc
@@ -1,9 +1,8 @@
|
||||
= Swagger2Markup
|
||||
:author: Robert Winkler
|
||||
:version: 0.6.3
|
||||
:hardbreaks:
|
||||
|
||||
image:https://travis-ci.org/RobWin/swagger2markup.svg?branch=master["Build Status", link="https://travis-ci.org/RobWin/swagger2markup"] image:https://coveralls.io/repos/RobWin/swagger2markup/badge.svg["Coverage Status", link="https://coveralls.io/r/RobWin/swagger2markup"] image:https://api.bintray.com/packages/robwin/maven/swagger2markup/images/download.svg[link="https://bintray.com/robwin/maven/swagger2markup/_latestVersion"] image:http://img.shields.io/badge/license-ASF2-blue.svg["Apache License 2", link="http://www.apache.org/licenses/LICENSE-2.0.txt"] image:https://img.shields.io/badge/Twitter-rbrtwnklr-blue.svg["Twitter", link="https://twitter.com/rbrtwnklr"] image:https://badges.gitter.im/Join%20Chat.svg[link="https://gitter.im/RobWin/swagger2markup?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
|
||||
image:https://travis-ci.org/Swagger2Markup/swagger2markup.svg?branch=master["Build Status", link="https://travis-ci.org/Swagger2Markup/swagger2markup"] image:https://coveralls.io/repos/RobWin/swagger2markup/badge.svg["Coverage Status", link="https://coveralls.io/r/RobWin/swagger2markup"] image:https://api.bintray.com/packages/robwin/maven/swagger2markup/images/download.svg[link="https://bintray.com/robwin/maven/swagger2markup/_latestVersion"] image:http://img.shields.io/badge/license-ASF2-blue.svg["Apache License 2", link="http://www.apache.org/licenses/LICENSE-2.0.txt"] image:https://img.shields.io/badge/Twitter-rbrtwnklr-blue.svg["Twitter", link="https://twitter.com/rbrtwnklr"] image:https://badges.gitter.im/Join%20Chat.svg[link="https://gitter.im/RobWin/swagger2markup?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
|
||||
|
||||
|
||||
== Overview
|
||||
@@ -12,387 +11,47 @@ The primary goal of this project is to *simplify the generation of an up-to-date
|
||||
|
||||
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/tree/master/samples/java-jersey2[Swagger JAX-RS], https://github.com/springfox/springfox[springfox] or https://github.com/spring-projects/spring-restdocs[spring-restdocs]. See https://github.com/RobWin/swagger2markup#usage-guide[usage guide] below. If you are are Gradle user, you can also use the https://github.com/RobWin/swagger2markup-gradle-plugin[Swagger2Markup Gradle Plugin].
|
||||
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 also use https://github.com/jbake-org/jbake[JBake], https://github.com/tomchristie/mkdocs[MkDocs], https://github.com/rtfd/readthedocs.org[ReadTheDocs] or https://github.com/tripit/slate[slate] to publish your AsciiDoc or Markdown documentation.
|
||||
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].
|
||||
|
||||
The project requires at least JDK 7.
|
||||
|
||||
== Usage guide
|
||||
== Reference documentation
|
||||
- http://swagger2markup.readme.io/[Reference Documentation]
|
||||
- https://github.com/Swagger2Markup/swagger2markup/blob/master/RELEASENOTES.adoc[Release notes]
|
||||
|
||||
=== Adding Swagger2Markup to your project
|
||||
The project is published in JCenter and Maven Central.
|
||||
== Contributing
|
||||
|
||||
==== Maven
|
||||
=== Community contributions
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<repositories>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>central</id>
|
||||
<name>bintray</name>
|
||||
<url>http://jcenter.bintray.com</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
Pull requests are welcome.
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.robwin</groupId>
|
||||
<artifactId>swagger2markup</artifactId>
|
||||
<version>0.6.3</version>
|
||||
</dependency>
|
||||
----
|
||||
* 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).
|
||||
|
||||
==== Gradle
|
||||
* 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.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
* 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.
|
||||
|
||||
compile "io.github.robwin:swagger2markup:0.6.3"
|
||||
----
|
||||
=== Questions
|
||||
You can ask questions about Swagger2Markup in https://gitter.im/Swagger2Markup/swagger2markup[Gitter].
|
||||
|
||||
=== Using Swagger2Markup
|
||||
=== Bugs
|
||||
If you believe you have found a bug, please take a moment to search the existing issues. If no one else has reported the problem, please open a new issue that describes the problem in detail and, ideally, includes a test that reproduces it.
|
||||
|
||||
Using the Swagger2MarkupConverter is simple. For example, if you are using https://github.com/spring-projects/spring-boot[Spring Boot] and https://github.com/springfox/springfox[springfox], you can generate your Swagger JSON file during the integration or unit test phase, convert the Swagger JSON file into AsciiDoc, convert AsciiDoc into HTML and PDF, copy the documentation into the Jar file and serve it as static content. That way there is no runtime overhead and there are no additional runtime libraries required.
|
||||
The quickest way to get started is to look at the demo project https://github.com/RobWin/spring-swagger2markup-demo[spring-swagger2markup-demo]. The demo shows how to generate static docs (HTML5 and PDF) with the https://github.com/RobWin/swagger2markup-gradle-plugin[Swagger2Markup Gradle Plugin] and serve them as static content in a Spring Boot App under http://localhost:9080/docs/index.html and http://localhost:9080/docs/index.pdf.
|
||||
|
||||
==== Generate Markup during an integration test
|
||||
|
||||
Swagger2MarkupConverter can be used to make a request to a Swagger endpoint during an integration test. The Swagger2MarkupConverter writes the generated documents into the folder `src/docs/asciidoc/generated` or `src/docs/markdown/generated`.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = Application.class)
|
||||
@IntegrationTest
|
||||
@WebAppConfiguration
|
||||
public class Swagger2MarkupTest {
|
||||
|
||||
@Test
|
||||
public void convertRemoteSwaggerToAsciiDoc() {
|
||||
// Remote Swagger source
|
||||
// Default is AsciiDoc
|
||||
Swagger2MarkupConverter.from("http://localhost:8080/v2/api-docs").build()
|
||||
.intoFolder("src/docs/asciidoc/generated");
|
||||
|
||||
// Then validate that three AsciiDoc files have been created
|
||||
String[] files = new File("src/docs/asciidoc/generated").list();
|
||||
assertThat(files).hasSize(3)
|
||||
.containsAll(Arrays.asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertRemoteSwaggerToMarkdown() {
|
||||
// Remote Swagger source
|
||||
// Markdown
|
||||
Swagger2MarkupConverter.from("http://localhost:8080/v2/api-docs")
|
||||
.withMarkupLanguage(MarkupLanguage.MARKDOWN).build()
|
||||
.intoFolder("src/docs/markdown/generated");
|
||||
|
||||
// Then validate that three Markdown files have been created
|
||||
String[] files = new File("src/docs/markdown/generated").list();
|
||||
assertThat(files).hasSize(3)
|
||||
.containsAll(Arrays.asList("definitions.md", "overview.md", "paths.md"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertLocalSwaggerToAsciiDoc() {
|
||||
//Local Swagger source
|
||||
//Default is AsciiDoc
|
||||
String location = Swagger2MarkupTest.class.getResource("/json/swagger.json").getPath();
|
||||
Swagger2MarkupConverter.from(location).build()
|
||||
.intoFolder("src/docs/asciidoc/generated");
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
==== Generate Markup during an unit test with springfox-staticdocs
|
||||
|
||||
Spring's MVC Test framework can also be used to make a request to a https://github.com/springfox/springfox[springfox] Swagger endpoint during an unit test. A custom ResultHandler `Swagger2MarkupResultHandler` is used to automatically convert the Swagger JSON response into an AsciiDoc document. The custom ResultHandler is part of `springfox-staticdocs`. That way you also verify that your Swagger endpoint is working.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@WebAppConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
|
||||
public class Swagger2MarkupTest {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertSwaggerToAsciiDoc() throws Exception {
|
||||
this.mockMvc.perform(get("/v2/api-docs")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc/generated").build())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertSwaggerToMarkdown() throws Exception {
|
||||
this.mockMvc.perform(get("/v2/api-docs")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/markdown/generated")
|
||||
.withMarkupLanguage(MarkupLanguage.MARKDOWN).build())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
==== Gradle dependencies
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
dependencies {
|
||||
...
|
||||
compile 'io.springfox:springfox-swagger2:2.0.0'
|
||||
testCompile 'io.springfox:springfox-staticdocs:2.0.0'
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
==== Springfox configuration
|
||||
|
||||
The following is a complete https://github.com/springfox/springfox[springfox] configuration to use Swagger in a Spring Boot Application.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@EnableSwagger2
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Docket restApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
.paths(ant("/api/**"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.title("Petstore API Title")
|
||||
.description("Petstore API Description")
|
||||
.contact("Petstore API Contact Email")
|
||||
.version("1.0.0")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
==== Combine generated documentation with your hand-written documentation
|
||||
|
||||
The following shows how you can combine the generated documentation with your hand-written AsciiDoc documentation. You have to create an `index.adoc` (it must not be necessarily called index). To include the programmatically generated snippets in your documentation, you use Asciidoc's `include` macro. The `generated` variable is configured below.
|
||||
|
||||
image::images/generated_docs.PNG[generated_docs]
|
||||
|
||||
You can generate your HTML5 and PDF documentation via the https://github.com/asciidoctor/asciidoctor-gradle-plugin[asciidoctor-gradle-plugin] or https://github.com/asciidoctor/asciidoctor-maven-plugin[asciidoctor-maven-plugin]. The following listing shows how to configure the Asciidoctor Gradle plugin. By default it searches for AsciiDoc files in `src/docs/asciidoc` and puts the HTML and PDF output into `build/asciidoc/html5` and `build/asciidoc/pdf`. The `generated` attribute is used to replace the variable in the `index.adoc` file and to provide configurable access to the generated snippets.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
ext {
|
||||
generatedDocumentation = file('src/docs/asciidoc/generated')
|
||||
}
|
||||
|
||||
test {
|
||||
outputs.dir generatedDocumentation
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
dependsOn test
|
||||
sources {
|
||||
include 'index.adoc'
|
||||
}
|
||||
backends = ['html5', 'pdf']
|
||||
attributes = [
|
||||
doctype: 'book',
|
||||
toc: 'left',
|
||||
toclevels: '2',
|
||||
numbered: '',
|
||||
sectlinks: '',
|
||||
sectanchors: '',
|
||||
generated: generatedDocumentation
|
||||
]
|
||||
}
|
||||
----
|
||||
|
||||
You can copy the output into your Jar file and serve the documentation as static content under `http://localhost:9080/docs/index.html` and `http://localhost:9080/docs/index.pdf`.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
jar {
|
||||
dependsOn asciidoctor
|
||||
from ("${asciidoctor.outputDir}/html5") {
|
||||
into 'static/docs'
|
||||
}
|
||||
from ("${asciidoctor.outputDir}/pdf") {
|
||||
into 'static/docs'
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
==== Include spring-restdocs example snippets
|
||||
|
||||
Swagger2Markup can be used together with https://github.com/spring-projects/spring-restdocs[spring-restdocs]. Swagger2Markup can include the generated CURL request, HTTP request and HTTP response example snippets from spring-restdocs into the generated AsciiDoc document. See https://github.com/spring-projects/spring-restdocs[spring-restdocs] how to configure it. Currently spring-restdocs does only support AsciiDoc.
|
||||
|
||||
Let's say you have a Swagger-annotated Spring RestController method with an ApiOperation value: `Add a new pet to the store`
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@RequestMapping(method = POST)
|
||||
@ApiOperation(value = "Add a new pet to the store")
|
||||
@ApiResponses(value = {@ApiResponse(code = 405, message = "Invalid input")})
|
||||
public ResponseEntity<String> addPet(
|
||||
@ApiParam(value = "Pet object that needs to be added to the store", required = true) @RequestBody Pet pet) {
|
||||
petData.add(pet);
|
||||
return Responses.ok("SUCCESS");
|
||||
}
|
||||
----
|
||||
|
||||
By convention the target folder of the generated request and response example files must be similar to the value of the ApiOperation, but with underscores and lowercase. For example a folder for `@ApiOperation(value = "Add a new pet to the store")` must be called `add_a_new_pet_to_the_store`.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Test
|
||||
public void findPetById() throws Exception {
|
||||
this.mockMvc.perform(post("/api/pet/").content(createPet())
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(RestDocumentation.document("add_a_new_pet_to_the_store"))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
----
|
||||
|
||||
The system property `org.springframework.restdocs.outputDir` is used to control the output base directory where the folder `add_a_new_pet_to_the_store` and the generated snippets are written to. The spring-restdocs output base directory is configured as follows:
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
ext {
|
||||
generatedDocumentation = file('src/docs/asciidoc/generated')
|
||||
}
|
||||
|
||||
test {
|
||||
systemProperty 'org.springframework.restdocs.outputDir', generatedDocumentation
|
||||
outputs.dir generatedDocumentation
|
||||
}
|
||||
----
|
||||
|
||||
You must specify the base output directory of spring-restdocs with the builder method `withExamples("src/docs/asciidoc/generated")`.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Test
|
||||
public void convertToAsciiDoc() throws Exception {
|
||||
this.mockMvc.perform(get("/v2/api-docs")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc")
|
||||
.withExamples("src/docs/asciidoc/generated").build())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
----
|
||||
|
||||
By convention the Swagger2MarkupConverter searches for a method annotated with `@ApiOperation(value = "Add a new pet to the store")` in a folder called `src/docs/asciidoc/generated/add_a_new_pet_to_the_store` and includes the `http-request.adoc` and `http-response.adoc` files, if they are available.
|
||||
|
||||
The AsciiDoc HTML output would look as follows:
|
||||
|
||||
image::images/springrestdocs_examples.PNG[springrestdocs]
|
||||
|
||||
==== Include hand-written descriptions into the generated documentation
|
||||
|
||||
If you don't want to pollute your source code with Swagger annotations just to add descriptions to Operations, Parameters and Model definitions. Like here:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@RequestMapping(method = PUT)
|
||||
@ApiOperation(value = "Update an existing pet")
|
||||
@ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid ID supplied"),
|
||||
@ApiResponse(code = 404, message = "Pet not found"),
|
||||
@ApiResponse(code = 405, message = "Validation exception")})
|
||||
public ResponseEntity<String> updatePet(
|
||||
@ApiParam(value = "Pet object that needs to be added to the store", required = true) @RequestBody Pet pet) {
|
||||
petData.add(pet);
|
||||
return Responses.ok("SUCCESS");
|
||||
}
|
||||
----
|
||||
|
||||
You can create hand-written descriptions and include them with the builder method `withDescriptions()` into your documentation by specifying the base folder of your documentation.
|
||||
|
||||
[source, java]
|
||||
----
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).withDescriptions("src/docs/asciidoc").build()
|
||||
.intoFolder("src/docs/asciidoc");
|
||||
----
|
||||
|
||||
By convention you need two folders `paths` and `definitions` inside your description base folder.
|
||||
The `paths` folder contains sub folders for all operations. The folder must be named similar to the value of the ApiOperation annotation, but with underscores and lowercase.
|
||||
For example a folder for `@ApiOperation(value = "Update an existing pet")` must be called `update_an_existing_pet`.
|
||||
|
||||
The `definitions` folder contains sub folders for all models. The folder must be named similar to the name of the Model, but lowercase.
|
||||
For example a folder for a model called `User` must be called `user`.
|
||||
|
||||
You can have a global description file for each operation or model. And you can have one description file per operation parameter or model property.
|
||||
For example:
|
||||
|
||||
image::images/handwritten_descriptions.PNG[handwritten_descriptions]
|
||||
|
||||
The AsciiDoc HTML output would look as follows:
|
||||
|
||||
image::images/handwritten_descr_asciidoc.PNG[handwritten_descr_asciidoc]
|
||||
|
||||
==== Include JSON and XML Schema files.
|
||||
Swagger2Markup can also include JSON and XML Schema files into the generated document.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Swagger2MarkupConverter.from("http://localhost:8080/api-docs").withSchemas("src/docs/schemas").build()
|
||||
.intoFolder("src/docs/asciidoc");
|
||||
----
|
||||
|
||||
You can create the schema files during a unit test as follows:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
RestDocumented restDocumented = RestDocumented.fromProperties();
|
||||
restDocumented.documentJsonSchema(MailStorageQuota.class, "src/docs/schemas");
|
||||
restDocumented.documentXmlSchema(MailStorageQuota.class, "src/docs/schemas");
|
||||
----
|
||||
|
||||
I will make RestDocumented public soon. RestDocumented creates a MailStorageQuota.xsd and MailStorageQuota.json file in the folder `src/docs/schemas`. The Swagger2MarkupConverter will include the JSON and XML Schemas, if a Swagger Operation uses the MailStorageQuota class as input or output.
|
||||
|
||||
== Screenshots
|
||||
|
||||
=== Swagger source
|
||||
image::images/swagger_json.PNG[swagger_json]
|
||||
|
||||
=== Generated AsciiDoc
|
||||
image::images/asciidoc.PNG[asciidoc]
|
||||
|
||||
=== Generated Markdown
|
||||
image::images/markdown.PNG[markdown]
|
||||
|
||||
=== Generated HTML using AsciidoctorJ
|
||||
image::images/asciidoc_html.PNG[asciidoc_html]
|
||||
|
||||
=== Generated PDF using AsciidoctorJ
|
||||
image::images/asciidoc_pdf.PNG[asciidoc_pdf]
|
||||
=== Enhancements
|
||||
If you’d like an enhancement to be made to Swagger2Markup, pull requests are most welcome. The source code is on GitHub. You may want to search the existing issues and pull requests to see if the enhancement is already being worked on. You may also want to open a new issue to discuss a possible enhancement before work on it begins.
|
||||
|
||||
== License
|
||||
|
||||
|
||||
@@ -46,11 +46,25 @@
|
||||
* Updated swagger-parser from v1.0.5 to v1.0.6
|
||||
* Support for default values in Parameters and Model properties
|
||||
|
||||
== Version 0.6.1
|
||||
=== Version 0.6.1
|
||||
* Updated swagger-parser from v1.0.6 to v1.0.8
|
||||
|
||||
== Version 0.6.2
|
||||
=== Version 0.6.2
|
||||
* curl-request.adoc from spring-restdocs is also added to the example chapters
|
||||
|
||||
== Version 0.6.3
|
||||
=== Version 0.6.3
|
||||
* Added possibility to write object definitions to separate files. Issue #19
|
||||
|
||||
== Version 0.7.0
|
||||
* Added support for both reference models and composed models
|
||||
|
||||
=== Version 0.7.1
|
||||
* Workaround: If the type of a BodyParameter is String and not a Model, the schema is null and lost. Therefore the fallback type of a BodyParameter is String now.
|
||||
|
||||
== Version 0.8.0
|
||||
* 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
|
||||
* Updated swagger-parser from v1.0.8 to v1.0.13
|
||||
* Support for global responses and parameters
|
||||
@@ -5,15 +5,15 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
|
||||
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.7'
|
||||
classpath 'io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE'
|
||||
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.8'
|
||||
classpath 'io.spring.gradle:dependency-management-plugin:0.5.3.RELEASE'
|
||||
classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.0.1'
|
||||
classpath 'org.asciidoctor:asciidoctorj:1.5.2'
|
||||
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
|
||||
}
|
||||
}
|
||||
description = 'swagger2markup Build'
|
||||
version = '0.6.3'
|
||||
version = '0.9.0'
|
||||
group = 'io.github.robwin'
|
||||
|
||||
apply plugin: 'java'
|
||||
@@ -54,7 +54,7 @@ dependencies {
|
||||
dependencyManagement {
|
||||
dependencies {
|
||||
dependency "io.github.robwin:markup-document-builder:0.1.4"
|
||||
dependency "io.swagger:swagger-compat-spec-parser:1.0.8"
|
||||
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"
|
||||
|
||||
@@ -21,9 +21,8 @@ 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.builder.document.DefinitionsDocument;
|
||||
import io.github.robwin.swagger2markup.builder.document.OverviewDocument;
|
||||
import io.github.robwin.swagger2markup.builder.document.PathsDocument;
|
||||
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;
|
||||
@@ -155,8 +154,8 @@ 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()
|
||||
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()));
|
||||
}
|
||||
|
||||
@@ -246,6 +245,16 @@ public class Swagger2MarkupConverter {
|
||||
this.schemasFolderPath = schemasFolderPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the Swagger data in any useful way
|
||||
* @param preProcessor function object to mutate the swagger object
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
public Builder preProcessSwagger(Consumer<Swagger> preProcessor) {
|
||||
preProcessor.accept(this.swagger);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,9 +18,12 @@
|
||||
*/
|
||||
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.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;
|
||||
@@ -118,11 +121,11 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
String definitionName = definitionsEntry.getKey();
|
||||
if(StringUtils.isNotBlank(definitionName)) {
|
||||
if (checkThatDefinitionIsNotInIgnoreList(definitionName)) {
|
||||
definition(definitionName, definitionsEntry.getValue(), docBuilder);
|
||||
definition(definitions, definitionName, definitionsEntry.getValue(), docBuilder);
|
||||
definitionSchema(definitionName, docBuilder);
|
||||
if (separatedDefinitionsEnabled) {
|
||||
MarkupDocBuilder defDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage);
|
||||
definition(definitionName, definitionsEntry.getValue(), defDocBuilder);
|
||||
definition(definitions, definitionName, definitionsEntry.getValue(), defDocBuilder);
|
||||
definitionSchema(definitionName, defDocBuilder);
|
||||
defDocBuilder.writeToFile(outputDirectory, definitionName.toLowerCase(), StandardCharsets.UTF_8);
|
||||
if (logger.isInfoEnabled()) {
|
||||
@@ -159,15 +162,14 @@ public class DefinitionsDocument extends MarkupDocument {
|
||||
* @param model the Swagger Model of the definition
|
||||
* @param docBuilder the docbuilder do use for output
|
||||
*/
|
||||
private void definition(String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
private void definition(Map<String, Model> definitions, String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
docBuilder.sectionTitleLevel2(definitionName);
|
||||
descriptionSection(definitionName, model, docBuilder);
|
||||
propertiesSection(definitionName, model, docBuilder);
|
||||
|
||||
propertiesSection(definitions, definitionName, model, docBuilder);
|
||||
}
|
||||
|
||||
private void propertiesSection(String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
Map<String, Property> properties = model.getProperties();
|
||||
private void propertiesSection(Map<String, Model> definitions, String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
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));
|
||||
@@ -187,6 +189,31 @@ 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();
|
||||
return definitions.containsKey(ref)
|
||||
? getAllProperties(definitions, definitions.get(model.getReference()))
|
||||
: null;
|
||||
}
|
||||
if(model instanceof ComposedModel) {
|
||||
ComposedModel composedModel = (ComposedModel)model;
|
||||
ImmutableMap.Builder<String, Property> allProperties = ImmutableMap.builder();
|
||||
if(composedModel.getAllOf() != null) {
|
||||
for(Model innerModel : composedModel.getAllOf()) {
|
||||
Map<String, Property> innerProperties = getAllProperties(definitions, innerModel);
|
||||
if(innerProperties != null) {
|
||||
allProperties.putAll(innerProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
return allProperties.build();
|
||||
}
|
||||
else {
|
||||
return model.getProperties();
|
||||
}
|
||||
}
|
||||
|
||||
private void descriptionSection(String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
|
||||
if(handWrittenDescriptionsEnabled){
|
||||
String description = handWrittenPathDescription(definitionName.toLowerCase(), DESCRIPTION_FILE_NAME);
|
||||
|
||||
@@ -105,22 +105,23 @@ public class OverviewDocument extends MarkupDocument {
|
||||
this.markupDocBuilder.newLine();
|
||||
}
|
||||
|
||||
this.markupDocBuilder.sectionTitleLevel2(URI_SCHEME);
|
||||
if(StringUtils.isNotBlank(swagger.getHost())){
|
||||
this.markupDocBuilder.textLine(HOST + swagger.getHost());
|
||||
}
|
||||
if(StringUtils.isNotBlank(swagger.getBasePath())){
|
||||
this.markupDocBuilder.textLine(BASE_PATH + swagger.getBasePath());
|
||||
}
|
||||
if(CollectionUtils.isNotEmpty(swagger.getSchemes())){
|
||||
List<String> schemes = new ArrayList<>();
|
||||
for(Scheme scheme : swagger.getSchemes()){
|
||||
schemes.add(scheme.toString());
|
||||
if(StringUtils.isNotBlank(swagger.getHost()) || StringUtils.isNotBlank(swagger.getBasePath()) || CollectionUtils.isNotEmpty(swagger.getSchemes())) {
|
||||
this.markupDocBuilder.sectionTitleLevel2(URI_SCHEME);
|
||||
if (StringUtils.isNotBlank(swagger.getHost())) {
|
||||
this.markupDocBuilder.textLine(HOST + swagger.getHost());
|
||||
}
|
||||
this.markupDocBuilder.textLine(SCHEMES + StringUtils.join(schemes, ", "));
|
||||
|
||||
if (StringUtils.isNotBlank(swagger.getBasePath())) {
|
||||
this.markupDocBuilder.textLine(BASE_PATH + swagger.getBasePath());
|
||||
}
|
||||
if (CollectionUtils.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.newLine();
|
||||
}
|
||||
this.markupDocBuilder.newLine();
|
||||
|
||||
if(CollectionUtils.isNotEmpty(swagger.getTags())){
|
||||
this.markupDocBuilder.sectionTitleLevel2(TAGS);
|
||||
@@ -130,8 +131,9 @@ public class OverviewDocument extends MarkupDocument {
|
||||
String description = tag.getDescription();
|
||||
if(StringUtils.isNoneBlank(description)){
|
||||
tags.add(name + ": " + description);
|
||||
}else{
|
||||
tags.add(name);
|
||||
}
|
||||
tags.add(name);
|
||||
}
|
||||
this.markupDocBuilder.unorderedList(tags);
|
||||
this.markupDocBuilder.newLine();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.github.robwin.swagger2markup.utils;
|
||||
|
||||
/**
|
||||
* Java 8 style Consumer functional interface
|
||||
*/
|
||||
public interface Consumer<T> {
|
||||
|
||||
/**
|
||||
* The function itself
|
||||
* @param t the function argument
|
||||
*/
|
||||
void accept(T t);
|
||||
|
||||
}
|
||||
@@ -39,7 +39,12 @@ public final class ParameterUtils {
|
||||
if(parameter instanceof BodyParameter){
|
||||
BodyParameter bodyParameter = (BodyParameter)parameter;
|
||||
Model model = bodyParameter.getSchema();
|
||||
type = ModelUtils.getType(model, markupLanguage);
|
||||
if(model != null){
|
||||
type = ModelUtils.getType(model, markupLanguage);
|
||||
}else{
|
||||
type = "string";
|
||||
}
|
||||
|
||||
}
|
||||
else if(parameter instanceof AbstractSerializableParameter){
|
||||
AbstractSerializableParameter serializableParameter = (AbstractSerializableParameter)parameter;
|
||||
|
||||
@@ -18,21 +18,27 @@
|
||||
*/
|
||||
package io.github.robwin.swagger2markup;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
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.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.BDDAssertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public class Swagger2MarkupConverterTest {
|
||||
|
||||
@Test
|
||||
@@ -51,6 +57,23 @@ public class Swagger2MarkupConverterTest {
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOldSwaggerSpec2AsciiDocConversion() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger_12.json").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
|
||||
//Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConversionWithDescriptionsAndExamples() throws IOException {
|
||||
//Given
|
||||
@@ -68,6 +91,44 @@ public class Swagger2MarkupConverterTest {
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConversionDoesNotContainUriScheme() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/yaml/swagger_should_not_contain_uri_scheme.yaml").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
|
||||
//Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
|
||||
assertThat(new String(Files.readAllBytes(Paths.get(outputDirectory + File.separator + "overview.adoc"))))
|
||||
.doesNotContain("=== URI scheme");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConversionContainsUriScheme() throws IOException {
|
||||
//Given
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/yaml/swagger_should_contain_uri_scheme.yaml").getFile());
|
||||
File outputDirectory = new File("build/docs/asciidoc/generated");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
|
||||
//Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(3).containsAll(asList("definitions.adoc", "overview.adoc", "paths.adoc"));
|
||||
|
||||
assertThat(new String(Files.readAllBytes(Paths.get(outputDirectory + File.separator + "overview.adoc"))))
|
||||
.contains("=== URI scheme");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwagger2MarkdownConversion() throws IOException {
|
||||
//Given
|
||||
@@ -115,8 +176,8 @@ public class Swagger2MarkupConverterTest {
|
||||
|
||||
//Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(8).containsAll(
|
||||
asList("definitions.adoc", "overview.adoc", "paths.adoc",
|
||||
assertThat(directories).hasSize(9).containsAll(
|
||||
asList("definitions.adoc", "overview.adoc", "paths.adoc", "identified.adoc",
|
||||
"user.adoc", "category.adoc", "pet.adoc", "tag.adoc", "order.adoc"));
|
||||
assertThat(new String(Files.readAllBytes(Paths.get(outputDirectory + File.separator + "definitions.adoc"))))
|
||||
.contains(new String(Files.readAllBytes(Paths.get(outputDirectory + File.separator + "user.adoc"))));
|
||||
@@ -136,13 +197,105 @@ public class Swagger2MarkupConverterTest {
|
||||
|
||||
//Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(8).containsAll(
|
||||
asList("definitions.md", "overview.md", "paths.md",
|
||||
assertThat(directories).hasSize(9).containsAll(
|
||||
asList("definitions.md", "overview.md", "paths.md", "identified.md",
|
||||
"user.md", "category.md", "pet.md", "tag.md", "order.md"));
|
||||
assertThat(new String(Files.readAllBytes(Paths.get(outputDirectory + File.separator + "definitions.md"))))
|
||||
.contains(new String(Files.readAllBytes(Paths.get(outputDirectory + File.separator + "user.md"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
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");
|
||||
FileUtils.deleteQuietly(outputDirectory);
|
||||
|
||||
//When
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).withSeparatedDefinitions().
|
||||
withMarkupLanguage(MarkupLanguage.MARKDOWN).build()
|
||||
.intoFolder(outputDirectory.getAbsolutePath());
|
||||
|
||||
// Then
|
||||
String[] directories = outputDirectory.list();
|
||||
assertThat(directories).hasSize(9).containsAll(
|
||||
asList("definitions.md", "overview.md", "paths.md", "identified.md",
|
||||
"user.md", "category.md", "pet.md", "tag.md", "order.md"));
|
||||
verifyMarkdownContainsFieldsInTables(
|
||||
outputDirectory + File.separator + "definitions.md",
|
||||
ImmutableMap.<String, Set<String>>builder()
|
||||
.put("Identified", ImmutableSet.of("id"))
|
||||
.put("User", ImmutableSet.of("id", "username", "firstName",
|
||||
"lastName", "email", "password", "phone", "userStatus"))
|
||||
.build());
|
||||
verifyMarkdownContainsFieldsInTables(
|
||||
outputDirectory + File.separator + "user.md",
|
||||
ImmutableMap.<String, Set<String>>builder()
|
||||
.put("User", ImmutableSet.of("id", "username", "firstName",
|
||||
"lastName", "email", "password", "phone", "userStatus"))
|
||||
.build()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a markdown document to search, this checks to see if the specified tables
|
||||
* have all of the expected fields listed.
|
||||
*
|
||||
* @param doc path of markdown document to inspect
|
||||
* @param fieldsByTable map of table name (header) to field names expected
|
||||
* to be found in that table.
|
||||
* @throws IOException if the markdown document could not be read
|
||||
*/
|
||||
private static void verifyMarkdownContainsFieldsInTables(String doc, Map<String, Set<String>> fieldsByTable) throws IOException {
|
||||
final List<String> lines = Files.readAllLines(Paths.get(doc), Charset.defaultCharset());
|
||||
final Map<String, Set<String>> fieldsLeftByTable = Maps.newHashMap();
|
||||
for(Map.Entry<String, Set<String>> entry : fieldsByTable.entrySet()) {
|
||||
fieldsLeftByTable.put(entry.getKey(), Sets.newHashSet(entry.getValue()));
|
||||
}
|
||||
String inTable = null;
|
||||
for(String line : lines) {
|
||||
// If we've found every field we care about, quit early
|
||||
if(fieldsLeftByTable.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Transition to a new table if we encounter a header
|
||||
final String currentHeader = getTableHeader(line);
|
||||
if(inTable == null || currentHeader != null) {
|
||||
inTable = currentHeader;
|
||||
}
|
||||
|
||||
// If we're in a table that we care about, inspect this potential table row
|
||||
if (inTable != null && fieldsLeftByTable.containsKey(inTable)){
|
||||
// If we're still in a table, read the row and check for the field name
|
||||
// NOTE: If there was at least one pipe, then there's at least 2 fields
|
||||
String[] parts = line.split("\\|");
|
||||
if(parts.length > 1) {
|
||||
final String fieldName = parts[1];
|
||||
final Set<String> fieldsLeft = fieldsLeftByTable.get(inTable);
|
||||
// Mark the field as found and if this table has no more fields to find,
|
||||
// remove it from the "fieldsLeftByTable" map to mark the table as done
|
||||
if(fieldsLeft.remove(fieldName) && fieldsLeft.isEmpty()) {
|
||||
fieldsLeftByTable.remove(inTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After reading the file, if there were still types, fail
|
||||
if(!fieldsLeftByTable.isEmpty()) {
|
||||
fail(String.format("Markdown file '%s' did not contain expected fields (by table): %s",
|
||||
doc, fieldsLeftByTable));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getTableHeader(String line) {
|
||||
return line.startsWith("###")
|
||||
? line.replace("###", "").trim()
|
||||
: null;
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testSwagger2HtmlConversion() throws IOException {
|
||||
|
||||
@@ -134,13 +134,7 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
"$ref": "#/responses/FoundPets"
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid status value"
|
||||
@@ -183,13 +177,7 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
"$ref": "#/responses/FoundPets"
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid tag value"
|
||||
@@ -219,12 +207,7 @@
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "petId",
|
||||
"description": "ID of pet that needs to be fetched",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
"$ref": "#/parameters/petId"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -729,38 +712,77 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"User": {
|
||||
"Identified": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
|
||||
54
src/test/resources/json/swagger_12.json
Normal file
54
src/test/resources/json/swagger_12.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"apiVersion" : "0.0.1-SNAPSHOT",
|
||||
"swaggerVersion" : "1.2",
|
||||
"basePath" : "",
|
||||
"resourcePath" : "/resource/x/v2",
|
||||
"apis" : [ {
|
||||
"path" : "/resource/x/v2",
|
||||
"operations" : [ {
|
||||
"method" : "POST",
|
||||
"nickname" : "createX",
|
||||
"type" : "string",
|
||||
"parameters" : [ {
|
||||
"type": "string",
|
||||
"description" : "The x in JSON format",
|
||||
"paramType" : "body",
|
||||
"name" : "body",
|
||||
"required" : true
|
||||
} ],
|
||||
"summary" : "Creates a x x.",
|
||||
"notes" : "If id already exists, the x is updated.",
|
||||
"responseMessages" : [ {
|
||||
"code" : 200,
|
||||
"message" : "ok"
|
||||
}, {
|
||||
"code" : 500,
|
||||
"message" : "error"
|
||||
} ],
|
||||
"consumes" : [ "application/json" ]
|
||||
} ]
|
||||
}, {
|
||||
"path" : "/resource/x/v2/{id}",
|
||||
"operations" : [ {
|
||||
"method" : "GET",
|
||||
"nickname" : "getX",
|
||||
"type" : "string",
|
||||
"parameters" : [ {
|
||||
"type" : "integer",
|
||||
"description" : "A valid x x UUID",
|
||||
"paramType" : "path",
|
||||
"name" : "id",
|
||||
"required" : true
|
||||
} ],
|
||||
"summary" : "Gets the x x with the specified id.",
|
||||
"responseMessages" : [ {
|
||||
"code" : 200,
|
||||
"message" : "ok"
|
||||
}, {
|
||||
"code" : 404,
|
||||
"message" : "not found"
|
||||
} ],
|
||||
"produces" : [ "application/json" ]
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
version: "0.0.0"
|
||||
title: Test - Should contain URI scheme
|
||||
|
||||
host: localhost
|
||||
|
||||
schemes:
|
||||
- http
|
||||
- https
|
||||
|
||||
basePath: /api
|
||||
|
||||
paths:
|
||||
/test:
|
||||
get:
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
@@ -0,0 +1,13 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
version: "0.0.0"
|
||||
title: Test - Should not contain URI scheme
|
||||
|
||||
paths:
|
||||
/test:
|
||||
get:
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
Reference in New Issue
Block a user