Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c50292563 | ||
|
|
3d116dd7f8 | ||
|
|
e6f7372c9f | ||
|
|
0ca91ea930 | ||
|
|
efea76d243 | ||
|
|
cd4ef60cc3 | ||
|
|
6ed557b4ac | ||
|
|
139c294f25 | ||
|
|
68a433b76b | ||
|
|
b0dba05b48 | ||
|
|
55bb2bdd71 | ||
|
|
3d4d87c0b0 | ||
|
|
ad0d03c95c | ||
|
|
0675beaa45 | ||
|
|
cb6526d0e5 | ||
|
|
f5a8454817 | ||
|
|
5bf8270f2e | ||
|
|
6c794e75fd | ||
|
|
b472bf97bb |
82
README.adoc
@@ -3,9 +3,7 @@
|
||||
:version: 0.1.0
|
||||
: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:http://img.shields.io/:version-{version}-blue.svg["Semantic Versioning", link="http://semver.org"] image:http://img.shields.io/badge/license-ASF2-blue.svg["Apache License 2", link="http://www.apache.org/licenses/LICENSE-2.0.txt"]
|
||||
|
||||
WARNING: Still under heavy development
|
||||
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:http://img.shields.io/:version-{version}-blue.svg["Semantic Versioning", link="https://bintray.com/robwin/maven/swagger2markup/0.1.0/view"] image:http://img.shields.io/badge/license-ASF2-blue.svg["Apache License 2", link="http://www.apache.org/licenses/LICENSE-2.0.txt"]
|
||||
|
||||
== Overview
|
||||
|
||||
@@ -15,7 +13,42 @@ The primary goal of this project is to simplify the documentation of RESTful API
|
||||
|
||||
== Usage
|
||||
|
||||
Using the Swagger2MarkupConverter is simple. For instance, you can generate your AsciiDoc/Markdown documentation using https://github.com/spring-projects/spring-boot[Spring Boot] and https://github.com/martypitt/swagger-springmvc[swagger-springmvc] as follows:
|
||||
=== Adding Swagger2Markup to your project
|
||||
|
||||
==== Maven
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jcenter-release</id>
|
||||
<name>jcenter</name>
|
||||
<url>http://oss.jfrog.org/artifactory/oss-release-local/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.robwin.swagger2markup</groupId>
|
||||
<artifactId>swagger2markup</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
==== Gradle
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
compile "io.github.robwin:swagger2markup:0.2.0"
|
||||
----
|
||||
|
||||
=== Using Swagger2Markup
|
||||
|
||||
Using the Swagger2MarkupConverter is simple. For instance, you can generate your AsciiDoc/Markdown documentation using https://github.com/spring-projects/spring-boot[Spring Boot] and https://github.com/martypitt/swagger-springmvc[swagger-springmvc] as follows.
|
||||
See demo project https://github.com/RobWin/spring-swagger2markup-demo[spring-swagger2markup-demo].
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@@ -29,16 +62,19 @@ public class Swagger2MarkupTest {
|
||||
public void convertSwaggerToMarkup() {
|
||||
//Remote
|
||||
Swagger2MarkupConverter.from("http://localhost:8080/api-docs").
|
||||
toAsciiDoc("src/docs/asciidoc/example.adoc");
|
||||
withMarkupLanguage(MarkupLanguage.MARKDOWN).
|
||||
withExamples("docs/generated").withSchemas("docs/schemas").build()
|
||||
.intoFolder("src/docs/markdown");
|
||||
|
||||
Swagger2MarkupConverter.from("http://localhost:8080/api-docs").
|
||||
toMarkdown("src/docs/markdown/example.md");
|
||||
withExamples("docs").withSchemas("docs/schemas").build()
|
||||
.intoFolder("src/docs/asciidoc");
|
||||
|
||||
//Local
|
||||
File file = new File(Swagger2MarkupTest.class.getResource("/json/swagger.json").getFile());
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).toAsciiDoc("src/docs/asciidoc/swagger.adoc")
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).build()
|
||||
.intoFolder("src/docs/asciidoc");
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -75,30 +111,36 @@ public class SpringBootSwaggerConfig {
|
||||
}
|
||||
----
|
||||
|
||||
You can then generate HTML5 and PDF documentation via https://github.com/asciidoctor/asciidoctorj[asciidoctorj] or even better via the https://github.com/asciidoctor/asciidoctor-gradle-plugin[asciidoctor-gradle-plugin] and https://github.com/aalmiray/markdown-gradle-plugin[markdown-gradle-plugin].
|
||||
You can generate your HTML5 and PDF 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/tomchristie/mkdocs[MkDocs] and https://github.com/rtfd/readthedocs.org[ReadTheDocs] to publish your Markdown documentation.
|
||||
See http://spring-swagger2markup-demo.readthedocs.org/[ReadTheDocs-demo]
|
||||
|
||||
== Example
|
||||
== swagger.json
|
||||
== Examples
|
||||
== Swagger source file
|
||||
image::images/swagger_json.PNG[swagger_json]
|
||||
|
||||
=== Generated AsciiDoc file
|
||||
image::images/asciidoc.PNG[asciidoc]
|
||||
|
||||
=== Generated Markdown file
|
||||
image::images/markdown.PNG[asciidoc]
|
||||
image::images/markdown.PNG[markdown]
|
||||
|
||||
=== Generated HTML
|
||||
=== Generated HTML using AsciidoctorJ
|
||||
image::images/asciidoc_html.PNG[asciidoc_html]
|
||||
|
||||
=== Generated HTML using Mkdocs
|
||||
image::images/mkdocs_html.PNG[mkdocs_html]
|
||||
|
||||
=== Generated PDF using AsciidoctorJ
|
||||
image::images/asciidoc_pdf.PNG[asciidoc_pdf]
|
||||
|
||||
== Document Builder
|
||||
The converter allows to build an AsciiDoc or Markdown document via the Builder pattern:
|
||||
The Swagger2Markup library allows to build an AsciiDoc or Markdown document via the Builder pattern:
|
||||
[source,java]
|
||||
----
|
||||
String asciiDoc = new AsciiDocBuilder().documentTitle("Title")
|
||||
.sectionTitleLevel1("Section1").paragraph("Text text")
|
||||
.sectionTitleLevel2("Code examples").listing("Code example").toString();
|
||||
DocumentBuilder builder = DocumentBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
|
||||
builder.documentTitle("Test title").textLine("Text line").writeToFile("/tmp", "test.adoc", StandardCharsets.UTF_8);
|
||||
|
||||
String markdown = new MarkdownBuilder().documentTitle("Title")
|
||||
.sectionTitleLevel1("Section1").paragraph("Text text")
|
||||
.sectionTitleLevel2("Code examples").listing("Code example").toString();
|
||||
DocumentBuilder builder = DocumentBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
|
||||
builder.documentTitle("Test title").textLine("Text line").writeToFile("/tmp", "test.adoc", StandardCharsets.UTF_8);
|
||||
----
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
= Release Notes
|
||||
|
||||
== Version 0.1.0
|
||||
* Initial version with support for AsciiDoc and Markdown
|
||||
* Initial version with support for AsciiDoc and Markdown
|
||||
|
||||
== Version 0.2.0
|
||||
* This version is not downward compatible. This version supports includes of example files and JSON/XML Schema files. See documentation.
|
||||
23
build.gradle
@@ -8,20 +8,16 @@ buildscript {
|
||||
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.6'
|
||||
classpath 'io.spring.gradle:dependency-management-plugin:0.3.1.RELEASE'
|
||||
classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.0.1'
|
||||
classpath 'me.champeau.gradle:jbake-gradle-plugin:0.2'
|
||||
classpath 'org.jbake:jbake-core:2.3.2'
|
||||
classpath 'org.asciidoctor:asciidoctorj:1.5.2'
|
||||
classpath 'org.freemarker:freemarker:2.3.19'
|
||||
classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.2.1.RELEASE'
|
||||
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
|
||||
}
|
||||
}
|
||||
description = 'swagger2markup Build'
|
||||
version = '0.1.0'
|
||||
group = 'io.swagger2markup'
|
||||
version = '0.2.0'
|
||||
group = 'io.github.robwin'
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'org.asciidoctor.convert'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'com.github.kt3k.coveralls'
|
||||
@@ -40,12 +36,13 @@ tasks.withType(JavaCompile) {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'io.swagger:swagger-compat-spec-parser'
|
||||
compile 'commons-collections:commons-collections'
|
||||
compile 'commons-io:commons-io'
|
||||
compile 'ch.qos.logback:logback-classic'
|
||||
testCompile 'junit:junit'
|
||||
}
|
||||
|
||||
@@ -53,17 +50,21 @@ dependencyManagement {
|
||||
dependencies {
|
||||
"io.swagger:swagger-compat-spec-parser" "1.0.0"
|
||||
"commons-collections:commons-collections" "3.2.1"
|
||||
"commons-io:commons-io" "2.4"
|
||||
"com.mangofactory:swagger-springmvc" "0.9.5"
|
||||
"com.jayway.restassured:spring-mock-mvc" "2.4.0"
|
||||
"ch.qos.logback:logback-classic" "1.1.2"
|
||||
"junit:junit" "4.11"
|
||||
}
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
backends = ['html5', 'pdf']
|
||||
attributes = [
|
||||
doctype: 'book',
|
||||
toc: 'left',
|
||||
toclevels: '1'
|
||||
toclevels: '2',
|
||||
numbered: ''
|
||||
]
|
||||
}
|
||||
|
||||
@@ -78,6 +79,10 @@ tasks.coveralls {
|
||||
dependsOn 'check'
|
||||
}
|
||||
|
||||
tasks.asciidoctor {
|
||||
dependsOn 'check'
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.2.1'
|
||||
}
|
||||
@@ -29,5 +29,47 @@ if (!project.hasProperty('bintrayApiKey')) ext.bintrayApiKey = ''
|
||||
bintray {
|
||||
user = project.bintrayUsername
|
||||
key = project.bintrayApiKey
|
||||
pkg.repo = 'swagger2markup'
|
||||
publications = ['mavenJava']
|
||||
pkg {
|
||||
repo = 'maven'
|
||||
name = 'swagger2markup'
|
||||
websiteUrl = 'https://github.com/RobWin/swagger2markup'
|
||||
issueTrackerUrl = 'https://github.com/RobWin/swagger2markup/issues'
|
||||
vcsUrl = 'https://github.com/RobWin/swagger2markup.git'
|
||||
desc = 'A Swagger to Markup (AsciiDoc and Markdown) converter.'
|
||||
licenses = ['Apache-2.0']
|
||||
version {
|
||||
vcsTag = project.version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
pom.withXml {
|
||||
def devs = ['RobWin': 'Robert Winkler']
|
||||
def root = asNode()
|
||||
root.appendNode('name', 'swagger2markup')
|
||||
root.appendNode('packaging', 'jar')
|
||||
root.appendNode('url', 'https://github.com/RobWin/swagger2markup')
|
||||
root.appendNode('description', 'A Swagger to Markup (AsciiDoc and Markdown) converter.')
|
||||
|
||||
def license = root.appendNode('licenses').appendNode('license')
|
||||
license.appendNode('name', 'Apache-2.0')
|
||||
license.appendNode('url', 'https://github.com/RobWin/swagger2markup/blob/master/LICENSE.txt')
|
||||
license.appendNode('distribution', 'repo')
|
||||
|
||||
root.appendNode('scm').appendNode('url', 'https://github.com/RobWin/swagger2markup.git')
|
||||
|
||||
def developers = root.appendNode('developers')
|
||||
devs.each {
|
||||
def d = developers.appendNode('developer')
|
||||
d.appendNode('id', it.key)
|
||||
d.appendNode('name', it.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 105 KiB |
BIN
images/asciidoc_pdf.PNG
Normal file
|
After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 21 KiB |
BIN
images/mkdocs_html.PNG
Normal file
|
After Width: | Height: | Size: 87 KiB |
@@ -1,534 +0,0 @@
|
||||
= Swagger Petstore
|
||||
This is a sample server Petstore server.
|
||||
|
||||
[Learn about Swagger](http://swagger.wordnik.com) or join the IRC channel `#swagger` on irc.freenode.net.
|
||||
|
||||
For this sample, you can use the api key `special-key` to test the authorization filters
|
||||
|
||||
Version: 1.0.0
|
||||
|
||||
== Update an existing pet
|
||||
----
|
||||
PUT /pets
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
body,body,Pet object that needs to be added to the store,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
400,Invalid ID supplied
|
||||
404,Pet not found
|
||||
405,Validation exception
|
||||
|===
|
||||
|
||||
=== Consumes
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Add a new pet to the store
|
||||
----
|
||||
POST /pets
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
body,body,Pet object that needs to be added to the store,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
405,Invalid input
|
||||
|===
|
||||
|
||||
=== Consumes
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Finds Pets by status
|
||||
----
|
||||
GET /pets/findByStatus
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
Multiple status values can be provided with comma seperated strings
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
status,query,Status values that need to be considered for filter,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
200,successful operation
|
||||
400,Invalid status value
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Finds Pets by tags
|
||||
----
|
||||
GET /pets/findByTags
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
tags,query,Tags to filter by,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
200,successful operation
|
||||
400,Invalid tag value
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Find pet by ID
|
||||
----
|
||||
GET /pets/{petId}
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
petId,path,ID of pet that needs to be fetched,true
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
200,successful operation
|
||||
400,Invalid ID supplied
|
||||
404,Pet not found
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Deletes a pet
|
||||
----
|
||||
DELETE /pets/{petId}
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
api_key,header,,true
|
||||
petId,path,Pet id to delete,true
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
400,Invalid pet value
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Updates a pet in the store with form data
|
||||
----
|
||||
POST /pets/{petId}
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
petId,path,ID of pet that needs to be updated,true
|
||||
name,formData,Updated name of the pet,true
|
||||
status,formData,Updated status of the pet,true
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
405,Invalid input
|
||||
|===
|
||||
|
||||
=== Consumes
|
||||
* application/x-www-form-urlencoded
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Place an order for a pet
|
||||
----
|
||||
POST /stores/order
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
body,body,order placed for purchasing the pet,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
200,successful operation
|
||||
400,Invalid Order
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Find purchase order by ID
|
||||
----
|
||||
GET /stores/order/{orderId}
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
orderId,path,ID of pet that needs to be fetched,true
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
200,successful operation
|
||||
400,Invalid ID supplied
|
||||
404,Order not found
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Delete purchase order by ID
|
||||
----
|
||||
DELETE /stores/order/{orderId}
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
orderId,path,ID of the order that needs to be deleted,true
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
400,Invalid ID supplied
|
||||
404,Order not found
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Create user
|
||||
----
|
||||
POST /users
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
This can only be done by the logged in user.
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
body,body,Created user object,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
default,successful operation
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Creates list of users with given input array
|
||||
----
|
||||
POST /users/createWithArray
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
body,body,List of user object,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
default,successful operation
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Creates list of users with given input array
|
||||
----
|
||||
POST /users/createWithList
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
body,body,List of user object,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
default,successful operation
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Logs user into the system
|
||||
----
|
||||
GET /users/login
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
username,query,The user name for login,false
|
||||
password,query,The password for login in clear text,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
200,successful operation
|
||||
400,Invalid username/password supplied
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Logs out current logged in user session
|
||||
----
|
||||
GET /users/logout
|
||||
----
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
default,successful operation
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Get user by user name
|
||||
----
|
||||
GET /users/{username}
|
||||
----
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
username,path,The name that needs to be fetched. Use user1 for testing.,true
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
200,successful operation
|
||||
400,Invalid username supplied
|
||||
404,User not found
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Updated user
|
||||
----
|
||||
PUT /users/{username}
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
This can only be done by the logged in user.
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
username,path,name that need to be deleted,true
|
||||
body,body,Updated user object,false
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
400,Invalid user supplied
|
||||
404,User not found
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Delete user
|
||||
----
|
||||
DELETE /users/{username}
|
||||
----
|
||||
|
||||
=== Description
|
||||
:hardbreaks:
|
||||
This can only be done by the logged in user.
|
||||
|
||||
=== Parameters
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Located in,Description,Required
|
||||
username,path,The name that needs to be deleted,true
|
||||
|===
|
||||
|
||||
=== Responses
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Code,Description
|
||||
400,Invalid username supplied
|
||||
404,User not found
|
||||
|===
|
||||
|
||||
=== Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
== Definitions
|
||||
=== User
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Type,Required
|
||||
id,integer,false
|
||||
username,string,false
|
||||
firstName,string,false
|
||||
lastName,string,false
|
||||
email,string,false
|
||||
password,string,false
|
||||
phone,string,false
|
||||
userStatus,integer,false
|
||||
|===
|
||||
|
||||
=== Category
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Type,Required
|
||||
id,integer,false
|
||||
name,string,false
|
||||
|===
|
||||
|
||||
=== Pet
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Type,Required
|
||||
id,integer,false
|
||||
category,ref,false
|
||||
name,string,true
|
||||
photoUrls,array,true
|
||||
tags,array,false
|
||||
status,string,false
|
||||
|===
|
||||
|
||||
=== Tag
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Type,Required
|
||||
id,integer,false
|
||||
name,string,false
|
||||
|===
|
||||
|
||||
=== Order
|
||||
[format="csv", options="header"]
|
||||
|===
|
||||
Name,Type,Required
|
||||
id,integer,false
|
||||
petId,integer,false
|
||||
quantity,integer,false
|
||||
shipDate,string,false
|
||||
status,string,false
|
||||
complete,boolean,false
|
||||
|===
|
||||
|
||||
@@ -1,494 +0,0 @@
|
||||
# Swagger Petstore
|
||||
This is a sample server Petstore server.
|
||||
|
||||
[Learn about Swagger](http://swagger.wordnik.com) or join the IRC channel `#swagger` on irc.freenode.net.
|
||||
|
||||
For this sample, you can use the api key `special-key` to test the authorization filters
|
||||
|
||||
Version: 1.0.0
|
||||
|
||||
## Update an existing pet
|
||||
```
|
||||
PUT /pets
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|body|body|Pet object that needs to be added to the store|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|400|Invalid ID supplied|
|
||||
|404|Pet not found|
|
||||
|405|Validation exception|
|
||||
|
||||
|
||||
### Consumes
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Add a new pet to the store
|
||||
```
|
||||
POST /pets
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|body|body|Pet object that needs to be added to the store|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|405|Invalid input|
|
||||
|
||||
|
||||
### Consumes
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Finds Pets by status
|
||||
```
|
||||
GET /pets/findByStatus
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Multiple status values can be provided with comma seperated strings
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|status|query|Status values that need to be considered for filter|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|200|successful operation|
|
||||
|400|Invalid status value|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Finds Pets by tags
|
||||
```
|
||||
GET /pets/findByTags
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|tags|query|Tags to filter by|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|200|successful operation|
|
||||
|400|Invalid tag value|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Find pet by ID
|
||||
```
|
||||
GET /pets/{petId}
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|petId|path|ID of pet that needs to be fetched|true|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|200|successful operation|
|
||||
|400|Invalid ID supplied|
|
||||
|404|Pet not found|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Deletes a pet
|
||||
```
|
||||
DELETE /pets/{petId}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|api_key|header||true|
|
||||
|petId|path|Pet id to delete|true|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|400|Invalid pet value|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Updates a pet in the store with form data
|
||||
```
|
||||
POST /pets/{petId}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|petId|path|ID of pet that needs to be updated|true|
|
||||
|name|formData|Updated name of the pet|true|
|
||||
|status|formData|Updated status of the pet|true|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|405|Invalid input|
|
||||
|
||||
|
||||
### Consumes
|
||||
* application/x-www-form-urlencoded
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Place an order for a pet
|
||||
```
|
||||
POST /stores/order
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|body|body|order placed for purchasing the pet|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|200|successful operation|
|
||||
|400|Invalid Order|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Find purchase order by ID
|
||||
```
|
||||
GET /stores/order/{orderId}
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|orderId|path|ID of pet that needs to be fetched|true|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|200|successful operation|
|
||||
|400|Invalid ID supplied|
|
||||
|404|Order not found|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Delete purchase order by ID
|
||||
```
|
||||
DELETE /stores/order/{orderId}
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|orderId|path|ID of the order that needs to be deleted|true|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|400|Invalid ID supplied|
|
||||
|404|Order not found|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Create user
|
||||
```
|
||||
POST /users
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
This can only be done by the logged in user.
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|body|body|Created user object|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|default|successful operation|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Creates list of users with given input array
|
||||
```
|
||||
POST /users/createWithArray
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|body|body|List of user object|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|default|successful operation|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Creates list of users with given input array
|
||||
```
|
||||
POST /users/createWithList
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|body|body|List of user object|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|default|successful operation|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Logs user into the system
|
||||
```
|
||||
GET /users/login
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|username|query|The user name for login|false|
|
||||
|password|query|The password for login in clear text|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|200|successful operation|
|
||||
|400|Invalid username/password supplied|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Logs out current logged in user session
|
||||
```
|
||||
GET /users/logout
|
||||
```
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|default|successful operation|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Get user by user name
|
||||
```
|
||||
GET /users/{username}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|username|path|The name that needs to be fetched. Use user1 for testing.|true|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|200|successful operation|
|
||||
|400|Invalid username supplied|
|
||||
|404|User not found|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Updated user
|
||||
```
|
||||
PUT /users/{username}
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
This can only be done by the logged in user.
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|username|path|name that need to be deleted|true|
|
||||
|body|body|Updated user object|false|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|400|Invalid user supplied|
|
||||
|404|User not found|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Delete user
|
||||
```
|
||||
DELETE /users/{username}
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
This can only be done by the logged in user.
|
||||
|
||||
### Parameters
|
||||
|Name|Located in|Description|Required|
|
||||
|----|----|----|----|
|
||||
|username|path|The name that needs to be deleted|true|
|
||||
|
||||
|
||||
### Responses
|
||||
|Code|Description|
|
||||
|----|----|
|
||||
|400|Invalid username supplied|
|
||||
|404|User not found|
|
||||
|
||||
|
||||
### Produces
|
||||
* application/json
|
||||
* application/xml
|
||||
|
||||
## Definitions
|
||||
### User
|
||||
|Name|Type|Required|
|
||||
|----|----|----|
|
||||
|id|integer|false|
|
||||
|username|string|false|
|
||||
|firstName|string|false|
|
||||
|lastName|string|false|
|
||||
|email|string|false|
|
||||
|password|string|false|
|
||||
|phone|string|false|
|
||||
|userStatus|integer|false|
|
||||
|
||||
|
||||
### Category
|
||||
|Name|Type|Required|
|
||||
|----|----|----|
|
||||
|id|integer|false|
|
||||
|name|string|false|
|
||||
|
||||
|
||||
### Pet
|
||||
|Name|Type|Required|
|
||||
|----|----|----|
|
||||
|id|integer|false|
|
||||
|category|ref|false|
|
||||
|name|string|true|
|
||||
|photoUrls|array|true|
|
||||
|tags|array|false|
|
||||
|status|string|false|
|
||||
|
||||
|
||||
### Tag
|
||||
|Name|Type|Required|
|
||||
|----|----|----|
|
||||
|id|integer|false|
|
||||
|name|string|false|
|
||||
|
||||
|
||||
### Order
|
||||
|Name|Type|Required|
|
||||
|----|----|----|
|
||||
|id|integer|false|
|
||||
|petId|integer|false|
|
||||
|quantity|integer|false|
|
||||
|shipDate|string|false|
|
||||
|status|string|false|
|
||||
|complete|boolean|false|
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package io.github.robwin.swagger2markup;
|
||||
|
||||
import com.wordnik.swagger.models.Swagger;
|
||||
import io.github.robwin.swagger2markup.builder.document.DefinitionsDocument;
|
||||
import io.github.robwin.swagger2markup.builder.document.PathsDocument;
|
||||
import io.github.robwin.swagger2markup.builder.markup.MarkupLanguage;
|
||||
import io.swagger.parser.SwaggerParser;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public class Swagger2MarkupConverter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Swagger2MarkupConverter.class);
|
||||
|
||||
private final Swagger swagger;
|
||||
private final MarkupLanguage markupLanguage;
|
||||
private final String examplesFolderPath;
|
||||
private final String schemasFolderPath;
|
||||
private static final String PATHS_DOCUMENT = "paths";
|
||||
private static final String DEFINITIONS_DOCUMENT = "definitions";
|
||||
|
||||
/**
|
||||
* @param markupLanguage the markup language which is used to generate the files
|
||||
* @param swagger the Swagger object
|
||||
* @param examplesFolderPath the folderPath where examples are stored
|
||||
* @param schemasFolderPath the folderPath where (XML, JSON)-Schema files are stored
|
||||
*/
|
||||
Swagger2MarkupConverter(MarkupLanguage markupLanguage, Swagger swagger, String examplesFolderPath, String schemasFolderPath){
|
||||
this.markupLanguage = markupLanguage;
|
||||
this.swagger = swagger;
|
||||
this.examplesFolderPath = examplesFolderPath;
|
||||
this.schemasFolderPath = schemasFolderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Swagger2MarkupConverter.Builder using a given Swagger source.
|
||||
*
|
||||
* @param swaggerSource the Swagger source. Can be a HTTP url or a path to a local file.
|
||||
* @return a Swagger2MarkupConverter
|
||||
*/
|
||||
public static Builder from(String swaggerSource){
|
||||
Validate.notEmpty(swaggerSource, "swaggerSource must not be null!");
|
||||
return new Builder(swaggerSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the document with the given markup language and stores
|
||||
* the files in the given folder.
|
||||
*
|
||||
* @param targetFolderPath the target folder
|
||||
* @throws IOException if the files cannot be written
|
||||
*/
|
||||
public void intoFolder(String targetFolderPath) throws IOException {
|
||||
Validate.notEmpty(targetFolderPath, "folderPath must not be null!");
|
||||
buildDocuments(targetFolderPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a file for the Paths (API) and a file for the Definitions (Model)
|
||||
|
||||
* @param directory the directory where the generated file should be stored
|
||||
* @throws IOException if a file cannot be written
|
||||
*/
|
||||
private void buildDocuments(String directory) throws IOException {
|
||||
new PathsDocument(swagger, markupLanguage, examplesFolderPath).build().writeToFile(directory, PATHS_DOCUMENT, StandardCharsets.UTF_8);
|
||||
new DefinitionsDocument(swagger, markupLanguage, schemasFolderPath).build().writeToFile(directory, DEFINITIONS_DOCUMENT, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
public static class Builder{
|
||||
private final Swagger swagger;
|
||||
private String examplesFolderPath;
|
||||
private String schemasFolderPath;
|
||||
private MarkupLanguage markupLanguage = MarkupLanguage.ASCIIDOC;
|
||||
|
||||
/**
|
||||
* Creates a Builder using a given Swagger source.
|
||||
*
|
||||
* @param swaggerSource the Swagger source. Can be a HTTP url or a path to a local file.
|
||||
*/
|
||||
Builder(String swaggerSource){
|
||||
swagger = new SwaggerParser().read(swaggerSource);
|
||||
}
|
||||
|
||||
public Swagger2MarkupConverter build(){
|
||||
return new Swagger2MarkupConverter(markupLanguage, swagger, examplesFolderPath, schemasFolderPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the markup language which should be used to generate the files
|
||||
*
|
||||
* @param markupLanguage the markup language which is used to generate the files
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
public Builder withMarkupLanguage(MarkupLanguage markupLanguage){
|
||||
this.markupLanguage = markupLanguage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include examples into the Paths document
|
||||
*
|
||||
* @param examplesFolderPath the path to the folder where the example documents reside
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
public Builder withExamples(String examplesFolderPath){
|
||||
this.examplesFolderPath = examplesFolderPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include (JSON, XML) schemas into the Definitions document
|
||||
*
|
||||
* @param schemasFolderPath the path to the folder where the schema documents reside
|
||||
* @return the Swagger2MarkupConverter.Builder
|
||||
*/
|
||||
public Builder withSchemas(String schemasFolderPath){
|
||||
this.schemasFolderPath = schemasFolderPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
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.swagger2markup.builder.markup.MarkupLanguage;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Project: swagger2markup
|
||||
* Copyright: Deutsche Telekom AG
|
||||
*
|
||||
* @author Robert Winkler <robert.winkler@telekom.de>
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DefinitionsDocument extends MarkupDocument {
|
||||
|
||||
private static final String DEFINITIONS = "Definitions";
|
||||
private static final List<String> IGNORED_DEFINITIONS = Arrays.asList("Void");
|
||||
private static final String JSON_SCHEMA = "JSON Schema";
|
||||
private static final String XML_SCHEMA = "XML Schema";
|
||||
private static final String NAME_COLUMN = "Name";
|
||||
private static final String TYPE_COLUMN = "Type";
|
||||
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 boolean schemasEnabled;
|
||||
private String schemasFolderPath;
|
||||
|
||||
public DefinitionsDocument(Swagger swagger, MarkupLanguage markupLanguage, String schemasFolderPath){
|
||||
super(swagger, markupLanguage);
|
||||
if(StringUtils.isNotBlank(schemasFolderPath)){
|
||||
this.schemasEnabled = true;
|
||||
this.schemasFolderPath = schemasFolderPath;
|
||||
}
|
||||
if(schemasEnabled){
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Include schemas is enabled.");
|
||||
}
|
||||
}else{
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Include schemas is disabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkupDocument build() throws IOException {
|
||||
definitions(swagger.getDefinitions());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the Swagger definitions.
|
||||
*
|
||||
* @param definitions the Swagger definitions
|
||||
*/
|
||||
private void definitions(Map<String, Model> definitions) throws IOException {
|
||||
if(MapUtils.isNotEmpty(definitions)){
|
||||
this.documentBuilder.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);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Definition processed: {}", definitionName);
|
||||
}
|
||||
}else{
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Definition was ignored: {}", definitionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the definition is not in the list of ignored definitions.
|
||||
*
|
||||
* @param definitionName the name of the definition
|
||||
* @return true if the definition can be processed
|
||||
*/
|
||||
private boolean checkThatDefinitionIsNotInIgnoreList(String definitionName) {
|
||||
return !IGNORED_DEFINITIONS.contains(definitionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a concrete definition
|
||||
*
|
||||
* @param definitionName the name of the definition
|
||||
* @param model the Swagger Model of the definition
|
||||
*/
|
||||
private void definition(String definitionName, Model model) {
|
||||
this.documentBuilder.sectionTitleLevel2(definitionName);
|
||||
Map<String, Property> properties = model.getProperties();
|
||||
List<String> csvContent = new ArrayList<>();
|
||||
csvContent.add(NAME_COLUMN + DELIMITER + TYPE_COLUMN + DELIMITER + REQUIRED_COLUMN);
|
||||
for (Map.Entry<String, Property> propertyEntry : properties.entrySet()) {
|
||||
Property property = propertyEntry.getValue();
|
||||
csvContent.add(propertyEntry.getKey() + DELIMITER + property.getType() + DELIMITER + property.getRequired());
|
||||
}
|
||||
this.documentBuilder.tableWithHeaderRow(csvContent);
|
||||
}
|
||||
|
||||
private void definitionSchema(String definitionName) 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void schema(String title, String schemasFolderPath, String schemaName, String language) throws IOException {
|
||||
java.nio.file.Path path = Paths.get(schemasFolderPath, schemaName);
|
||||
if (Files.isReadable(path)) {
|
||||
this.documentBuilder.sectionTitleLevel3(title);
|
||||
this.documentBuilder.source(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim(), language);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Schema file processed: {}", path);
|
||||
}
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Schema file is not readable: {}", path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.github.robwin.swagger2markup.builder.document;
|
||||
|
||||
import com.wordnik.swagger.models.Swagger;
|
||||
import io.github.robwin.swagger2markup.builder.markup.DocumentBuilder;
|
||||
import io.github.robwin.swagger2markup.builder.markup.DocumentBuilders;
|
||||
import io.github.robwin.swagger2markup.builder.markup.MarkupLanguage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Project: swagger2markup
|
||||
* Copyright: Deutsche Telekom AG
|
||||
*
|
||||
* @author Robert Winkler <robert.winkler@telekom.de>
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class MarkupDocument {
|
||||
|
||||
protected static final String DELIMITER = ",";
|
||||
protected static final String REQUIRED_COLUMN = "Required";
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
protected Swagger swagger;
|
||||
protected MarkupLanguage markupLanguage;
|
||||
protected DocumentBuilder documentBuilder;
|
||||
|
||||
MarkupDocument(Swagger swagger, MarkupLanguage markupLanguage){
|
||||
this.swagger = swagger;
|
||||
this.markupLanguage = markupLanguage;
|
||||
this.documentBuilder = DocumentBuilders.documentBuilder(markupLanguage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the MarkupDocument.
|
||||
*
|
||||
* @return the built MarkupDocument
|
||||
* @throws IOException if the files to include are not readable
|
||||
*/
|
||||
public abstract MarkupDocument build() throws IOException ;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the document.
|
||||
*/
|
||||
public String toString(){
|
||||
return documentBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the builder to a file and clears the builder.
|
||||
*
|
||||
* @param directory the directory where the generated file should be stored
|
||||
* @param fileName the name of the file
|
||||
* @param charset the the charset to use for encoding
|
||||
* @throws IOException if the file cannot be written
|
||||
*/
|
||||
public void writeToFile(String directory, String fileName, Charset charset) throws IOException{
|
||||
documentBuilder.writeToFile(directory, fileName, charset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package io.github.robwin.swagger2markup.builder.document;
|
||||
|
||||
import com.wordnik.swagger.models.*;
|
||||
import com.wordnik.swagger.models.parameters.Parameter;
|
||||
import io.github.robwin.swagger2markup.builder.markup.MarkupLanguage;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Project: swagger2markup
|
||||
* Copyright: Deutsche Telekom AG
|
||||
*
|
||||
* @author Robert Winkler <robert.winkler@telekom.de>
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class PathsDocument extends MarkupDocument {
|
||||
|
||||
private static final String VERSION = "Version: ";
|
||||
private static final String DESCRIPTION_COLUMN = "Description";
|
||||
private static final String DESCRIPTION = DESCRIPTION_COLUMN;
|
||||
private static final String PARAMETERS = "Parameters";
|
||||
private static final String PRODUCES = "Produces";
|
||||
private static final String CONSUMES = "Consumes";
|
||||
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 NAME_COLUMN = "Name";
|
||||
private static final String LOCATED_IN_COLUMN = "Located in";
|
||||
private static final String CODE_COLUMN = "Code";
|
||||
public static final String REQUEST_EXAMPLE_FILE_NAME = "request";
|
||||
public static final String RESPONSE_EXAMPLE_FILE_NAME = "response";
|
||||
|
||||
private boolean examplesEnabled;
|
||||
private String examplesFolderPath;
|
||||
|
||||
public PathsDocument(Swagger swagger, MarkupLanguage markupLanguage, String examplesFolderPath){
|
||||
super(swagger, markupLanguage);
|
||||
if(StringUtils.isNotBlank(examplesFolderPath)){
|
||||
this.examplesEnabled = true;
|
||||
this.examplesFolderPath = examplesFolderPath;
|
||||
}
|
||||
if(examplesEnabled){
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Include examples is enabled.");
|
||||
}
|
||||
}else{
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Include examples is disabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkupDocument build() throws IOException {
|
||||
documentHeader(swagger.getInfo());
|
||||
paths(swagger.getPaths());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the document header
|
||||
*
|
||||
* @param info the Swagger Info
|
||||
*/
|
||||
private void documentHeader(Info info) {
|
||||
this.documentBuilder
|
||||
.documentTitle(info.getTitle())
|
||||
.textLine(info.getDescription())
|
||||
.textLine(VERSION + info.getVersion())
|
||||
.newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all paths of the Swagger file
|
||||
*
|
||||
* @param paths a Map of Swagger Paths
|
||||
*/
|
||||
private void paths(Map<String, Path> paths) throws IOException {
|
||||
if(MapUtils.isNotEmpty(paths)) {
|
||||
//this.documentBuilder.sectionTitleLevel1(FEATURES);
|
||||
for (Map.Entry<String, Path> entry : paths.entrySet()) {
|
||||
Path path = entry.getValue();
|
||||
path("GET", entry.getKey(), path.getGet());
|
||||
path("PUT", entry.getKey(), path.getPut());
|
||||
path("DELETE", entry.getKey(), path.getDelete());
|
||||
path("POST", entry.getKey(), path.getPost());
|
||||
path("PATCH", entry.getKey(), path.getPatch());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a path
|
||||
*
|
||||
* @param httpMethod the HTTP method of the path
|
||||
* @param resourcePath the URL of the path
|
||||
* @param operation the Swagger Operation
|
||||
*/
|
||||
private void path(String httpMethod, String resourcePath, Operation operation) throws IOException {
|
||||
if(operation != null){
|
||||
pathTitle(httpMethod, resourcePath, operation);
|
||||
descriptionSection(operation);
|
||||
parametersSection(operation);
|
||||
responsesSection(operation);
|
||||
consumesSection(operation);
|
||||
producesSection(operation);
|
||||
examplesSection(operation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void pathTitle(String httpMethod, String resourcePath, Operation operation) {
|
||||
String summary = operation.getSummary();
|
||||
String title;
|
||||
if(StringUtils.isNotBlank(summary)) {
|
||||
title = summary;
|
||||
this.documentBuilder.sectionTitleLevel1(title);
|
||||
this.documentBuilder.listing(httpMethod + " " + resourcePath);
|
||||
}else{
|
||||
title = httpMethod + " " + resourcePath;
|
||||
this.documentBuilder.sectionTitleLevel1(title);
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Path processed: {}", title);
|
||||
}
|
||||
}
|
||||
|
||||
private void descriptionSection(Operation operation) {
|
||||
String description = operation.getDescription();
|
||||
if(StringUtils.isNotBlank(description)){
|
||||
this.documentBuilder.sectionTitleLevel2(DESCRIPTION);
|
||||
this.documentBuilder.paragraph(description);
|
||||
}
|
||||
}
|
||||
|
||||
private void parametersSection(Operation operation) {
|
||||
List<Parameter> parameters = operation.getParameters();
|
||||
if(CollectionUtils.isNotEmpty(parameters)){
|
||||
List<String> csvContent = new ArrayList<>();
|
||||
csvContent.add(NAME_COLUMN + DELIMITER + LOCATED_IN_COLUMN + DELIMITER + DESCRIPTION_COLUMN + DELIMITER + REQUIRED_COLUMN);
|
||||
for(Parameter parameter : parameters){
|
||||
csvContent.add(parameter.getName() + DELIMITER + parameter.getIn() + DELIMITER + parameter.getDescription() + DELIMITER + parameter.getRequired());
|
||||
}
|
||||
this.documentBuilder.sectionTitleLevel2(PARAMETERS);
|
||||
this.documentBuilder.tableWithHeaderRow(csvContent);
|
||||
}
|
||||
}
|
||||
|
||||
private void consumesSection(Operation operation) {
|
||||
List<String> consumes = operation.getConsumes();
|
||||
if(CollectionUtils.isNotEmpty(consumes)){
|
||||
this.documentBuilder.sectionTitleLevel2(CONSUMES);
|
||||
this.documentBuilder.unorderedList(consumes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void producesSection(Operation operation) {
|
||||
List<String> produces = operation.getProduces();
|
||||
if(CollectionUtils.isNotEmpty(produces)){
|
||||
this.documentBuilder.sectionTitleLevel2(PRODUCES);
|
||||
this.documentBuilder.unorderedList(produces);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the example section of a Swagger Operation
|
||||
*
|
||||
* @param operation the Swagger Operation
|
||||
* @throws IOException if the example file is not readable
|
||||
*/
|
||||
private void examplesSection(Operation operation) throws IOException {
|
||||
if(examplesEnabled){
|
||||
String summary = operation.getSummary();
|
||||
if(StringUtils.isNotBlank(summary)) {
|
||||
String exampleFolder = summary.replace(".", "").replace(" ", "_").toLowerCase();
|
||||
example(EXAMPLE_REQUEST, exampleFolder, REQUEST_EXAMPLE_FILE_NAME);
|
||||
example(EXAMPLE_RESPONSE, exampleFolder, RESPONSE_EXAMPLE_FILE_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a concrete example
|
||||
*
|
||||
* @param title the title of the example
|
||||
* @param exampleFolder the name of the folder where the example file resides
|
||||
* @param exampleFileName the name of the example file
|
||||
* @throws IOException
|
||||
*/
|
||||
private void example(String title, String exampleFolder, String exampleFileName) throws IOException {
|
||||
for (String fileNameExtension : markupLanguage.getFileNameExtensions()) {
|
||||
java.nio.file.Path path = Paths.get(examplesFolderPath, exampleFolder, exampleFileName + fileNameExtension);
|
||||
if (Files.isReadable(path)) {
|
||||
this.documentBuilder.sectionTitleLevel2(title);
|
||||
this.documentBuilder.paragraph(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim());
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Example file processed: {}", path);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Example file is not readable: {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void responsesSection(Operation operation) {
|
||||
Map<String, Response> responses = operation.getResponses();
|
||||
if(MapUtils.isNotEmpty(responses)){
|
||||
List<String> csvContent = new ArrayList<>();
|
||||
csvContent.add(CODE_COLUMN + DELIMITER + DESCRIPTION_COLUMN);
|
||||
for(Map.Entry<String, Response> entry : responses.entrySet()){
|
||||
Response response = entry.getValue();
|
||||
csvContent.add(entry.getKey() + DELIMITER + response.getDescription());
|
||||
}
|
||||
this.documentBuilder.sectionTitleLevel2(RESPONSES);
|
||||
this.documentBuilder.tableWithHeaderRow(csvContent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
package io.swagger2markup.builder;
|
||||
package io.github.robwin.swagger2markup.builder.markup;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -9,6 +17,7 @@ public abstract class AbstractDocumentBuilder implements DocumentBuilder {
|
||||
|
||||
protected StringBuilder documentBuilder = new StringBuilder();
|
||||
protected String newLine = System.getProperty("line.separator");
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected void documentTitle(Markup markup, String title){
|
||||
documentBuilder.append(markup).append(title).append(newLine);
|
||||
@@ -26,6 +35,7 @@ public abstract class AbstractDocumentBuilder implements DocumentBuilder {
|
||||
documentBuilder.append(markup).append(title).append(newLine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentBuilder textLine(String text){
|
||||
documentBuilder.append(text).append(newLine);
|
||||
return this;
|
||||
@@ -39,7 +49,7 @@ public abstract class AbstractDocumentBuilder implements DocumentBuilder {
|
||||
delimitedTextLine(markup, text);
|
||||
}
|
||||
|
||||
private void delimitedTextLine(Markup markup, String text){
|
||||
protected void delimitedTextLine(Markup markup, String text){
|
||||
documentBuilder.append(markup).append(newLine).append(text).append(newLine).append(markup).append(newLine).append(newLine);
|
||||
}
|
||||
|
||||
@@ -62,6 +72,7 @@ public abstract class AbstractDocumentBuilder implements DocumentBuilder {
|
||||
documentBuilder.append(newLine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentBuilder newLine(){
|
||||
documentBuilder.append(newLine);
|
||||
return this;
|
||||
@@ -71,4 +82,16 @@ public abstract class AbstractDocumentBuilder implements DocumentBuilder {
|
||||
public String toString(){
|
||||
return documentBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToFile(String directory, String fileNameWithExtension, Charset charset) throws IOException {
|
||||
Files.createDirectories(Paths.get(directory));
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(directory, fileNameWithExtension), charset)){
|
||||
writer.write(documentBuilder.toString());
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("{} was written to: {}", fileNameWithExtension, directory);
|
||||
}
|
||||
documentBuilder = new StringBuilder();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.swagger2markup.builder;
|
||||
package io.github.robwin.swagger2markup.builder.markup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -20,6 +22,8 @@ public interface DocumentBuilder {
|
||||
|
||||
DocumentBuilder listing(String text);
|
||||
|
||||
DocumentBuilder source(String text, String language);
|
||||
|
||||
DocumentBuilder boldTextLine(String text);
|
||||
|
||||
DocumentBuilder italicTextLine(String text);
|
||||
@@ -30,5 +34,18 @@ public interface DocumentBuilder {
|
||||
|
||||
DocumentBuilder newLine();
|
||||
|
||||
/**
|
||||
* Returns a string representation of the document.
|
||||
*/
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Writes the content of the builder to a file and clears the builder.
|
||||
*
|
||||
* @param directory the directory where the generated file should be stored
|
||||
* @param fileName the name of the file
|
||||
* @param charset the the charset to use for encoding
|
||||
* @throws IOException if the file cannot be written
|
||||
*/
|
||||
void writeToFile(String directory, String fileName, Charset charset) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.github.robwin.swagger2markup.builder.markup;
|
||||
|
||||
import io.github.robwin.swagger2markup.builder.markup.asciidoc.AsciiDocBuilder;
|
||||
import io.github.robwin.swagger2markup.builder.markup.markdown.MarkdownBuilder;
|
||||
|
||||
/**
|
||||
* Project: swagger2markup
|
||||
* Copyright: Deutsche Telekom AG
|
||||
*
|
||||
* @author Robert Winkler <robert.winkler@telekom.de>
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class DocumentBuilders {
|
||||
|
||||
private DocumentBuilders(){};
|
||||
|
||||
public static DocumentBuilder documentBuilder(MarkupLanguage markupLanguage){
|
||||
switch(markupLanguage){
|
||||
case MARKDOWN: return new MarkdownBuilder();
|
||||
case ASCIIDOC: return new AsciiDocBuilder();
|
||||
default: return new AsciiDocBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.swagger2markup.builder;
|
||||
package io.github.robwin.swagger2markup.builder.markup;
|
||||
|
||||
/**
|
||||
* Project: swagger2asciidoc
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.github.robwin.swagger2markup.builder.markup;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public enum MarkupLanguage {
|
||||
ASCIIDOC(".adoc,.asciidoc"),
|
||||
MARKDOWN(".md,.markdown");
|
||||
|
||||
private final String fileNameExtensions;
|
||||
|
||||
/**
|
||||
* @param fileNameExtensions file name suffix
|
||||
*/
|
||||
private MarkupLanguage(final String fileNameExtensions) {
|
||||
this.fileNameExtensions = fileNameExtensions;
|
||||
}
|
||||
|
||||
public List<String> getFileNameExtensions() {
|
||||
return Arrays.asList(fileNameExtensions.split(","));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.swagger2markup.builder.asciidoc;
|
||||
package io.github.robwin.swagger2markup.builder.markup.asciidoc;
|
||||
|
||||
import io.swagger2markup.builder.Markup;
|
||||
import io.github.robwin.swagger2markup.builder.markup.Markup;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
@@ -1,8 +1,10 @@
|
||||
package io.swagger2markup.builder.asciidoc;
|
||||
package io.github.robwin.swagger2markup.builder.markup.asciidoc;
|
||||
|
||||
import io.swagger2markup.builder.AbstractDocumentBuilder;
|
||||
import io.swagger2markup.builder.DocumentBuilder;
|
||||
import io.github.robwin.swagger2markup.builder.markup.AbstractDocumentBuilder;
|
||||
import io.github.robwin.swagger2markup.builder.markup.DocumentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -64,6 +66,13 @@ public class AsciiDocBuilder extends AbstractDocumentBuilder{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentBuilder source(String text, String language){
|
||||
documentBuilder.append(String.format("[source,%s]", language)).append(newLine);
|
||||
listing(AsciiDoc.LISTING, text);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentBuilder tableWithHeaderRow(List<String> rowsInCSV){
|
||||
documentBuilder.append("[format=\"csv\", options=\"header\"]").append(newLine);
|
||||
@@ -74,4 +83,11 @@ public class AsciiDocBuilder extends AbstractDocumentBuilder{
|
||||
documentBuilder.append(AsciiDoc.TABLE).append(newLine).append(newLine);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToFile(String directory, String fileName, Charset charset) throws IOException {
|
||||
String fileNameWithExtension = fileName + ".adoc";
|
||||
super.writeToFile(directory, fileNameWithExtension, charset);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.swagger2markup.builder.markdown;
|
||||
package io.github.robwin.swagger2markup.builder.markup.markdown;
|
||||
|
||||
import io.swagger2markup.builder.Markup;
|
||||
import io.github.robwin.swagger2markup.builder.markup.Markup;
|
||||
|
||||
/**
|
||||
* Project: swagger2asciidoc
|
||||
@@ -1,8 +1,10 @@
|
||||
package io.swagger2markup.builder.markdown;
|
||||
package io.github.robwin.swagger2markup.builder.markup.markdown;
|
||||
|
||||
import io.swagger2markup.builder.AbstractDocumentBuilder;
|
||||
import io.swagger2markup.builder.DocumentBuilder;
|
||||
import io.github.robwin.swagger2markup.builder.markup.AbstractDocumentBuilder;
|
||||
import io.github.robwin.swagger2markup.builder.markup.DocumentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -51,6 +53,14 @@ public class MarkdownBuilder extends AbstractDocumentBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentBuilder source(String text, String language){
|
||||
documentBuilder.append(Markdown.LISTING).append(language).append(newLine).
|
||||
append(text).append(newLine).
|
||||
append(Markdown.LISTING).append(newLine).append(newLine);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentBuilder boldTextLine(String text){
|
||||
boldTextLine(Markdown.BOLD, text);
|
||||
@@ -101,4 +111,10 @@ public class MarkdownBuilder extends AbstractDocumentBuilder
|
||||
newLine().newLine();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToFile(String directory, String fileName, Charset charset) throws IOException {
|
||||
String fileNameWithExtension = fileName + ".md";
|
||||
super.writeToFile(directory, fileNameWithExtension, charset);
|
||||
}
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
package io.swagger2markup;
|
||||
|
||||
import com.wordnik.swagger.models.*;
|
||||
import com.wordnik.swagger.models.parameters.Parameter;
|
||||
import com.wordnik.swagger.models.properties.Property;
|
||||
import io.swagger.parser.SwaggerParser;
|
||||
import io.swagger2markup.builder.DocumentBuilder;
|
||||
import io.swagger2markup.builder.asciidoc.AsciiDocBuilder;
|
||||
import io.swagger2markup.builder.markdown.MarkdownBuilder;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public class Swagger2MarkupConverter {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Swagger2MarkupConverter.class);
|
||||
private static final String VERSION = "Version: ";
|
||||
private static final String SUMMARY = "Summary";
|
||||
private static final String DESCRIPTION = "Description";
|
||||
private static final String PARAMETERS = "Parameters";
|
||||
private static final String PRODUCES = "Produces";
|
||||
private static final String CONSUMES = "Consumes";
|
||||
private static final String RESPONSES = "Responses";
|
||||
private static final String DEFINITIONS = "Definitions";
|
||||
private static final List<String> IGNORED_DEFINITIONS = Arrays.asList("Void");
|
||||
private final Swagger swagger;
|
||||
private DocumentBuilder documentBuilder;
|
||||
|
||||
private Swagger2MarkupConverter(String swaggerFileLocation){
|
||||
swagger = new SwaggerParser().read(swaggerFileLocation);
|
||||
}
|
||||
|
||||
public static Swagger2MarkupConverter from(String swaggerFileLocation){
|
||||
return new Swagger2MarkupConverter(swaggerFileLocation);
|
||||
}
|
||||
|
||||
public void toAsciiDoc(String fileLocation) throws IOException {
|
||||
documentBuilder = new AsciiDocBuilder();
|
||||
buildDocument();
|
||||
writeAsciiDocFile(fileLocation);
|
||||
}
|
||||
|
||||
public void toMarkdown(String fileLocation) throws IOException {
|
||||
documentBuilder = new MarkdownBuilder();
|
||||
buildDocument();
|
||||
writeAsciiDocFile(fileLocation);
|
||||
}
|
||||
|
||||
private void buildDocument(){
|
||||
documentHeader(swagger.getInfo());
|
||||
paths(swagger.getPaths());
|
||||
definitions(swagger.getDefinitions());
|
||||
}
|
||||
|
||||
private void writeAsciiDocFile(String asciiDocFileLocation) throws IOException {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(asciiDocFileLocation),
|
||||
StandardCharsets.UTF_8)){
|
||||
writer.write(documentBuilder.toString());
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to convert Swagger file to AsciiDoc", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void paths(Map<String, Path> paths) {
|
||||
for(Map.Entry<String, Path> entry : paths.entrySet()){
|
||||
Path path = entry.getValue();
|
||||
path("GET", entry.getKey(), path.getGet());
|
||||
path("PUT", entry.getKey(), path.getPut());
|
||||
path("DELETE", entry.getKey(), path.getDelete());
|
||||
path("POST", entry.getKey(), path.getPost());
|
||||
path("PATCH", entry.getKey(), path.getPatch());
|
||||
}
|
||||
}
|
||||
|
||||
private void documentHeader(Info info) {
|
||||
documentBuilder
|
||||
.documentTitle(info.getTitle())
|
||||
.textLine(info.getDescription())
|
||||
.textLine(VERSION + info.getVersion())
|
||||
.newLine();
|
||||
}
|
||||
|
||||
private void path(String httpMethod, String resourcePath, Operation operation) {
|
||||
if(operation != null){
|
||||
pathTitle(httpMethod, resourcePath, operation);
|
||||
descriptionSection(operation);
|
||||
parametersSection(operation);
|
||||
responsesSection(operation);
|
||||
consumesSection(operation);
|
||||
producesSection(operation);
|
||||
}
|
||||
}
|
||||
|
||||
private void pathTitle(String httpMethod, String resourcePath, Operation operation) {
|
||||
String summary = operation.getSummary();
|
||||
if(StringUtils.isNotBlank(summary)) {
|
||||
documentBuilder.sectionTitleLevel1(operation.getSummary());
|
||||
documentBuilder.listing(httpMethod + " " + resourcePath);
|
||||
}else{
|
||||
documentBuilder.sectionTitleLevel1(httpMethod + " " + resourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
private void descriptionSection(Operation operation) {
|
||||
String description = operation.getDescription();
|
||||
if(StringUtils.isNotBlank(description)){
|
||||
documentBuilder.sectionTitleLevel2(DESCRIPTION);
|
||||
documentBuilder.paragraph(description);
|
||||
}
|
||||
}
|
||||
|
||||
private void consumesSection(Operation operation) {
|
||||
List<String> consumes = operation.getConsumes();
|
||||
if(CollectionUtils.isNotEmpty(consumes)){
|
||||
documentBuilder.sectionTitleLevel2(CONSUMES);
|
||||
documentBuilder.unorderedList(consumes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void producesSection(Operation operation) {
|
||||
List<String> produces = operation.getProduces();
|
||||
if(CollectionUtils.isNotEmpty(produces)){
|
||||
documentBuilder.sectionTitleLevel2(PRODUCES);
|
||||
documentBuilder.unorderedList(produces);
|
||||
}
|
||||
}
|
||||
|
||||
private void parametersSection(Operation operation) {
|
||||
List<Parameter> parameters = operation.getParameters();
|
||||
if(CollectionUtils.isNotEmpty(parameters)){
|
||||
List<String> csvContent = new ArrayList<>();
|
||||
csvContent.add("Name,Located in,Description,Required");
|
||||
for(Parameter parameter : parameters){
|
||||
StringBuilder rowBuilder = new StringBuilder();
|
||||
rowBuilder.append(parameter.getName()).append(",").
|
||||
append(parameter.getIn()).append(",").
|
||||
append(parameter.getDescription()).append(",").
|
||||
append(parameter.getRequired());
|
||||
csvContent.add(rowBuilder.toString());
|
||||
}
|
||||
documentBuilder.sectionTitleLevel2(PARAMETERS);
|
||||
documentBuilder.tableWithHeaderRow(csvContent);
|
||||
}
|
||||
}
|
||||
|
||||
private void responsesSection(Operation operation) {
|
||||
Map<String, Response> responses = operation.getResponses();
|
||||
if(MapUtils.isNotEmpty(responses)){
|
||||
List<String> csvContent = new ArrayList<>();
|
||||
csvContent.add("Code,Description");
|
||||
for(Map.Entry<String, Response> entry : responses.entrySet()){
|
||||
Response response = entry.getValue();
|
||||
StringBuilder rowBuilder = new StringBuilder();
|
||||
rowBuilder.append(entry.getKey()).append(",").
|
||||
append(response.getDescription());
|
||||
csvContent.add(rowBuilder.toString());
|
||||
}
|
||||
documentBuilder.sectionTitleLevel2(RESPONSES);
|
||||
documentBuilder.tableWithHeaderRow(csvContent);
|
||||
}
|
||||
}
|
||||
|
||||
private void definitions(Map<String, Model> definitions) {
|
||||
if(MapUtils.isNotEmpty(definitions)){
|
||||
documentBuilder.sectionTitleLevel1(DEFINITIONS);
|
||||
for(Map.Entry<String, Model> definitionsEntry : definitions.entrySet()){
|
||||
String definitionName = definitionsEntry.getKey();
|
||||
if(!IGNORED_DEFINITIONS.contains(definitionName)) {
|
||||
documentBuilder.sectionTitleLevel2(definitionName);
|
||||
Model model = definitionsEntry.getValue();
|
||||
Map<String, Property> properties = model.getProperties();
|
||||
List<String> csvContent = new ArrayList<>();
|
||||
csvContent.add("Name,Type,Required");
|
||||
for (Map.Entry<String, Property> propertyEntry : properties.entrySet()) {
|
||||
Property property = propertyEntry.getValue();
|
||||
StringBuilder rowBuilder = new StringBuilder();
|
||||
rowBuilder.append(propertyEntry.getKey()).append(",").
|
||||
append(property.getType()).append(",").append(property.getRequired());
|
||||
csvContent.add(rowBuilder.toString());
|
||||
}
|
||||
documentBuilder.tableWithHeaderRow(csvContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
src/main/resources/logback.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true">
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,28 @@
|
||||
package io.github.robwin.swagger2markup;
|
||||
|
||||
import io.github.robwin.swagger2markup.builder.markup.MarkupLanguage;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public class Swagger2MarkupConverterTest {
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConverter() throws IOException {
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger.json").getFile());
|
||||
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).
|
||||
withMarkupLanguage(MarkupLanguage.MARKDOWN).
|
||||
withExamples("docs").withSchemas("docs/schemas").build()
|
||||
.intoFolder("src/docs/markdown");
|
||||
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).
|
||||
withExamples("docs").withSchemas("docs/schemas").build()
|
||||
.intoFolder("src/docs/asciidoc");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package io.github.robwin.swagger2markup.builder;
|
||||
|
||||
import io.github.robwin.swagger2markup.builder.markup.DocumentBuilder;
|
||||
import io.github.robwin.swagger2markup.builder.markup.DocumentBuilders;
|
||||
import io.github.robwin.swagger2markup.builder.markup.MarkupLanguage;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Project: swagger2markup
|
||||
* Copyright: Deutsche Telekom AG
|
||||
*
|
||||
* @author Robert Winkler <robert.winkler@telekom.de>
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DocumentBuilderTest {
|
||||
|
||||
@Test
|
||||
public void testToFile() throws IOException {
|
||||
DocumentBuilder builder = DocumentBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
|
||||
builder.documentTitle("Test title").textLine("Text line").writeToFile("/tmp", "test.adoc", StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package io.swagger2markup;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Robert Winkler
|
||||
*/
|
||||
public class Swagger2MarkupConverterTest {
|
||||
|
||||
@Test
|
||||
public void testSwagger2AsciiDocConverter() throws IOException {
|
||||
File file = new File(Swagger2MarkupConverterTest.class.getResource("/json/swagger.json").getFile());
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).toAsciiDoc("src/docs/asciidoc/swagger.adoc");
|
||||
|
||||
Swagger2MarkupConverter.from(file.getAbsolutePath()).toMarkdown("src/docs/markdown/swagger.md");
|
||||
}
|
||||
}
|
||||