Compare commits

...

32 Commits

Author SHA1 Message Date
Robert Winkler
90880a00f3 Added possibility to write object definitions to separate files. Issue #19 2015-06-23 09:24:15 +02:00
Robert Winkler
675dd762a8 Merge pull request #19 from sg-ad/SplitDefinitionFiles
Adding possibility to write object definitions to separate files.
2015-06-23 08:45:25 +02:00
Sebastien Gagnon
7cdd436b10 Add possibility to write object definitions to separate files. 2015-06-22 16:30:05 -04:00
Robert Winkler
a78126c551 Added twitter batch 2015-06-16 08:29:50 +02:00
Robert Winkler
f729bf15c3 Added gitter hook 2015-06-10 12:42:02 +02:00
Robert Winkler
ce129703f8 Updated documentation 2015-06-10 09:09:59 +02:00
Robert Winkler
c99bba90a4 Updated swagger-parser from v1.0.6 to v1.0.8 2015-06-10 08:57:29 +02:00
Robert Winkler
914a8ed5fb Merge remote-tracking branch 'origin/master' 2015-06-08 08:51:37 +02:00
Robert Winkler
85b95c189e Updated swagger-parser from v1.0.6 to v1.0.8 2015-06-08 08:51:19 +02:00
Robert Winkler
8722bdc8cb Delete SUMMARY..adoc 2015-05-27 20:12:42 +02:00
Robert Winkler
2ce724cdd0 Update null 2015-05-27 20:08:08 +02:00
Robert Winkler
922b6b8534 Create SUMMARY..adoc 2015-05-27 20:07:51 +02:00
Robert Winkler
a05f4b2e29 Update README.adoc 2015-05-27 20:05:06 +02:00
Robert Winkler
e4e32f3f9f Updated documentation 2015-05-21 11:05:07 +02:00
Robert Winkler
bf0b864c0d * Updated swagger-parser from v1.0.5 to v1.0.6
* Support for default values in Parameters and Model properties
2015-05-21 11:00:02 +02:00
Robert Winkler
4948c8bea1 * Swagger License is not mandatory anymore
* Updated markup-document-builder from v0.1.3 to v0.1.4
2015-05-20 10:12:21 +02:00
Robert Winkler
9397bf4255 Merge remote-tracking branch 'origin/master' 2015-05-18 12:40:13 +02:00
Robert Winkler
a6d85d7b0c * Swagger License is not mandatory anymore
* Updated markup-document-builder from v0.1.3 to v0.1.4
2015-05-18 12:40:05 +02:00
Robert Winkler
16371443e8 Updated documentation 2015-05-11 07:18:43 +02:00
Robert Winkler
5738d86988 Updated documentation 2015-05-11 07:05:38 +02:00
Robert Winkler
e1bf3fbe94 Updated documentation 2015-05-10 20:11:23 +02:00
Robert Winkler
7ce98408f4 Updated documentation 2015-05-10 20:07:07 +02:00
Robert Winkler
1a7b219c40 Updated documentation 2015-05-10 20:02:37 +02:00
Robert Winkler
8a8e93f3ca Updated documentation 2015-05-08 21:36:58 +02:00
Robert Winkler
1d95d9afc2 Updates documentation 2015-05-07 11:42:37 +02:00
Robert Winkler
5b49187cb7 Updated documentation 2015-05-06 09:11:33 +02:00
Robert Winkler
7b99565636 Updated documentation 2015-05-06 09:07:19 +02:00
Robert Winkler
32980d1476 Updated documentation 2015-05-06 09:05:04 +02:00
Robert Winkler
490a6d974f Updated documentation 2015-05-06 08:52:53 +02:00
Robert Winkler
4e971817a2 Updated documentation 2015-05-06 08:51:20 +02:00
Robert Winkler
f649553727 Updated documentation 2015-05-05 16:26:28 +02:00
Robert Winkler
3576a80872 Added Swagger2Markup Gradle Plugin 2015-05-05 15:59:54 +02:00
16 changed files with 385 additions and 246 deletions

View File

@@ -4,4 +4,12 @@ jdk:
before_install:
- chmod +x gradlew
after_success:
- ./gradlew jacocoTestReport coveralls
- ./gradlew jacocoTestReport coveralls
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/9c620e84679284b7d621
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false
Your unique webhook url for this service:

View File

