Restructured project and added Markdown support.

This commit is contained in:
Robert Winkler
2015-02-13 12:56:34 +01:00
parent 3e8e21aef4
commit 287032c1dd
54 changed files with 3027 additions and 240 deletions

View File

@@ -0,0 +1,6 @@
description = 'swagger2markup core library'
dependencies {
compile 'io.swagger:swagger-legacy-spec-parser'
compile 'commons-collections:commons-collections'
}

View File

@@ -0,0 +1,534 @@
= 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,Schema
400,Invalid ID supplied,null
404,Pet not found,null
405,Validation exception,null
|===
=== 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,Schema
405,Invalid input,null
|===
=== Consumes
* application/json
* application/xml
=== Produces
* application/json
* application/xml
== Finds Pets by status
=== Description
:hardbreaks:
Multiple status values can be provided with comma seperated strings
----
GET /pets/findByStatus
----
=== 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,Schema
200,successful operation,com.wordnik.swagger.models.properties.ArrayProperty@79fc30a5
400,Invalid status value,null
|===
=== Produces
* application/json
* application/xml
== Finds Pets by tags
=== Description
:hardbreaks:
Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.
----
GET /pets/findByTags
----
=== Parameters
[format="csv", options="header"]
|===
Name,Located in,Description,Required
tags,query,Tags to filter by,false
|===
=== Responses
[format="csv", options="header"]
|===
Code,Description,Schema
200,successful operation,com.wordnik.swagger.models.properties.ArrayProperty@669fdb50
400,Invalid tag value,null
|===
=== Produces
* application/json
* application/xml
== Find pet by ID
=== Description
:hardbreaks:
Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions
----
GET /pets/{petId}
----
=== 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,Schema
200,successful operation,com.wordnik.swagger.models.properties.RefProperty@7729ecff
400,Invalid ID supplied,null
404,Pet not found,null
|===
=== 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,Schema
400,Invalid pet value,null
|===
=== 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,Schema
405,Invalid input,null
|===
=== 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,Schema
200,successful operation,com.wordnik.swagger.models.properties.RefProperty@121f512d
400,Invalid Order,null
|===
=== Produces
* application/json
* application/xml
== Find purchase order by ID
=== Description
:hardbreaks:
For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
----
GET /stores/order/{orderId}
----
=== 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,Schema
200,successful operation,com.wordnik.swagger.models.properties.RefProperty@afe22d3
400,Invalid ID supplied,null
404,Order not found,null
|===
=== Produces
* application/json
* application/xml
== Delete purchase order by ID
=== Description
:hardbreaks:
For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
----
DELETE /stores/order/{orderId}
----
=== 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,Schema
400,Invalid ID supplied,null
404,Order not found,null
|===
=== Produces
* application/json
* application/xml
== Create user
=== Description
:hardbreaks:
This can only be done by the logged in user.
----
POST /users
----
=== Parameters
[format="csv", options="header"]
|===
Name,Located in,Description,Required
body,body,Created user object,false
|===
=== Responses
[format="csv", options="header"]
|===
Code,Description,Schema
default,successful operation,null
|===
=== 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,Schema
default,successful operation,null
|===
=== 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,Schema
default,successful operation,null
|===
=== 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,Schema
200,successful operation,com.wordnik.swagger.models.properties.StringProperty@12a33d87
400,Invalid username/password supplied,null
|===
=== Produces
* application/json
* application/xml
== Logs out current logged in user session
----
GET /users/logout
----
=== Responses
[format="csv", options="header"]
|===
Code,Description,Schema
default,successful operation,null
|===
=== 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,Schema
200,successful operation,com.wordnik.swagger.models.properties.RefProperty@2a556538
400,Invalid username supplied,null
404,User not found,null
|===
=== Produces
* application/json
* application/xml
== Updated user
=== Description
:hardbreaks:
This can only be done by the logged in user.
----
PUT /users/{username}
----
=== 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,Schema
400,Invalid user supplied,null
404,User not found,null
|===
=== Produces
* application/json
* application/xml
== Delete user
=== Description
:hardbreaks:
This can only be done by the logged in user.
----
DELETE /users/{username}
----
=== 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,Schema
400,Invalid username supplied,null
404,User not found,null
|===
=== 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
|===