@@ -1,10 +1,10 @@
= Swagger2Markup
:author: Robert Winkler
:version: 0.5.1
:version: 0.6.3
:hardbreaks:
image:https://travis-ci.org/RobWin/swagger2markup.svg["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://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/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"]
== Overview
@@ -12,15 +12,15 @@ 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 design-first Swagger YAML file into a human-readable format and combine it with hand-written documentation. As an alternative, you can choose the implementation-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 usage guide below and <<integration-with-spring-restdocs, Integration with spring-restdocs>>.
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].
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/aalmiray/markdown-gradle-plugin[markdown-gradle-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 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.
The project requires at least JDK 7.
== Usage
== Usage guide
=== Adding Swagger2Markup to your project
The project is published in JCenter and Maven Central.
@@ -43,7 +43,7 @@ The project is published in JCenter and Maven Central.
<dependency>
<groupId>io.github.robwin</groupId>
<artifactId>swagger2markup</artifactId>
<version>0.5.1</version>
<version>0.6.3</version>
</dependency>
----
@@ -55,17 +55,17 @@ repositories {
jcenter()
}
compile "io.github.robwin:swagger2markup:0.5.1"
compile "io.github.robwin:swagger2markup:0.6.3"
----
=== Using Swagger2Markup
Using the Swagger2MarkupConverter is simple. For example, you can generate your AsciiDoc or Markdown documentation using https://github.com/spring-projects/spring-boot[Spring Boot] and https://github.com/springfox/springfox[springfox] during the unit or integration test phase, 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 library dependencies 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 Swagger2Markup 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.
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` or `src/docs/markdown`.
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]
----
@@ -77,11 +77,12 @@ public class Swagger2MarkupTest {
@Test
public void convertRemoteSwaggerToAsciiDoc() {
//Remote Swagger source
//Default is AsciiDoc
// Remote Swagger source
// Default is AsciiDoc
Swagger2MarkupConverter.from("http://localhost:8080/v2/api-docs").build()
.intoFolder("src/docs/asciidoc/generated");
//Then
// 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"));
@@ -89,14 +90,14 @@ public class Swagger2MarkupTest {
@Test
public void convertRemoteSwaggerToMarkdown() {
//Remote Swagger source
//Markdown
// Remote Swagger source
// Markdown
Swagger2MarkupConverter.from("http://localhost:8080/v2/api-docs")
.withMarkupLanguage(MarkupLanguage.MARKDOWN).build()
.intoFolder("src/docs/asciidoc/generated");
.intoFolder("src/docs/markdown/generated");
//Then
String[] files = new File("src/docs/asciidoc/generated").list();
// 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"));
}
@@ -105,16 +106,16 @@ public class Swagger2MarkupTest {
public void convertLocalSwaggerToAsciiDoc() {
//Local Swagger source
//Default is AsciiDoc
File file = new File(Swagger2MarkupTest.class.getResource("/json/swagger.json").getFile());
Swagger2MarkupConverter.from(file.getAbsolutePath()).build()
.intoFolder("src/docs/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` now. That way you also verify that your Swagger endpoint is working.
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]
----
@@ -137,7 +138,7 @@ public class Swagger2MarkupTest {
public void convertSwaggerToAsciiDoc() throws Exception {
this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc").build())
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc/generated").build())
.andExpect(status().isOk());
}
@@ -145,7 +146,7 @@ public class Swagger2MarkupTest {
public void convertSwaggerToMarkdown() throws Exception {
this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc")
.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/markdown/generated")
.withMarkupLanguage(MarkupLanguage.MARKDOWN).build())
.andExpect(status().isOk());
}
@@ -200,20 +201,19 @@ public class Application {
==== Combine generated documentation with your hand-written documentation
The following shows how you can combine the generated documentation with your hand-written documentation with AsciiDoc. 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.
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]. 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 provide configurable access to the generated snippets. The system property is used to control the base directory to which the documents are generated.
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]
[source,groovy]
----
ext {
generatedDocumentation = file('src/docs/asciidoc/generated')
}
test {
systemProperty 'io.springfox.staticdocs.outputDir', generatedDocumentation
outputs.dir generatedDocumentation
}
@@ -237,7 +237,7 @@ asciidoctor {
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]
[source,groovy]
----
jar {
dependsOn asciidoctor
@@ -250,6 +250,71 @@ jar {
}
----
==== 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:
@@ -292,82 +357,7 @@ The AsciiDoc HTML output would look as follows:
image::images/handwritten_descr_asciidoc.PNG[handwritten_descr_asciidoc]
== Examples
== 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]
== Integration with spring-restdocs
Swagger2Markup can be used together with https://github.com/spring-projects/spring-restdocs[spring-restdocs]. Swagger2Markup can include the generated HTTP request and response 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");
}
----
The target folder of the generated request and response example files must be `add_a_new_pet_to_the_store` (similar to the value of the ApiOperation, but with underscores and lowercase).
[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 spring-restdocs output directory is configured as follows:
[source]
----
org.springframework.restdocs.outputDir = src/docs/asciidoc/generated
----
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("swagger_adoc")
.withExamples("src/docs/asciidoc/generated").build())
.andExpect(status().isOk());
}
----
The Swagger2MarkupConverter searches for a Swagger ApiOperation with 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.
=== Generated AsciiDoc
image::images/springrestdocs_examples.PNG[springrestdocs]
== Integration of JSON and XML Schema files.
==== Include JSON and XML Schema files.
Swagger2Markup can also include JSON and XML Schema files into the generated document.
[source,java]
@@ -387,6 +377,23 @@ 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]
== License
Copyright 2015 Robert Winkler

View File

@@ -32,5 +32,25 @@
== Version 0.5.0
* Support for including hand-written descriptions instead of using Swagger Annotations for descriptions
== Version 0.5.1
* Bugfix: Definition name must be lowercase so that descriptions file can be found
=== Version 0.5.1
* Bugfix: Definition name must be lowercase so that descriptions file can be found
=== Version 0.5.2
* Swagger License is not mandatory anymore
* Updated markup-document-builder from v0.1.3 to v0.1.4
=== Version 0.5.3
* Fixed compiler warning: [options] bootstrap class path not set in conjunction with -source 1.7
== Version 0.6.0
* Updated swagger-parser from v1.0.5 to v1.0.6
* Support for default values in Parameters and Model properties
== Version 0.6.1
* Updated swagger-parser from v1.0.6 to v1.0.8
== Version 0.6.2
* curl-request.adoc from spring-restdocs is also added to the example chapters
== Version 0.6.3
* Added possibility to write object definitions to separate files. Issue #19

View File

@@ -5,15 +5,15 @@ buildscript {
}
dependencies {
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.6'
classpath 'io.spring.gradle:dependency-management-plugin:0.5.0.RELEASE'
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.7'
classpath 'io.spring.gradle:dependency-management-plugin:0.5.1.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.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
}
}
description = 'swagger2markup Build'
version = '0.5.1'
version = '0.6.3'
group = 'io.github.robwin'
apply plugin: 'java'
@@ -53,8 +53,8 @@ dependencies {
dependencyManagement {
dependencies {
dependency "io.github.robwin:markup-document-builder:0.1.3"
dependency "io.swagger:swagger-compat-spec-parser:1.0.5"
dependency "io.github.robwin:markup-document-builder:0.1.4"
dependency "io.swagger:swagger-compat-spec-parser:1.0.8"
dependency "commons-collections:commons-collections:3.2.1"
dependency "commons-io:commons-io:2.4"
dependency "junit:junit:4.11"
@@ -117,5 +117,5 @@ tasks.asciidoctor {
}
task wrapper(type: Wrapper) {
gradleVersion = '2.2.1'
gradleVersion = '2.4'
}

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#Fri Feb 13 13:57:45 CET 2015
#Mon Jun 08 08:20:09 CEST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip

View File

@@ -20,14 +20,14 @@ package io.github.robwin.swagger2markup;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wordnik.swagger.models.Swagger;
import com.wordnik.swagger.util.Json;
import com.wordnik.swagger.util.Yaml;
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.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;
@@ -46,6 +46,7 @@ public class Swagger2MarkupConverter {
private final String examplesFolderPath;
private final String schemasFolderPath;
private final String descriptionsFolderPath;
private final boolean separatedDefinitions;
private static final String OVERVIEW_DOCUMENT = "overview";
private static final String PATHS_DOCUMENT = "paths";
private static final String DEFINITIONS_DOCUMENT = "definitions";
@@ -56,13 +57,15 @@ public class Swagger2MarkupConverter {
* @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.
*/
Swagger2MarkupConverter(MarkupLanguage markupLanguage, Swagger swagger, String examplesFolderPath, String schemasFolderPath, String descriptionsFolderPath){
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;
}
/**
@@ -135,7 +138,7 @@ public class Swagger2MarkupConverter {
}
/**
* Writes a file for the Paths (API) and a file for the Definitions (Model)
* Builds all documents and writes them to a directory
* @param directory the directory where the generated file should be stored
* @throws IOException if a file cannot be written
@@ -143,18 +146,18 @@ public class Swagger2MarkupConverter {
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).build().writeToFile(directory, DEFINITIONS_DOCUMENT, StandardCharsets.UTF_8);
new DefinitionsDocument(swagger, markupLanguage, schemasFolderPath, descriptionsFolderPath, separatedDefinitions, directory).build().writeToFile(directory, DEFINITIONS_DOCUMENT, StandardCharsets.UTF_8);
}
/**
* Returns a file for the Paths (API) and a file for the Definitions (Model)
* Returns all documents as a String
* @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).build().toString()));
.concat(new DefinitionsDocument(swagger, markupLanguage, schemasFolderPath, schemasFolderPath, false, null).build().toString()));
}
@@ -163,6 +166,7 @@ public class Swagger2MarkupConverter {
private String examplesFolderPath;
private String schemasFolderPath;
private String descriptionsFolderPath;
private boolean separatedDefinitions;
private MarkupLanguage markupLanguage = MarkupLanguage.ASCIIDOC;
/**
@@ -172,6 +176,9 @@ public class Swagger2MarkupConverter {
*/
Builder(String swaggerLocation){
swagger = new SwaggerParser().read(swaggerLocation);
if(swagger == null){
throw new IllegalArgumentException("Failed to read the Swagger file. ");
}
}
/**
@@ -184,7 +191,7 @@ public class Swagger2MarkupConverter {
}
public Swagger2MarkupConverter build(){
return new Swagger2MarkupConverter(markupLanguage, swagger, examplesFolderPath, schemasFolderPath, descriptionsFolderPath);
return new Swagger2MarkupConverter(markupLanguage, swagger, examplesFolderPath, schemasFolderPath, descriptionsFolderPath, separatedDefinitions);
}
/**
@@ -209,6 +216,15 @@ public class Swagger2MarkupConverter {
return this;
}
/**
* In addition to the definitions file, also create separate definition files for each model definition.
* @return the Swagger2MarkupConverter.Builder
*/
public Builder withSeparatedDefinitions() {
this.separatedDefinitions = true;
return this;
}
/**
* Include examples into the Paths document
*

View File

@@ -18,23 +18,23 @@
*/
package io.github.robwin.swagger2markup.builder.document;
import com.wordnik.swagger.models.Model;
import com.wordnik.swagger.models.Swagger;
import com.wordnik.swagger.models.properties.Property;
import io.github.robwin.markup.builder.MarkupDocBuilder;
import io.github.robwin.markup.builder.MarkupDocBuilders;
import io.swagger.models.Model;
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 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;
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.*;
/**
* @author Robert Winkler
@@ -42,20 +42,22 @@ import java.util.Map;
public class DefinitionsDocument extends MarkupDocument {
private static final String DEFINITIONS = "Definitions";
private static final List<String> IGNORED_DEFINITIONS = Arrays.asList("Void");
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";
public static final String JSON_SCHEMA_EXTENSION = ".json";
public static final String XML_SCHEMA_EXTENSION = ".xsd";
public static final String JSON = "json";
public static final String XML = "xml";
private static final String JSON_SCHEMA_EXTENSION = ".json";
private static final String XML_SCHEMA_EXTENSION = ".xsd";
private static final String JSON = "json";
private static final String XML = "xml";
private static final String DESCRIPTION_FILE_NAME = "description";
private boolean schemasEnabled;
private String schemasFolderPath;
private boolean handWrittenDescriptionsEnabled;
private String descriptionsFolderPath;
private boolean separatedDefinitionsEnabled;
private String outputDirectory;
public DefinitionsDocument(Swagger swagger, MarkupLanguage markupLanguage, String schemasFolderPath, String descriptionsFolderPath){
public DefinitionsDocument(Swagger swagger, MarkupLanguage markupLanguage, String schemasFolderPath, String descriptionsFolderPath, boolean separatedDefinitionsEnabled, String outputDirectory){
super(swagger, markupLanguage);
if(StringUtils.isNotBlank(schemasFolderPath)){
this.schemasEnabled = true;
@@ -83,11 +85,23 @@ public class DefinitionsDocument extends MarkupDocument {
logger.debug("Include hand-written descriptions is disabled.");
}
}
this.separatedDefinitionsEnabled = separatedDefinitionsEnabled;
if(this.separatedDefinitionsEnabled){
if (logger.isDebugEnabled()) {
logger.debug("Create separated definition files is enabled.");
}
Validate.notEmpty(outputDirectory, "Output directory is required for separated definition files!");
}else{
if (logger.isDebugEnabled()) {
logger.debug("Create separated definition files is disabled.");
}
}
this.outputDirectory = outputDirectory;
}
@Override
public MarkupDocument build() throws IOException {
definitions(swagger.getDefinitions());
definitions(swagger.getDefinitions(), this.markupDocBuilder);
return this;
}
@@ -95,16 +109,26 @@ public class DefinitionsDocument extends MarkupDocument {
* Builds the Swagger definitions.
*
* @param definitions the Swagger definitions
* @param docBuilder the doc builder to use for output
*/
private void definitions(Map<String, Model> definitions) throws IOException {
private void definitions(Map<String, Model> definitions, MarkupDocBuilder docBuilder) throws IOException {
if(MapUtils.isNotEmpty(definitions)){
this.markupDocBuilder.sectionTitleLevel1(DEFINITIONS);
docBuilder.sectionTitleLevel1(DEFINITIONS);
for(Map.Entry<String, Model> definitionsEntry : definitions.entrySet()){
String definitionName = definitionsEntry.getKey();
if(StringUtils.isNotBlank(definitionName)) {
if (checkThatDefinitionIsNotInIgnoreList(definitionName)) {
definition(definitionName, definitionsEntry.getValue());
definitionSchema(definitionName);
definition(definitionName, definitionsEntry.getValue(), docBuilder);
definitionSchema(definitionName, docBuilder);
if (separatedDefinitionsEnabled) {
MarkupDocBuilder defDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage);
definition(definitionName, definitionsEntry.getValue(), defDocBuilder);
definitionSchema(definitionName, defDocBuilder);
defDocBuilder.writeToFile(outputDirectory, definitionName.toLowerCase(), StandardCharsets.UTF_8);
if (logger.isInfoEnabled()) {
logger.info("Separate definition file produced: {}", definitionName);
}
}
if (logger.isInfoEnabled()) {
logger.info("Definition processed: {}", definitionName);
}
@@ -133,52 +157,57 @@ public class DefinitionsDocument extends MarkupDocument {
*
* @param definitionName the name of the definition
* @param model the Swagger Model of the definition
* @param docBuilder the docbuilder do use for output
*/
private void definition(String definitionName, Model model) throws IOException {
this.markupDocBuilder.sectionTitleLevel2(definitionName);
descriptionSection(definitionName, model);
propertiesSection(definitionName, model);
private void definition(String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
docBuilder.sectionTitleLevel2(definitionName);
descriptionSection(definitionName, model, docBuilder);
propertiesSection(definitionName, model, docBuilder);
}
private void propertiesSection(String definitionName, Model model) throws IOException {
private void propertiesSection(String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
Map<String, Property> properties = model.getProperties();
List<String> headerAndContent = new ArrayList<>();
List<String> header = Arrays.asList(NAME_COLUMN, DESCRIPTION_COLUMN, SCHEMA_COLUMN, REQUIRED_COLUMN);
List<String> header = Arrays.asList(NAME_COLUMN, DESCRIPTION_COLUMN, REQUIRED_COLUMN, SCHEMA_COLUMN, DEFAULT_COLUMN);
headerAndContent.add(StringUtils.join(header, DELIMITER));
if(MapUtils.isNotEmpty(properties)){
for (Map.Entry<String, Property> propertyEntry : properties.entrySet()) {
Property property = propertyEntry.getValue();
String type = PropertyUtils.getType(property, markupLanguage);
String propertyName = propertyEntry.getKey();
List<String> content = Arrays.asList(propertyName, propertyDescription(definitionName, propertyName, property), type, Boolean.toString(property.getRequired()));
List<String> content = Arrays.asList(
propertyName,
propertyDescription(definitionName, propertyName, property),
Boolean.toString(property.getRequired()),
PropertyUtils.getType(property, markupLanguage),
PropertyUtils.getDefaultValue(property));
headerAndContent.add(StringUtils.join(content, DELIMITER));
}
this.markupDocBuilder.tableWithHeaderRow(headerAndContent);
docBuilder.tableWithHeaderRow(headerAndContent);
}
}
private void descriptionSection(String definitionName, Model model) throws IOException {
private void descriptionSection(String definitionName, Model model, MarkupDocBuilder docBuilder) throws IOException {
if(handWrittenDescriptionsEnabled){
String description = handWrittenPathDescription(definitionName.toLowerCase(), DESCRIPTION_FILE_NAME);
if(StringUtils.isNotBlank(description)){
this.markupDocBuilder.paragraph(description);
docBuilder.paragraph(description);
}else{
if (logger.isInfoEnabled()) {
logger.info("Hand-written description cannot be read. Trying to use description from Swagger source.");
}
modelDescription(model);
modelDescription(model, docBuilder);
}
}
else{
modelDescription(model);
modelDescription(model, docBuilder);
}
}
private void modelDescription(Model model) {
private void modelDescription(Model model, MarkupDocBuilder docBuilder) {
String description = model.getDescription();
if (StringUtils.isNotBlank(description)) {
this.markupDocBuilder.paragraph(description);
docBuilder.paragraph(description);
}
}
@@ -228,20 +257,20 @@ public class DefinitionsDocument extends MarkupDocument {
return null;
}
private void definitionSchema(String definitionName) throws IOException {
private void definitionSchema(String definitionName, MarkupDocBuilder docBuilder) throws IOException {
if(schemasEnabled) {
if (StringUtils.isNotBlank(definitionName)) {
schema(JSON_SCHEMA, schemasFolderPath, definitionName + JSON_SCHEMA_EXTENSION, JSON);
schema(XML_SCHEMA, schemasFolderPath, definitionName + XML_SCHEMA_EXTENSION, XML);
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) throws IOException {
private void schema(String title, String schemasFolderPath, String schemaName, String language, MarkupDocBuilder docBuilder) throws IOException {
java.nio.file.Path path = Paths.get(schemasFolderPath, schemaName);
if (Files.isReadable(path)) {
this.markupDocBuilder.sectionTitleLevel3(title);
this.markupDocBuilder.source(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim(), language);
docBuilder.sectionTitleLevel3(title);
docBuilder.source(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim(), language);
if (logger.isInfoEnabled()) {
logger.info("Schema file processed: {}", path);
}

View File

@@ -18,7 +18,7 @@
*/
package io.github.robwin.swagger2markup.builder.document;
import com.wordnik.swagger.models.Swagger;
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;
@@ -34,6 +34,7 @@ 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";

View File

@@ -18,7 +18,7 @@
*/
package io.github.robwin.swagger2markup.builder.document;
import com.wordnik.swagger.models.*;
import io.swagger.models.*;
import io.github.robwin.markup.builder.MarkupLanguage;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -90,7 +90,7 @@ public class OverviewDocument extends MarkupDocument {
}
License license = info.getLicense();
if(license != null) {
if(license != null && (StringUtils.isNotBlank(license.getName()) || StringUtils.isNotBlank(license.getUrl()))) {
this.markupDocBuilder.sectionTitleLevel2(LICENSE_INFORMATION);
if (StringUtils.isNotBlank(license.getName())) {
this.markupDocBuilder.textLine(LICENSE + license.getName());

View File

@@ -18,12 +18,12 @@
*/
package io.github.robwin.swagger2markup.builder.document;
import com.wordnik.swagger.models.Operation;
import com.wordnik.swagger.models.Path;
import com.wordnik.swagger.models.Response;
import com.wordnik.swagger.models.Swagger;
import com.wordnik.swagger.models.parameters.Parameter;
import com.wordnik.swagger.models.properties.Property;
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 io.github.robwin.swagger2markup.utils.ParameterUtils;
import io.github.robwin.swagger2markup.utils.PropertyUtils;
@@ -50,12 +50,14 @@ 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_REQUEST = "Example request";
private static final String EXAMPLE_RESPONSE = "Example response";
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";
@@ -195,13 +197,18 @@ public class PathsDocument extends MarkupDocument {
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);
List<String> header = Arrays.asList(TYPE_COLUMN, NAME_COLUMN, DESCRIPTION_COLUMN, REQUIRED_COLUMN, SCHEMA_COLUMN, DEFAULT_COLUMN);
headerAndContent.add(StringUtils.join(header, DELIMITER));
for(Parameter parameter : parameters){
String type = ParameterUtils.getType(parameter, markupLanguage);
String parameterType = WordUtils.capitalize(parameter.getIn() + PARAMETER);
// Table content row
List<String> content = Arrays.asList(parameterType, parameter.getName(), parameterDescription(operation, parameter), Boolean.toString(parameter.getRequired()), type);
List<String> content = Arrays.asList(
parameterType,
parameter.getName(),
parameterDescription(operation, parameter),
Boolean.toString(parameter.getRequired()), type,
ParameterUtils.getDefaultValue(parameter));
headerAndContent.add(StringUtils.join(content, DELIMITER));
}
this.markupDocBuilder.sectionTitleLevel3(PARAMETERS);
@@ -271,6 +278,12 @@ public class PathsDocument extends MarkupDocument {
String summary = operation.getSummary();
if(StringUtils.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);
}
String requestExample = example(exampleFolder, REQUEST_EXAMPLE_FILE_NAME);
if(StringUtils.isNotBlank(requestExample)){
this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_REQUEST);

View File

@@ -18,10 +18,10 @@
*/
package io.github.robwin.swagger2markup.utils;
import com.wordnik.swagger.models.ArrayModel;
import com.wordnik.swagger.models.Model;
import com.wordnik.swagger.models.ModelImpl;
import com.wordnik.swagger.models.RefModel;
import io.swagger.models.ArrayModel;
import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
import io.swagger.models.RefModel;
import io.github.robwin.markup.builder.MarkupLanguage;
import org.apache.commons.lang3.Validate;

View File

@@ -18,8 +18,11 @@
*/
package io.github.robwin.swagger2markup.utils;
import com.wordnik.swagger.models.Model;
import com.wordnik.swagger.models.parameters.*;
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;
@@ -38,60 +41,17 @@ public final class ParameterUtils {
Model model = bodyParameter.getSchema();
type = ModelUtils.getType(model, markupLanguage);
}
else if(parameter instanceof PathParameter){
PathParameter pathParameter = (PathParameter)parameter;
type = getTypeWithFormat(pathParameter.getType(), pathParameter.getFormat());
}
else if(parameter instanceof QueryParameter){
QueryParameter queryParameter = (QueryParameter)parameter;
List<String> enums = queryParameter.getEnum();
else if(parameter instanceof AbstractSerializableParameter){
AbstractSerializableParameter serializableParameter = (AbstractSerializableParameter)parameter;
List enums = serializableParameter.getEnum();
if(CollectionUtils.isNotEmpty(enums)){
type = "enum" + " (" + StringUtils.join(enums, ", ") + ")";
}else{
type = getTypeWithFormat(queryParameter.getType(), queryParameter.getFormat());
type = getTypeWithFormat(serializableParameter.getType(), serializableParameter.getFormat());
}
if(type.equals("array")){
String collectionFormat = queryParameter.getCollectionFormat();
type = collectionFormat + " " + PropertyUtils.getType(queryParameter.getItems(), markupLanguage) + " " + type;
}
}
else if(parameter instanceof HeaderParameter){
HeaderParameter headerParameter = (HeaderParameter)parameter;
List<String> enums = headerParameter.getEnum();
if(CollectionUtils.isNotEmpty(enums)){
type = "enum" + " (" + StringUtils.join(enums, ", ") + ")";
}else{
type = getTypeWithFormat(headerParameter.getType(), headerParameter.getFormat());
}
if(type.equals("array")){
String collectionFormat = headerParameter.getCollectionFormat();
type = collectionFormat + " " + PropertyUtils.getType(headerParameter.getItems(), markupLanguage) + " " + type;
}
}
else if(parameter instanceof FormParameter){
FormParameter formParameter = (FormParameter)parameter;
List<String> enums = formParameter.getEnum();
if(CollectionUtils.isNotEmpty(enums)){
type = "enum" + " (" + StringUtils.join(enums, ", ") + ")";
}else{
type = getTypeWithFormat(formParameter.getType(), formParameter.getFormat());
}
if(type.equals("array")){
String collectionFormat = formParameter.getCollectionFormat();
type = collectionFormat + " " + PropertyUtils.getType(formParameter.getItems(), markupLanguage) + " " + type;
}
}
else if(parameter instanceof CookieParameter){
CookieParameter cookieParameter = (CookieParameter)parameter;
List<String> enums = cookieParameter.getEnum();
if(CollectionUtils.isNotEmpty(enums)){
type = "enum" + " (" + StringUtils.join(enums, ", ") + ")";
}else{
type = getTypeWithFormat(cookieParameter.getType(), cookieParameter.getFormat());
}
if(type.equals("array")){
String collectionFormat = cookieParameter.getCollectionFormat();
type = collectionFormat + " " + PropertyUtils.getType(cookieParameter.getItems(), markupLanguage) + " " + type;
String collectionFormat = serializableParameter.getCollectionFormat();
type = collectionFormat + " " + PropertyUtils.getType(serializableParameter.getItems(), markupLanguage) + " " + type;
}
}
else if(parameter instanceof RefParameter){
@@ -101,16 +61,27 @@ public final class ParameterUtils {
default: return refParameter.getSimpleRef();
}
}
return type;
return StringUtils.defaultString(type);
}
private static String getTypeWithFormat(String typeWithoutFormat, String format) {
String type;
if(StringUtils.isNotBlank(format)){
type = typeWithoutFormat + " (" + format + ")";
type = StringUtils.defaultString(typeWithoutFormat) + " (" + format + ")";
}else{
type = typeWithoutFormat;
type = StringUtils.defaultString(typeWithoutFormat);
}
return type;
}
public static String getDefaultValue(Parameter parameter){
Validate.notNull(parameter, "property must not be null!");
String defaultValue = "";
if(parameter instanceof AbstractSerializableParameter){
AbstractSerializableParameter serializableParameter = (AbstractSerializableParameter)parameter;
defaultValue = serializableParameter.getDefaultValue();
}
return StringUtils.defaultString(defaultValue);
}
}

View File

@@ -18,16 +18,14 @@
*/
package io.github.robwin.swagger2markup.utils;
import com.wordnik.swagger.models.properties.ArrayProperty;
import com.wordnik.swagger.models.properties.Property;
import com.wordnik.swagger.models.properties.RefProperty;
import com.wordnik.swagger.models.properties.StringProperty;
import io.swagger.models.properties.*;
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 java.util.Objects;
public final class PropertyUtils {
@@ -55,11 +53,41 @@ public final class PropertyUtils {
}
else{
if(StringUtils.isNotBlank(property.getFormat())){
type = property.getType() + " (" + property.getFormat() + ")";
type = StringUtils.defaultString(property.getType()) + " (" + property.getFormat() + ")";
}else{
type = property.getType();
}
}
return type;
return StringUtils.defaultString(type);
}
public static String getDefaultValue(Property property){
Validate.notNull(property, "property must not be null!");
String defaultValue = "";
if(property instanceof BooleanProperty){
BooleanProperty booleanProperty = (BooleanProperty)property;
defaultValue = Objects.toString(booleanProperty.getDefault(), "");
}else if(property instanceof StringProperty){
StringProperty stringProperty = (StringProperty)property;
defaultValue = Objects.toString(stringProperty.getDefault(), "");
}else if(property instanceof DoubleProperty){
DoubleProperty doubleProperty = (DoubleProperty)property;
defaultValue = Objects.toString(doubleProperty.getDefault(), "");
}else if(property instanceof FloatProperty){
FloatProperty floatProperty = (FloatProperty)property;
defaultValue = Objects.toString(floatProperty.getDefault(), "");
}else if(property instanceof IntegerProperty){
IntegerProperty integerProperty = (IntegerProperty)property;
defaultValue = Objects.toString(integerProperty.getDefault(), "");
}
else if(property instanceof LongProperty){
LongProperty longProperty = (LongProperty)property;
defaultValue = Objects.toString(longProperty.getDefault(), "");
}
else if(property instanceof UUIDProperty){
UUIDProperty uuidProperty = (UUIDProperty)property;
defaultValue = Objects.toString(uuidProperty.getDefault(), "");
}
return defaultValue;
}
}

View File

@@ -24,6 +24,8 @@ import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static java.util.Arrays.asList;
import static org.assertj.core.api.BDDAssertions.assertThat;
@@ -100,6 +102,47 @@ public class Swagger2MarkupConverterTest {
assertThat(directories).hasSize(3).containsAll(asList("definitions.md", "overview.md", "paths.md"));
}
@Test
public void testSwagger2AsciiDocConversionWithSeparatedDefinitions() 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().build()
.intoFolder(outputDirectory.getAbsolutePath());
//Then
String[] directories = outputDirectory.list();
assertThat(directories).hasSize(8).containsAll(
asList("definitions.adoc", "overview.adoc", "paths.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"))));
}
@Test
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");
FileUtils.deleteQuietly(outputDirectory);
//When
Swagger2MarkupConverter.from(file.getAbsolutePath()).withSeparatedDefinitions().
withMarkupLanguage(MarkupLanguage.MARKDOWN).build()
.intoFolder(outputDirectory.getAbsolutePath());
//Then
String[] directories = outputDirectory.list();
assertThat(directories).hasSize(8).containsAll(
asList("definitions.md", "overview.md", "paths.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 testSwagger2HtmlConversion() throws IOException {

View File

@@ -563,14 +563,16 @@
"name": "username",
"description": "The user name for login",
"required": false,
"type": "string"
"type": "string",
"default": "testUser"
},
{
"in": "query",
"name": "password",
"description": "The password for login in clear text",
"required": false,
"type": "string"
"type": "string",
"default": "testPassword"
}
],
"responses": {
@@ -623,7 +625,8 @@
"name": "username",
"description": "The name that needs to be fetched. Use user1 for testing.",
"required": true,
"type": "string"
"type": "string",
"default": "testUser"
}
],
"responses": {