View File

@@ -0,0 +1,415 @@
# 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|Schema|
|----|----|----|
|400|Invalid ID supplied|null||404|Pet not found|null||405|Validation exception|null|
### 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|Schema|
|----|----|----|
|405|Invalid input|null|
### Consumes
* application/json
* application/xml
### Produces
* application/json
* application/xml
## Finds Pets by status
### Description
Multiple status values can be provided with comma seperated strings
```
GET /pets/findByStatus
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|status|query|Status values that need to be considered for filter|false|
### Responses
|Code|Description|Schema|
|----|----|----|
|200|successful operation|com.wordnik.swagger.models.properties.ArrayProperty@42cc43ea||400|Invalid status value|null|
### Produces
* application/json
* application/xml
## Finds Pets by tags
### Description
Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.
```
GET /pets/findByTags
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|tags|query|Tags to filter by|false|
### Responses
|Code|Description|Schema|
|----|----|----|
|200|successful operation|com.wordnik.swagger.models.properties.ArrayProperty@3f17a74f||400|Invalid tag value|null|
### Produces
* application/json
* application/xml
## Find pet by ID
### Description
Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions
```
GET /pets/{petId}
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|petId|path|ID of pet that needs to be fetched|true|
### Responses
|Code|Description|Schema|
|----|----|----|
|200|successful operation|com.wordnik.swagger.models.properties.RefProperty@2347fe11||400|Invalid ID supplied|null||404|Pet not found|null|
### 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|Schema|
|----|----|----|
|400|Invalid pet value|null|
### 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|Schema|
|----|----|----|
|405|Invalid input|null|
### 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|Schema|
|----|----|----|
|200|successful operation|com.wordnik.swagger.models.properties.RefProperty@3115cf36||400|Invalid Order|null|
### Produces
* application/json
* application/xml
## Find purchase order by ID
### Description
For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
```
GET /stores/order/{orderId}
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|orderId|path|ID of pet that needs to be fetched|true|
### Responses
|Code|Description|Schema|
|----|----|----|
|200|successful operation|com.wordnik.swagger.models.properties.RefProperty@11e609ed||400|Invalid ID supplied|null||404|Order not found|null|
### Produces
* application/json
* application/xml
## Delete purchase order by ID
### Description
For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
```
DELETE /stores/order/{orderId}
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|orderId|path|ID of the order that needs to be deleted|true|
### Responses
|Code|Description|Schema|
|----|----|----|
|400|Invalid ID supplied|null||404|Order not found|null|
### Produces
* application/json
* application/xml
## Create user
### Description
This can only be done by the logged in user.
```
POST /users
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|body|body|Created user object|false|
### Responses
|Code|Description|Schema|
|----|----|----|
|default|successful operation|null|
### 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|Schema|
|----|----|----|
|default|successful operation|null|
### 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|Schema|
|----|----|----|
|default|successful operation|null|
### 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|Schema|
|----|----|----|
|200|successful operation|com.wordnik.swagger.models.properties.StringProperty@1349f941||400|Invalid username/password supplied|null|
### Produces
* application/json
* application/xml
## Logs out current logged in user session
```
GET /users/logout
```
### Responses
|Code|Description|Schema|
|----|----|----|
|default|successful operation|null|
### 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|Schema|
|----|----|----|
|200|successful operation|com.wordnik.swagger.models.properties.RefProperty@fe22a4f||400|Invalid username supplied|null||404|User not found|null|
### Produces
* application/json
* application/xml
## Updated user
### Description
This can only be done by the logged in user.
```
PUT /users/{username}
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|username|path|name that need to be deleted|true||body|body|Updated user object|false|
### Responses
|Code|Description|Schema|
|----|----|----|
|400|Invalid user supplied|null||404|User not found|null|
### Produces
* application/json
* application/xml
## Delete user
### Description
This can only be done by the logged in user.
```
DELETE /users/{username}
```
### Parameters
|Name|Located in|Description|Required|
|----|----|----|----|
|username|path|The name that needs to be deleted|true|
### Responses
|Code|Description|Schema|
|----|----|----|
|400|Invalid username supplied|null||404|User not found|null|
### 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|

View File

@@ -0,0 +1,205 @@
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.asciidoc.AsciiDocBuilder;
import io.swagger2markup.builder.DocumentBuilder;
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){
pathTitleAndDescription(httpMethod, resourcePath, operation);
parametersSection(operation);
responsesSection(operation);
consumesSection(operation);
producesSection(operation);
}
}
private void pathTitleAndDescription(String httpMethod, String resourcePath, Operation operation) {
String summary = operation.getSummary();
if(StringUtils.isNotBlank(summary)) {
documentBuilder.sectionTitleLevel1(operation.getSummary());
description(operation);
documentBuilder.listing(httpMethod + " " + resourcePath);
}else{
documentBuilder.sectionTitleLevel1(httpMethod + " " + resourcePath);
description(operation);
}
}
private void description(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,Schema");
for(Map.Entry<String, Response> entry : responses.entrySet()){
Response response = entry.getValue();
StringBuilder rowBuilder = new StringBuilder();
rowBuilder.append(entry.getKey()).append(",").
append(response.getDescription()).append(",").
append(response.getSchema());
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);
}
}
}
}
}

View File

@@ -0,0 +1,74 @@
package io.swagger2markup.builder;
import java.util.List;
/**
* @author Robert Winkler
*/
public abstract class AbstractDocumentBuilder implements DocumentBuilder {
protected StringBuilder documentBuilder = new StringBuilder();
protected String newLine = System.getProperty("line.separator");
protected void documentTitle(Markup markup, String title){
documentBuilder.append(markup).append(title).append(newLine);
}
protected void sectionTitleLevel1(Markup markup, String title){
documentBuilder.append(markup).append(title).append(newLine);
}
protected void sectionTitleLevel2(Markup markup, String title){
documentBuilder.append(markup).append(title).append(newLine);
}
protected void sectionTitleLevel3(Markup markup, String title){
documentBuilder.append(markup).append(title).append(newLine);
}
public DocumentBuilder textLine(String text){
documentBuilder.append(text).append(newLine);
return this;
}
protected void paragraph(Markup markup, String text){
documentBuilder.append(markup).append(newLine).append(text).append(newLine).append(newLine);
}
protected void listing(Markup markup, String text){
delimitedTextLine(markup, text);
}
private void delimitedTextLine(Markup markup, String text){
documentBuilder.append(markup).append(newLine).append(text).append(newLine).append(markup).append(newLine).append(newLine);
}
protected void preserveLineBreaks(Markup markup){
documentBuilder.append(markup).append(newLine);
}
protected void boldTextLine(Markup markup, String text){
delimitedTextLine(markup, text);
}
protected void italicTextLine(Markup markup, String text){
delimitedTextLine(markup, text);
}
protected void unorderedList(Markup markup, List<String> list){
for(String listEntry : list){
documentBuilder.append(markup).append(listEntry).append(newLine);
}
documentBuilder.append(newLine);
}
public DocumentBuilder newLine(){
documentBuilder.append(newLine);
return this;
}
@Override
public String toString(){
return documentBuilder.toString();
}
}

View File

@@ -0,0 +1,34 @@
package io.swagger2markup.builder;
import java.util.List;
/**
* @author Robert Winkler
*/
public interface DocumentBuilder {
DocumentBuilder documentTitle(String title);
DocumentBuilder sectionTitleLevel1(String title);
DocumentBuilder sectionTitleLevel2(String title);
DocumentBuilder sectionTitleLevel3(String title);
DocumentBuilder textLine(String text);
DocumentBuilder paragraph(String text);
DocumentBuilder listing(String text);
DocumentBuilder boldTextLine(String text);
DocumentBuilder italicTextLine(String text);
DocumentBuilder unorderedList(List<String> list);
DocumentBuilder tableWithHeaderRow(List<String> rowsInCSV);
DocumentBuilder newLine();
String toString();
}

View File

@@ -0,0 +1,12 @@
package io.swagger2markup.builder;
/**
* Project: swagger2asciidoc
* Copyright: Deutsche Telekom AG
*
* @author Robert Winkler <robert.winkler@telekom.de>
* @since 2.0.0
*/
public interface Markup {
public String toString();
}

View File

@@ -0,0 +1,37 @@
package io.swagger2markup.builder.asciidoc;
import io.swagger2markup.builder.Markup;
/**
* @author Robert Winkler
*/
public enum AsciiDoc implements Markup {
LABELED(":: "),
TABLE("|==="),
LISTING("----"),
HARDBREAKS(":hardbreaks:"),
DOCUMENT_TITLE("= "),
SECTION_TITLE_LEVEL1("== "),
SECTION_TITLE_LEVEL2("=== "),
SECTION_TITLE_LEVEL3("==== "),
BOLD("*"),
ITALIC("*"),
LIST_ENTRY("* ");
private final String markup;
/**
* @param markup AsciiDoc markup
*/
private AsciiDoc(final String markup) {
this.markup = markup;
}
/* (non-Javadoc)
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return markup;
}
}

View File

@@ -0,0 +1,77 @@
package io.swagger2markup.builder.asciidoc;
import io.swagger2markup.builder.AbstractDocumentBuilder;
import io.swagger2markup.builder.DocumentBuilder;
import java.util.List;
/**
* @author Robert Winkler
*/
public class AsciiDocBuilder extends AbstractDocumentBuilder{
@Override
public DocumentBuilder documentTitle(String title){
documentTitle(AsciiDoc.DOCUMENT_TITLE, title);
return this;
}
@Override
public DocumentBuilder sectionTitleLevel1(String title){
sectionTitleLevel1(AsciiDoc.SECTION_TITLE_LEVEL1, title);
return this;
}
@Override
public DocumentBuilder sectionTitleLevel2(String title){
sectionTitleLevel2(AsciiDoc.SECTION_TITLE_LEVEL2, title);
return this;
}
@Override
public DocumentBuilder sectionTitleLevel3(String title){
sectionTitleLevel3(AsciiDoc.SECTION_TITLE_LEVEL3, title);
return this;
}
@Override
public DocumentBuilder paragraph(String text){
paragraph(AsciiDoc.HARDBREAKS, text);
return this;
}
@Override
public DocumentBuilder listing(String text){
listing(AsciiDoc.LISTING, text);
return this;
}
@Override
public DocumentBuilder boldTextLine(String text){
boldTextLine(AsciiDoc.BOLD, text);
return this;
}
@Override
public DocumentBuilder italicTextLine(String text) {
italicTextLine(AsciiDoc.ITALIC, text);
return this;
}
@Override
public DocumentBuilder unorderedList(List<String> list){
unorderedList(AsciiDoc.LIST_ENTRY, list);
return this;
}
@Override
public DocumentBuilder tableWithHeaderRow(List<String> rowsInCSV){
documentBuilder.append("[format=\"csv\", options=\"header\"]").append(newLine);
documentBuilder.append(AsciiDoc.TABLE).append(newLine);
for(String row : rowsInCSV){
documentBuilder.append(row).append(newLine);
}
documentBuilder.append(AsciiDoc.TABLE).append(newLine).append(newLine);
return this;
}
}

View File

@@ -0,0 +1,41 @@
package io.swagger2markup.builder.markdown;
import io.swagger2markup.builder.Markup;
/**
* Project: swagger2asciidoc
* Copyright: Deutsche Telekom AG
*
* @author Robert Winkler <robert.winkler@telekom.de>
* @since 2.0.0
*/
public enum Markdown implements Markup {
HARDBREAKS(""),
TABLE_COLUMN("|"),
TABLE_ROW("-"),
LISTING("```"),
DOCUMENT_TITLE("# "),
SECTION_TITLE_LEVEL1("## "),
SECTION_TITLE_LEVEL2("### "),
SECTION_TITLE_LEVEL3("### "),
BOLD("**"),
ITALIC("*"),
LIST_ENTRY("* ");
private final String markup;
/**
* @param markup AsciiDoc markup
*/
private Markdown(final String markup) {
this.markup = markup;
}
/* (non-Javadoc)
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return markup;
}
}

View File

@@ -0,0 +1,103 @@
package io.swagger2markup.builder.markdown;
import io.swagger2markup.builder.AbstractDocumentBuilder;
import io.swagger2markup.builder.DocumentBuilder;
import java.util.Arrays;
import java.util.List;
/**
* Project: swagger2asciidoc
* Copyright: Deutsche Telekom AG
*
* @author Robert Winkler <robert.winkler@telekom.de>
* @since 2.0.0
*/
public class MarkdownBuilder extends AbstractDocumentBuilder
{
@Override
public DocumentBuilder documentTitle(String title){
documentTitle(Markdown.DOCUMENT_TITLE, title);
return this;
}
@Override
public DocumentBuilder sectionTitleLevel1(String title){
sectionTitleLevel1(Markdown.SECTION_TITLE_LEVEL1, title);
return this;
}
@Override
public DocumentBuilder sectionTitleLevel2(String title){
sectionTitleLevel2(Markdown.SECTION_TITLE_LEVEL2, title);
return this;
}
@Override
public DocumentBuilder sectionTitleLevel3(String title){
sectionTitleLevel3(Markdown.SECTION_TITLE_LEVEL3, title);
return this;
}
@Override
public DocumentBuilder paragraph(String text){
paragraph(Markdown.HARDBREAKS, text);
return this;
}
@Override
public DocumentBuilder listing(String text){
listing(Markdown.LISTING, text);
return this;
}
@Override
public DocumentBuilder boldTextLine(String text){
boldTextLine(Markdown.BOLD, text);
return this;
}
@Override
public DocumentBuilder italicTextLine(String text) {
italicTextLine(Markdown.ITALIC, text);
return this;
}
@Override
public DocumentBuilder unorderedList(List<String> list){
unorderedList(Markdown.LIST_ENTRY, list);
return this;
}
@Override
public DocumentBuilder tableWithHeaderRow(List<String> rowsInCSV){
String headersInCSV = rowsInCSV.get(0);
List<String> contentRowsInCSV = rowsInCSV.subList(1, rowsInCSV.size());
List<String> headers = Arrays.asList(headersInCSV.split(","));
// Header
documentBuilder.append(Markdown.TABLE_COLUMN);
for(String header : headers){
documentBuilder.append(header).append(Markdown.TABLE_COLUMN);
}
newLine();
// Header/Content separator
documentBuilder.append(Markdown.TABLE_COLUMN);
for(String header : headers){
for(int i = 1; i<5; i++) {
documentBuilder.append(Markdown.TABLE_ROW);
}
documentBuilder.append(Markdown.TABLE_COLUMN);
}
newLine();
// Content
for(String contentRow : contentRowsInCSV){
documentBuilder.append(Markdown.TABLE_COLUMN);
List<String> columns = Arrays.asList(contentRow.split(","));
for(String columnText : columns){
documentBuilder.append(columnText).append(Markdown.TABLE_COLUMN);
}
}
newLine().newLine();
return this;
}
}

View File

@@ -0,0 +1,20 @@
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");
}
}

View File

@@ -0,0 +1,846 @@
{
"swagger": "2.0",
"info": {
"description": "This is a sample server Petstore server.\n\n[Learn about Swagger](http://swagger.wordnik.com) or join the IRC channel `#swagger` on irc.freenode.net.\n\nFor this sample, you can use the api key `special-key` to test the authorization filters\n",
"version": "1.0.0",
"title": "Swagger Petstore",
"termsOfService": "http://helloreverb.com/terms/",
"contact": {
"name": "apiteam@wordnik.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"host": "petstore.swagger.wordnik.com",
"basePath": "/v2",
"schemes": [
"http"
],
"paths": {
"/pets": {
"post": {
"tags": [
"pet"
],
"summary": "Add a new pet to the store",
"description": "",
"operationId": "addPet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": false,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write_pets",
"read_pets"
]
}
]
},
"put": {
"tags": [
"pet"
],
"summary": "Update an existing pet",
"description": "",
"operationId": "updatePet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": false,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
},
"405": {
"description": "Validation exception"
}
},
"security": [
{
"petstore_auth": [
"write_pets",
"read_pets"
]
}
]
}
},
"/pets/findByStatus": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by status",
"description": "Multiple status values can be provided with comma seperated strings",
"operationId": "findPetsByStatus",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "query",
"name": "status",
"description": "Status values that need to be considered for filter",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid status value"
}
},
"security": [
{
"petstore_auth": [
"write_pets",
"read_pets"
]
}
]
}
},
"/pets/findByTags": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by tags",
"description": "Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.",
"operationId": "findPetsByTags",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "query",
"name": "tags",
"description": "Tags to filter by",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid tag value"
}
},
"security": [
{
"petstore_auth": [
"write_pets",
"read_pets"
]
}
]
}
},
"/pets/{petId}": {
"get": {
"tags": [
"pet"
],
"summary": "Find pet by ID",
"description": "Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions",
"operationId": "getPetById",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "path",
"name": "petId",
"description": "ID of pet that needs to be fetched",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
}
},
"security": [
{
"api_key": []
},
{
"petstore_auth": [
"write_pets",
"read_pets"
]
}
]
},
"post": {
"tags": [
"pet"
],
"summary": "Updates a pet in the store with form data",
"description": "",
"operationId": "updatePetWithForm",
"consumes": [
"application/x-www-form-urlencoded"
],
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "path",
"name": "petId",
"description": "ID of pet that needs to be updated",
"required": true,
"type": "string"
},
{
"in": "formData",
"name": "name",
"description": "Updated name of the pet",
"required": true,
"type": "string"
},
{
"in": "formData",
"name": "status",
"description": "Updated status of the pet",
"required": true,
"type": "string"
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write_pets",
"read_pets"
]
}
]
},
"delete": {
"tags": [
"pet"
],
"summary": "Deletes a pet",
"description": "",
"operationId": "deletePet",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "header",
"name": "api_key",
"description": "",
"required": true,
"type": "string"
},
{
"in": "path",
"name": "petId",
"description": "Pet id to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"400": {
"description": "Invalid pet value"
}
},
"security": [
{
"petstore_auth": [
"write_pets",
"read_pets"
]
}
]
}
},
"/stores/order": {
"post": {
"tags": [
"store"
],
"summary": "Place an order for a pet",
"description": "",
"operationId": "placeOrder",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "order placed for purchasing the pet",
"required": false,
"schema": {
"$ref": "#/definitions/Order"
}
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Order"
}
},
"400": {
"description": "Invalid Order"
}
}
}
},
"/stores/order/{orderId}": {
"get": {
"tags": [
"store"
],
"summary": "Find purchase order by ID",
"description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions",
"operationId": "getOrderById",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "path",
"name": "orderId",
"description": "ID of pet that needs to be fetched",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Order"
}
},
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Order not found"
}
}
},
"delete": {
"tags": [
"store"
],
"summary": "Delete purchase order by ID",
"description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors",
"operationId": "deleteOrder",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "path",
"name": "orderId",
"description": "ID of the order that needs to be deleted",
"required": true,
"type": "string"
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Order not found"
}
}
}
},
"/users": {
"post": {
"tags": [
"user"
],
"summary": "Create user",
"description": "This can only be done by the logged in user.",
"operationId": "createUser",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Created user object",
"required": false,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/users/createWithArray": {
"post": {
"tags": [
"user"
],
"summary": "Creates list of users with given input array",
"description": "",
"operationId": "createUsersWithArrayInput",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "List of user object",
"required": false,
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/users/createWithList": {
"post": {
"tags": [
"user"
],
"summary": "Creates list of users with given input array",
"description": "",
"operationId": "createUsersWithListInput",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "List of user object",
"required": false,
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/users/login": {
"get": {
"tags": [
"user"
],
"summary": "Logs user into the system",
"description": "",
"operationId": "loginUser",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "query",
"name": "username",
"description": "The user name for login",
"required": false,
"type": "string"
},
{
"in": "query",
"name": "password",
"description": "The password for login in clear text",
"required": false,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "string"
}
},
"400": {
"description": "Invalid username/password supplied"
}
}
}
},
"/users/logout": {
"get": {
"tags": [
"user"
],
"summary": "Logs out current logged in user session",
"description": "",
"operationId": "logoutUser",
"produces": [
"application/json",
"application/xml"
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/users/{username}": {
"get": {
"tags": [
"user"
],
"summary": "Get user by user name",
"description": "",
"operationId": "getUserByName",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "path",
"name": "username",
"description": "The name that needs to be fetched. Use user1 for testing.",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/User"
}
},
"400": {
"description": "Invalid username supplied"
},
"404": {
"description": "User not found"
}
}
},
"put": {
"tags": [
"user"
],
"summary": "Updated user",
"description": "This can only be done by the logged in user.",
"operationId": "updateUser",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "path",
"name": "username",
"description": "name that need to be deleted",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "body",
"description": "Updated user object",
"required": false,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"400": {
"description": "Invalid user supplied"
},
"404": {
"description": "User not found"
}
}
},
"delete": {
"tags": [
"user"
],
"summary": "Delete user",
"description": "This can only be done by the logged in user.",
"operationId": "deleteUser",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "path",
"name": "username",
"description": "The name that needs to be deleted",
"required": true,
"type": "string"
}
],
"responses": {
"400": {
"description": "Invalid username supplied"
},
"404": {
"description": "User not found"
}
}
}
}
},
"securityDefinitions": {
"api_key": {
"type": "apiKey",
"name": "api_key",
"in": "header"
},
"petstore_auth": {
"type": "oauth2",
"authorizationUrl": "http://petstore.swagger.wordnik.com/api/oauth/dialog",
"flow": "implicit",
"scopes": {
"write_pets": "modify pets in your account",
"read_pets": "read your pets"
}
}
},
"definitions": {
"User": {
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"username": {
"type": "string"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"phone": {
"type": "string"
},
"userStatus": {
"type": "integer",
"format": "int32",
"description": "User Status"
}
}
},
"Category": {
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
}
},
"Pet": {
"required": [
"name",
"photoUrls"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"category": {
"$ref": "#/definitions/Category"
},
"name": {
"type": "string",
"example": "doggie"
},
"photoUrls": {
"type": "array",
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/Tag"
}
},
"status": {
"type": "string",
"description": "pet status in the store"
}
}
},
"Tag": {
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
}
},
"Order": {
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"petId": {
"type": "integer",
"format": "int64"
},
"quantity": {
"type": "integer",
"format": "int32"
},
"shipDate": {
"type": "string",
"format": "date-time"
},
"status": {
"type": "string",
"description": "Order Status"
},
"complete": {
"type": "boolean"
}
}
}
}
}