diff --git a/node_modules/swagger-to-markdown/.npmignore b/node_modules/swagger-to-markdown/.npmignore new file mode 100644 index 0000000..aceedef --- /dev/null +++ b/node_modules/swagger-to-markdown/.npmignore @@ -0,0 +1,2 @@ +.idea +.idea/* diff --git a/node_modules/swagger-to-markdown/README.md b/node_modules/swagger-to-markdown/README.md new file mode 100644 index 0000000..914e6f7 --- /dev/null +++ b/node_modules/swagger-to-markdown/README.md @@ -0,0 +1,195 @@ +Here at Skookum we write a lot of REST services. REST services provides a great integration point between frontend and backend developers. This makes it easy to split work into large units, frontend development and backend development. Frontend developers write tremendously awesome user interfaces with clean markup and a performant and responsive user experience. Backend developers write testable, maintainable, performant, and robust service code. The REST service specification is the glue that holds it all together. A specification allows frontend developers to start immediately by mocking the REST service responses with real data. A specification allows backend developers to start writing unit tests to ensure their code meets the desired state. + +We all agree a REST service specification is a great tool to streamline and enhance our development process. We also all agree that writing documention is about as fun as a root canal. I have found a great tool to make this process easier-Swagger-UI [https://github.com/wordnik/swagger-ui]. The Swagger set of tools is an entire toolset revolved around generating REST service documentation. At its core is the Swagger specification. Here is an example: + +```javascript +{ + "apiVersion":"0.2", + "swaggerVersion":"1.1-SNAPSHOT", + "basePath":"http://petstore.swagger.wordnik.com/api", + "resourcePath":"/store", + "apis":[ + { + "path":"/store.{format}/order/{orderId}", + "description":"Operations about store", + "operations":[ + { + "httpMethod":"GET", + "summary":"Find purchase order by ID", + "notes":"For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors", + "responseClass":"Order", + "nickname":"getOrderById", + "parameters":[ + { + "name":"orderId", + "description":"ID of pet that needs to be fetched", + "paramType":"path", + "required":true, + "allowMultiple":false, + "dataType":"string" + } + ], + "errorResponses":[ + { + "code":400, + "reason":"Invalid ID supplied" + }, + { + "code":404, + "reason":"Order not found" + } + ] + }, + { + "httpMethod":"DELETE", + "summary":"Delete purchase order by ID", + "notes":"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "responseClass":"void", + "nickname":"deleteOrder", + "parameters":[ + { + "name":"orderId", + "description":"ID of the order that needs to be deleted", + "paramType":"path", + "required":true, + "allowMultiple":false, + "dataType":"string" + } + ], + "errorResponses":[ + { + "code":400, + "reason":"Invalid ID supplied" + }, + { + "code":404, + "reason":"Order not found" + } + ] + } + ] + } + ] +} +``` + +Swagger-UI is a tool that will transform the Swagger specification into a fully functional REST client that allows developers not only to view the REST documentation, but also interact with the REST API. You can view example requests, example responses, and even input arguments and see how the responses change. Overall its an awesome discovery tool and really helps developers, both frontend for discovery, and backend for testing and demoing. + +In our use of Swagger-UI we came across one issue though. Swagger-UI is only good if users have access to the tool. If however you aren't able to put Swagger-UI in a public space, the users will not be able to view the documentation or interact with the API. For example if you and your clients are on different networks, and the API should not be exposed on the public web. This leads you back to writing your own API documentation by hand again and losing the power of the Swagger specification. + +Well one handy thing about a specification is that, well its a specification. This means as developers we know it follows very specific rules. We can write tools that interact with that specification. So I decided to write a Swagger-to-Markdown script. This script can be found here https://github.com/Skookum/SwaggerToMarkdown/blob/master/swagger-to-markdown.rb. It takes a number of parameters, but the main parameters it takes is the Swagger specification for your API. It will traverse your specification and generate a static Markdown file that contains a lot of the same information as the dynamic Swagger-UI tool. It writes out all the operations, their arguments, their error codes, and will even perform curl operations to generate example responses and example requests. Here is an example markdown file that was generated with our script. + + ./swagger-to-markdown.rb -r resources.json -p parameters.json -n Demo -o test.md -s pet.json + +or reading from a remote server: + + ./swagger-to-markdown.rb -r resources.json -p parameters.json -n Demo -o test.md -s http://petstore.swagger.wordnik.com/api/pet.json + +One thing to note is that this remote read is not performing any type of validation so please use this only on trusted resources. + +#Demo 0.2 REST API +Base Path: http://petstore.swagger.wordnik.com/api + +[Please add API specific content here] + + +##General Considerations +[Please add API specific content here] + + +##Pet Resource +Operations about pets + +###Find pet by ID + +Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions +####Definition + + + GET /pet.{format}/{petId} + +####Arguments +* **petId** - ID of pet that needs to be fetched + + +####Example Request + curl http://petstore.swagger.wordnik.com/api/pet.json/1 + +####Example Response + { + "id": 1, + "category": { + "id": 2, + "name": "Cats" + }, + "name": "Cat 1", + "photoUrls": [ + "url1", + "url2" + ], + "tags": [ + { + "id": 1, + "name": "tag1" + }, + { + "id": 2, + "name": "tag2" + } + ], + "status": "available" + } + +####Potential Errors +* **400** - Invalid ID supplied +* **404** - Pet not found + + +###Add a new pet to the store + +[Please add operation information to the notes section] + +####Definition + + + POST /pet.{format} + +####Arguments +* [Please add a name for argument] - Pet object that needs to be added to the store + + +####Example Request + curl -X POST -H "Content-Type:application/json" -d '{ "id": 1, "category": { "id": 2, "name": "Cats" }, "name": "Cat 1", "photoUrls": [ "url1", "url2" ], "tags": [ { "id": 1, "name": "tag1" }, { "id": 2, "name": "tag2" } ], "status": "available" }' http://petstore.swagger.wordnik.com/api/pet.json + +####Example Response + "SUCCESS" + +####Potential Errors +* **405** - Invalid input + + +###Update an existing pet + +[Please add operation information to the notes section] + +####Definition + + + PUT /pet.{format} + +####Arguments +* [Please add a name for argument] - Pet object that needs to be updated in the store + + +####Example Request + curl -X PUT -H "Content-Type:application/json" -d '{ "id": 1, "category": { "id": 2, "name": "Cats" }, "name": "Cat 1", "photoUrls": [ "url1", "url2" ], "tags": [ { "id": 1, "name": "tag1" }, { "id": 2, "name": "tag2" } ], "status": "available" }' http://petstore.swagger.wordnik.com/api/pet.json + +####Example Response + "SUCCESS" + +####Potential Errors +* **400** - Invalid ID supplied +* **404** - Pet not found +* **405** - Validation exception + +Now we have another tool in our toolbox. For now this script lives in one of our organization's repositories, but once I clean it up a little more I plan on giving it over to Wordnik. I hope others will find a use for this script. diff --git a/node_modules/swagger-to-markdown/args.js b/node_modules/swagger-to-markdown/args.js new file mode 100644 index 0000000..3fce9e0 --- /dev/null +++ b/node_modules/swagger-to-markdown/args.js @@ -0,0 +1,89 @@ +var File = require('fs'); +function opt(shrt, lng, help, type, required) { + return { + short:shrt, + long:lng, + help:help, + type:type, + required:required + } +} +function Parser(opts) { + + function help(err){ + var req = opts.filter(function(v){ return v.required}).map(function(v){ return '-'+ v.short+' '+ v.type }).join(' '); + console.log('usage: '+process.argv.join(' '), req); + if (!Array.isArray(err)){ + console.log('ERROR', Array.prototype.slice.call(arguments,0).join(' ')); + process.exit(1); + } + args.forEach(function(v){ + console.log(v.required ? '*': '', '-'+ v.short, '--'+ v.long, typeof v.type =='string' ? v.type : '', v.help) + }) + process.exit(0) + } + this.handle = { + 'filename':function (args) { + var file = args.shift(); + if (!File.existsSync(file)) { + throw "file does not exist: " + file; + } + return file; + }, + 'json_file':function(args){ + var sargs =args.shift().split(/,/).map(function(v){ + return JSON.parse(File.readFileSync(v, 'utf-8')) + }); + + return sargs.length == 1 ? sargs[0] : sargs; + }, + 'array':function (args) { + return args.shift().split(/,\s*/) + }, + 'int':function (args) { + return parseInt(args.shift()) + }, + 'string':function(args){ + return args.shift(); + }, + 'help':help + } + var self = this; + function ex(opt, args, ret){ + var f = typeof opt.type == 'function' ? opt.type : self.handle[opt.type]; + if (!f) { + help('Could not handle opt', opt.long, opt); + } else { + try { + ret[opt.long] = f.call(self, args); + } catch (e) { + help('Could not handle opt', e); + } + } + } + this.parse = function (args) { + var ret = {}; + while (args.length) { + var arg = args.shift(); + for (var i in opts) { + var opt = opts[i] + if ('-' + opt.short == arg || '--' + opt.long == arg) { + ex(opt, args, ret); + } + } + } + opts.forEach(function(opt){ + if (ret[opt.long]) + return; + if (opt.default){ + ex(opt, [opt.default], ret); + }else if (opt.required){ + help('required option "--'+ opt.long+ '" is not satisfied') + } + + }); + return ret; + } +} +Parser.opt = opt; +module.exports = Parser; \ No newline at end of file diff --git a/node_modules/swagger-to-markdown/index.js b/node_modules/swagger-to-markdown/index.js new file mode 100644 index 0000000..1247028 --- /dev/null +++ b/node_modules/swagger-to-markdown/index.js @@ -0,0 +1 @@ +module.exports = require('./swagger'); diff --git a/node_modules/swagger-to-markdown/package.json b/node_modules/swagger-to-markdown/package.json new file mode 100644 index 0000000..544b6ea --- /dev/null +++ b/node_modules/swagger-to-markdown/package.json @@ -0,0 +1,34 @@ +{ + "name": "swagger-to-markdown", + "version": "0.3.1", + "author": { + "name": "jspears", + "email": "speajus@gmail.com" + }, + "description": "convert swagger to markdown", + "repository": { + "type": "git", + "url": "https://github.com/jspears/swagger-to-markdown.git" + }, + "keywords": [ + "swagger", + "markdown", + "documentation" + ], + "license": "MIT", + "engines": { + "node": ">=0.6" + }, + "readme": "Here at Skookum we write a lot of REST services. REST services provides a great integration point between frontend and backend developers. This makes it easy to split work into large units, frontend development and backend development. Frontend developers write tremendously awesome user interfaces with clean markup and a performant and responsive user experience. Backend developers write testable, maintainable, performant, and robust service code. The REST service specification is the glue that holds it all together. A specification allows frontend developers to start immediately by mocking the REST service responses with real data. A specification allows backend developers to start writing unit tests to ensure their code meets the desired state.\n\nWe all agree a REST service specification is a great tool to streamline and enhance our development process. We also all agree that writing documention is about as fun as a root canal. I have found a great tool to make this process easier-Swagger-UI [https://github.com/wordnik/swagger-ui]. The Swagger set of tools is an entire toolset revolved around generating REST service documentation. At its core is the Swagger specification. Here is an example:\n\n```javascript\n{\n \"apiVersion\":\"0.2\",\n \"swaggerVersion\":\"1.1-SNAPSHOT\",\n \"basePath\":\"http://petstore.swagger.wordnik.com/api\",\n \"resourcePath\":\"/store\",\n \"apis\":[\n {\n \"path\":\"/store.{format}/order/{orderId}\",\n \"description\":\"Operations about store\",\n \"operations\":[\n {\n \"httpMethod\":\"GET\",\n \"summary\":\"Find purchase order by ID\",\n \"notes\":\"For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors\",\n \"responseClass\":\"Order\",\n \"nickname\":\"getOrderById\",\n \"parameters\":[\n {\n \"name\":\"orderId\",\n \"description\":\"ID of pet that needs to be fetched\",\n \"paramType\":\"path\",\n \"required\":true,\n \"allowMultiple\":false,\n \"dataType\":\"string\"\n }\n ],\n \"errorResponses\":[\n {\n \"code\":400,\n \"reason\":\"Invalid ID supplied\"\n },\n {\n \"code\":404,\n \"reason\":\"Order not found\"\n }\n ]\n },\n {\n \"httpMethod\":\"DELETE\",\n \"summary\":\"Delete purchase order by ID\",\n \"notes\":\"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors\",\n \"responseClass\":\"void\",\n \"nickname\":\"deleteOrder\",\n \"parameters\":[\n {\n \"name\":\"orderId\",\n \"description\":\"ID of the order that needs to be deleted\",\n \"paramType\":\"path\",\n \"required\":true,\n \"allowMultiple\":false,\n \"dataType\":\"string\"\n }\n ],\n \"errorResponses\":[\n {\n \"code\":400,\n \"reason\":\"Invalid ID supplied\"\n },\n {\n \"code\":404,\n \"reason\":\"Order not found\"\n }\n ]\n }\n ]\n }\n ]\n}\n```\n\nSwagger-UI is a tool that will transform the Swagger specification into a fully functional REST client that allows developers not only to view the REST documentation, but also interact with the REST API. You can view example requests, example responses, and even input arguments and see how the responses change. Overall its an awesome discovery tool and really helps developers, both frontend for discovery, and backend for testing and demoing.\n\nIn our use of Swagger-UI we came across one issue though. Swagger-UI is only good if users have access to the tool. If however you aren't able to put Swagger-UI in a public space, the users will not be able to view the documentation or interact with the API. For example if you and your clients are on different networks, and the API should not be exposed on the public web. This leads you back to writing your own API documentation by hand again and losing the power of the Swagger specification.\n\nWell one handy thing about a specification is that, well its a specification. This means as developers we know it follows very specific rules. We can write tools that interact with that specification. So I decided to write a Swagger-to-Markdown script. This script can be found here https://github.com/Skookum/SwaggerToMarkdown/blob/master/swagger-to-markdown.rb. It takes a number of parameters, but the main parameters it takes is the Swagger specification for your API. It will traverse your specification and generate a static Markdown file that contains a lot of the same information as the dynamic Swagger-UI tool. It writes out all the operations, their arguments, their error codes, and will even perform curl operations to generate example responses and example requests. Here is an example markdown file that was generated with our script.\n\n ./swagger-to-markdown.rb -r resources.json -p parameters.json -n Demo -o test.md -s pet.json\n\nor reading from a remote server:\n\n ./swagger-to-markdown.rb -r resources.json -p parameters.json -n Demo -o test.md -s http://petstore.swagger.wordnik.com/api/pet.json\n\nOne thing to note is that this remote read is not performing any type of validation so please use this only on trusted resources.\n\n#Demo 0.2 REST API\nBase Path: http://petstore.swagger.wordnik.com/api\n\n[Please add API specific content here]\n\n\n##General Considerations\n[Please add API specific content here]\n\n\n##Pet Resource\nOperations about pets\n\n###Find pet by ID\n\nReturns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions\n####Definition\n\n\n GET /pet.{format}/{petId}\n\n####Arguments\n* **petId** - ID of pet that needs to be fetched\n\n\n####Example Request\n curl http://petstore.swagger.wordnik.com/api/pet.json/1\n\n####Example Response\n {\n \"id\": 1,\n \"category\": {\n \"id\": 2,\n \"name\": \"Cats\"\n },\n \"name\": \"Cat 1\",\n \"photoUrls\": [\n \"url1\",\n \"url2\"\n ],\n \"tags\": [\n {\n \"id\": 1,\n \"name\": \"tag1\"\n },\n {\n \"id\": 2,\n \"name\": \"tag2\"\n }\n ],\n \"status\": \"available\"\n }\n\n####Potential Errors\n* **400** - Invalid ID supplied\n* **404** - Pet not found\n\n\n###Add a new pet to the store\n\n[Please add operation information to the notes section]\n\n####Definition\n\n\n POST /pet.{format}\n\n####Arguments\n* [Please add a name for argument] - Pet object that needs to be added to the store\n\n\n####Example Request\n curl -X POST -H \"Content-Type:application/json\" -d '{ \"id\": 1, \"category\": { \"id\": 2, \"name\": \"Cats\" }, \"name\": \"Cat 1\", \"photoUrls\": [ \"url1\", \"url2\" ], \"tags\": [ { \"id\": 1, \"name\": \"tag1\" }, { \"id\": 2, \"name\": \"tag2\" } ], \"status\": \"available\" }' http://petstore.swagger.wordnik.com/api/pet.json\n\n####Example Response\n \"SUCCESS\"\n\n####Potential Errors\n* **405** - Invalid input\n\n\n###Update an existing pet\n\n[Please add operation information to the notes section]\n\n####Definition\n\n\n PUT /pet.{format}\n\n####Arguments\n* [Please add a name for argument] - Pet object that needs to be updated in the store\n\n\n####Example Request\n curl -X PUT -H \"Content-Type:application/json\" -d '{ \"id\": 1, \"category\": { \"id\": 2, \"name\": \"Cats\" }, \"name\": \"Cat 1\", \"photoUrls\": [ \"url1\", \"url2\" ], \"tags\": [ { \"id\": 1, \"name\": \"tag1\" }, { \"id\": 2, \"name\": \"tag2\" } ], \"status\": \"available\" }' http://petstore.swagger.wordnik.com/api/pet.json\n\n####Example Response\n \"SUCCESS\"\n\n####Potential Errors\n* **400** - Invalid ID supplied\n* **404** - Pet not found\n* **405** - Validation exception\n\nNow we have another tool in our toolbox. For now this script lives in one of our organization's repositories, but once I clean it up a little more I plan on giving it over to Wordnik. I hope others will find a use for this script.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/jspears/swagger-to-markdown/issues" + }, + "homepage": "https://github.com/jspears/swagger-to-markdown", + "_id": "swagger-to-markdown@0.3.1", + "dist": { + "shasum": "aaf807e6af3a1d0e9fa081401a64173cad10376c" + }, + "_from": "swagger-to-markdown@", + "_resolved": "https://registry.npmjs.org/swagger-to-markdown/-/swagger-to-markdown-0.3.1.tgz" +} diff --git a/node_modules/swagger-to-markdown/parameters.json b/node_modules/swagger-to-markdown/parameters.json new file mode 100644 index 0000000..38bda4c --- /dev/null +++ b/node_modules/swagger-to-markdown/parameters.json @@ -0,0 +1,4 @@ +{ + "petId" : "1", + "PET.POST" : "{ \"id\": 1, \"category\": { \"id\": 2, \"name\": \"Cats\" }, \"name\": \"Cat 1\", \"photoUrls\": [ \"url1\", \"url2\" ], \"tags\": [ { \"id\": 1, \"name\": \"tag1\" }, { \"id\": 2, \"name\": \"tag2\" } ], \"status\": \"available\" }" +} diff --git a/node_modules/swagger-to-markdown/pet.json b/node_modules/swagger-to-markdown/pet.json new file mode 100644 index 0000000..8c70536 --- /dev/null +++ b/node_modules/swagger-to-markdown/pet.json @@ -0,0 +1,171 @@ +{ + "apiVersion":"0.2", + "swaggerVersion":"1.0", + "basePath":"http://petstore.swagger.wordnik.com/api", + "resourcePath":"/pet", + "apis":[ + { + "path":"/pet.{format}/{petId}", + "description":"Operations about pets", + "operations":[ + { + "parameters":[ + { + "name":"petId", + "description":"ID of pet that needs to be fetched", + "dataType":"string", + "allowableValues":{ + "valueType":"RANGE", + "max":10.0, + "min":0.0, + "valueType":"RANGE" + }, + "required":true, + "allowMultiple":false, + "paramType":"path" + } + ], + "httpMethod":"GET", + "notes":"Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions", + "responseTypeInternal":"com.wordnik.swagger.sample.model.Pet", + "errorResponses":[ + { + "reason":"Invalid ID supplied", + "code":400 + }, + { + "reason":"Pet not found", + "code":404 + } + ], + "nickname":"getPetById", + "responseClass":"pet", + "summary":"Find pet by ID" + } + ] + }, + { + "path":"/pet.{format}", + "description":"Operations about pets", + "operations":[ + { + "parameters":[ + { + "description":"Pet object that needs to be added to the store", + "dataType":"pet", + "required":true, + "valueTypeInternal":"com.wordnik.swagger.sample.model.Pet", + "allowMultiple":false, + "paramType":"body" + } + ], + "httpMethod":"POST", + "responseTypeInternal":"ok", + "errorResponses":[ + { + "reason":"Invalid input", + "code":405 + } + ], + "nickname":"addPet", + "responseClass":"ok", + "summary":"Add a new pet to the store" + }, + { + "parameters":[ + { + "description":"Pet object that needs to be updated in the store", + "dataType":"pet", + "required":true, + "valueTypeInternal":"com.wordnik.swagger.sample.model.Pet", + "allowMultiple":false, + "paramType":"body" + } + ], + "httpMethod":"PUT", + "responseTypeInternal":"ok", + "errorResponses":[ + { + "reason":"Invalid ID supplied", + "code":400 + }, + { + "reason":"Pet not found", + "code":404 + }, + { + "reason":"Validation exception", + "code":405 + } + ], + "nickname":"updatePet", + "responseClass":"ok", + "summary":"Update an existing pet" + } + ] + } + ], + "models":{ + "Category":{ + "properties":{ + "id":{ + "type":"long" + }, + "name":{ + "type":"string" + } + }, + "id":"category" + }, + "Pet":{ + "properties":{ + "tags":{ + "type":"array", + "items":{ + "$ref":"tag" + } + }, + "id":{ + "type":"long" + }, + "category":{ + "type":"category" + }, + "status":{ + "type":"string", + "description":"pet status in the store", + "allowableValues":{ + "valueType":"LIST", + "values":[ + "available", + "pending", + "sold" + ], + "valueType":"LIST" + } + }, + "name":{ + "type":"string" + }, + "photoUrls":{ + "type":"array", + "items":{ + "type":"string" + } + } + }, + "id":"pet" + }, + "Tag":{ + "properties":{ + "id":{ + "type":"long" + }, + "name":{ + "type":"string" + } + }, + "id":"tag" + } + } +} diff --git a/node_modules/swagger-to-markdown/resources.json b/node_modules/swagger-to-markdown/resources.json new file mode 100644 index 0000000..08b8ab5 --- /dev/null +++ b/node_modules/swagger-to-markdown/resources.json @@ -0,0 +1,11 @@ +{ + "apiVersion":"0.2", + "swaggerVersion":"1.0", + "basePath":"http://petstore.swagger.wordnik.com/api", + "apis":[ + { + "path":"/pet.{format}", + "description":"Operations about pets" + } + ] +} diff --git a/node_modules/swagger-to-markdown/swagger-to-markdown.js b/node_modules/swagger-to-markdown/swagger-to-markdown.js new file mode 100755 index 0000000..c0ebf87 --- /dev/null +++ b/node_modules/swagger-to-markdown/swagger-to-markdown.js @@ -0,0 +1,13 @@ +#!/usr/bin/env node +var SwaggerToMarkdown = require('./swagger'), Parse = require('./args'), opt = Parse.opt; +var options = new Parse([ + opt('n', 'apiname', "Provide the API name", 'string'), + opt('r', 'resourcefile', "Provide the resources.json to define your API resources filename", 'json_file', true), + opt('p', 'parametersfile', "Provide the parameters.json to define your API parameters filename", 'json_file', false), + opt('o', 'markdownfile', "Provide the api.md to define your output Markdown filename", 'filename'), + opt('s', 'specifications', "List of specification files in a json format", 'json_file'), + opt('h', 'help', 'Show this message', 'help'), + opt('v', 'version', 'Show version') +]).parse(process.argv.slice(2)); + +console.log(new SwaggerToMarkdown().$enhance(options).print()); diff --git a/node_modules/swagger-to-markdown/swagger-to-markdown.rb b/node_modules/swagger-to-markdown/swagger-to-markdown.rb new file mode 100755 index 0000000..bd16ff3 --- /dev/null +++ b/node_modules/swagger-to-markdown/swagger-to-markdown.rb @@ -0,0 +1,253 @@ +#!/usr/bin/env ruby + +require 'open3' +require 'rubygems' +require 'json' +require 'net/http' +require 'titleize' +require 'optparse' +require 'ostruct' +require 'open-uri' + +class SwaggerToMarkdown + def self.enhance(options) + resources = extract_json options.resourcefile + @parameters = extract_json options.parametersfile + + write_api_to_markdown options.markdownfile, + options.apiname, + resources['apiVersion'], + resources['basePath'], + resources['apis'], + options.specifications + end + + def self.write_api_to_markdown(markdown_file, api_name, api_version, base_path, apis, specifications) + File.open(markdown_file, "w+") do |f| + write_header f, api_name, api_version, base_path + + apis.each_with_index do |resource, index| + f.write build_markdown_header( + (extract_resource_name(resource['path'])+" resource").titleize, + 2 + ) + f.write resource['description'] + "\n\n" + write_specification(f, base_path, extract_resource_name(resource['path']), specifications[index]) + f.write "\n\n" + end + end + end + + def self.write_specification(f, base_path, resource, specification) + specification = extract_json specification + apis = specification['apis'] + + apis.map {|method| method['operations'].map {|operation| write_operation f, base_path, resource, operation, method['path'] }} + end + + def self.write_operation(f, base_path, resource, operation, path) + if operation['summary'].nil? + f.write build_markdown_header("[Please add operation summary information to the summary section]\n\n", 3) + else + f.write build_markdown_header(operation['summary'] + "\n", 3) + end + + if operation['notes'].nil? + f.write "[Please add operation information to the notes section]\n\n" + else + f.write operation['notes'] + "\n" + end + + f.write build_markdown_header("Definition", 4) + f.write "\n\n" + + write_code_block f, operation['httpMethod'] + " " + path + f.write "\n\n" + + f.write build_markdown_header("Arguments", 4) + write_arguments f, operation['parameters'] + f.write "\n\n" + + f.write build_markdown_header("Example Request", 4) + response = write_example_request f, base_path, operation, path, operation['parameters'], resource + f.write "\n\n" + + f.write build_markdown_header("Example Response", 4) + write_code_block(f, response) if !response.nil? + f.write "\n\n" + + f.write build_markdown_header("Potential Errors", 4) + write_errors f, operation['errorResponses'] + f.write "\n\n" + end + + def self.write_example_request(f, base_path, operation, path, arguments, resource) + path = populate_arguments path, arguments + case operation["httpMethod"] + when "GET" + command = "curl " + base_path + path + when "POST" + data = @parameters[resource.upcase + ".POST"] + command = "curl -X POST -H \"Content-Type:application/json\" -d '" + data + "' " + base_path + path + when "PUT" + data = @parameters[resource.upcase + ".POST"] + command = "curl -X PUT -H \"Content-Type:application/json\" -d '" + data + "' " + base_path + path + end + + stdin, stdout, stderr = Open3.popen3(command) + write_code_block(f, command) + response = stdout.read + begin + JSON.pretty_generate(JSON.parse(response)).gsub("\n","\n ") + rescue + response + end + end + + def self.populate_arguments(path, arguments) + path = path.sub("{format}", "json") + return path if arguments.nil? + + arguments.reject {|argument| argument['name'].nil? }.reject {|argument| @parameters[argument["name"]].nil?}.map {|argument| path = path.sub("{#{argument["name"]}}", @parameters[argument["name"]])} + + path + end + + def self.write_errors(f, errors) + if errors.nil? || errors.length <= 0 + f.write "* None\n" + return + end + + errors.each do |error| + f.write "* " + if error['code'].nil? + f.write "[Please add a code for error]" + else + f.write "**" + error['code'].to_s + "**" + end + + if error['reason'].nil? + f.write "" + else + f.write " - " + error['reason'] + end + + f.write "\n" + end + + end + + def self.write_arguments(f, arguments) + if arguments.nil? || arguments.length <= 0 + f.write "* None\n" + return + end + + arguments.each do |argument| + f.write "* " + if argument['name'].nil? + f.write "[Please add a name for argument]" + else + f.write "**" + argument['name'] + "**" + end + + if argument['description'].nil? + f.write "" + else + f.write " - " + argument['description'] + end + + f.write "\n" + end + end + + def self.write_code_block(f, text) + f.write " " + text + end + + def self.write_header(f, api_name, api_version, base_path) + f.write build_markdown_header(api_name + " " + api_version + " REST API", 1) + f.write "Base Path: " + base_path + "\n\n" + f.write build_input_here + f.write "\n\n" + f.write build_markdown_header("General Considerations", 2) + f.write build_input_here + f.write "\n\n" + end + + def self.extract_resource_name(path) + end_of_resource_name = path.index(".") + resource_name = path[1,end_of_resource_name-1] + end + + def self.build_input_here + input_here = "[Please add API specific content here]\n" + end + + def self.build_markdown_header(text, level) + header = "#" * level + text + "\n" + end + + def self.extract_json(file_name) + file = open(file_name) + json = JSON.parse(file.read) + end + + def self.parse(args) + # The options specified on the command line will be collected in *options*. + # We set default values here. + options = OpenStruct.new + + opts = OptionParser.new do |opts| + opts.banner = "Usage: swagger-to-markdown.rb -n API_NAME -r resources.json -o api.md -s x,y,z" + + opts.separator "" + opts.separator "Specific options:" + + opts.on("-n", "--name API-name", + "Provide the API name") do |apiname| + options.apiname = apiname + end + + opts.on("-r", "--resources resources.json", + "Provide the resources.json to define your API resources filename") do |resourcefile| + options.resourcefile = resourcefile + end + + opts.on("-p", "--parameters parameters.json", + "Provide the parameters.json to define your API parameters filename") do |parametersfile| + options.parametersfile = parametersfile + end + + opts.on("-o", "--markdown api.md", + "Provide the api.md to define your output Markdown filename") do |markdownfile| + options.markdownfile = markdownfile + end + + opts.on("-s", "--specification x,y,z", Array, "List of specification files in a json format") do |specifications| + options.specifications = specifications + end + + opts.separator "" + opts.separator "Common options:" + + opts.on_tail("-h", "--help", "Show this message") do + puts opts + exit + end + + # Another typical switch to print the version. + opts.on_tail("--version", "Show version") do + puts "0.1" + exit + end + end + + opts.parse!(args) + options + end +end + +options = SwaggerToMarkdown.parse(ARGV) +SwaggerToMarkdown.enhance(options) diff --git a/node_modules/swagger-to-markdown/swagger.js b/node_modules/swagger-to-markdown/swagger.js new file mode 100644 index 0000000..2c0d282 --- /dev/null +++ b/node_modules/swagger-to-markdown/swagger.js @@ -0,0 +1,232 @@ + +function $titlelize(str) { + if (!str) return; + str.split(/[^a-zA-Z0-9]/).filter(function(v){ + return v; + }).map(function (v) { + return v.substring(0, 1).toUpperCase() + v.substring(1); + }).join(' '); +} + +function SwaggerToMarkdown() { + var self = this; + var _lines = []; + this.print = function(){ + return _lines.join(''); + } + var f = { + $write:function () { + for (var i = 0, l = arguments.length; i < l; i++) { + _lines.push(arguments[i]); + } + } + } + + this.$enhance = function (options) { + var resources = options.resourcefile; + this.parameters = options.parametersfile; + this.$write_api_to_markdown(options.markdownfile, options.apiname, resources["apiVersion"], resources["basePath"], resources["apis"], options.specifications); + return this; + }; + + this.$write_api_to_markdown = function (markdown_file, api_name, api_version, base_path, apis, specifications) { + + self.$write_header(f, api_name, api_version, base_path); + return apis && apis.forEach(function (resource, index) { + var path = resource.path + $titlelize(resource.resource); + f.$write(self.$build_markdown_header( + $titlelize(self.$extract_resource_name(resource.path)+'resource'), 2 + )) + f.$write(self.$build_markdown_header(self.$extract_resource_name(path), 2)); + f.$write(resource.description+"\n\n"); + (Array.isArray(specifications) ? specifications : [specifications]).forEach(function(spec){ + + self.$write_specification(f, base_path, self.$extract_resource_name(resource.path),spec); + }) + return f.$write("\n\n"); + }, this); + return this; + }; + + this.$write_specification = function (f, base_path, resource, specification) { + var apis = specification["apis"]; + return apis && apis.map(function (method) { + return method["operations"].map(function (operation) { + return self.$write_operation(f, base_path, resource, operation, method["path"]) + }) + }); + }; + + this.$write_operation = function (f, base_path, resource, operation, path) { + var response; + if (!operation.summary) { + f.$write(this.$build_markdown_header("[Please add operation summary information to the summary section]\n\n", 3)) + } else { + f.$write(this.$build_markdown_header(operation.summary + "\n", 3)) + } + + if (!operation.notes) { + f.$write("[Please add operation information to the notes section]\n\n") + } else { + f.$write(operation.notes + "\n"); + } + ; + f.$write(this.$build_markdown_header("Definition", 4)); + f.$write("\n\n"); + this.$write_code_block(f, operation.httpMethod + " " + path); + f.$write("\n\n"); + f.$write(this.$build_markdown_header("Arguments", 4)); + this.$write_arguments(f, operation.parameters); + f.$write("\n\n"); + f.$write(this.$build_markdown_header("Example Request", 4)); + response = this.$write_example_request(f, base_path, operation, path, operation.parameters, resource); + f.$write("\n\n"); + f.$write(this.$build_markdown_header("Example Response", 4)); + + if (!response) { + this.$write_code_block(f, response) + } + + f.$write("\n\n"); + f.$write(this.$build_markdown_header("Potential Errors", 4)); + this.$write_errors(f, operation.errorResponses); + return f.$write("\n\n"); + }; + + this.$write_example_request = function (f, base_path, operation, path, arguments, resource) { + + path = this.$populate_arguments(path, arguments); + var commmand, data; + switch (operation.httpMethod) { + case 'GET': + command = "curl " + base_path + path; + break; + case 'POST': + { + + data = resource ? "" : this.parameters[resource.toUpperCase() + ".POST"]; + command = "curl -X POST -H \"Content-Type:application/json\" -d '" + data + "' " + base_path + path; + break; + } + case 'PUT': + { + data = resource ? "" : this.parameters[resource.toUpperCase() + ".PUT"]; + command = "curl -X PUT -H \"Content-Type:application/json\" -d '" + data + "' " + base_path + path; + + } + } + this.$write_code_block(f, command); +// response = stdout.$read(); +// return (function () { +// try { +// __scope.JSON.$pretty_generate(__scope.JSON.$parse(response)).$gsub("\n", "\n ") +// } catch ($err) { +// if (true) { +// response +// } +// else { +// throw $err; +// } +// } +// }).call(this); + }; + + this.$populate_arguments = function (path, arguments) { + path = path.replace("{format}", "json"); + if (!(arguments && arguments.length)) { + return path; + } + + arguments.filter(function (argument) { + return argument.name && argument.paramType == 'path' && self.parameters && self.parameters[argument.name] + }).map(function (argument) { + return path = path.replace("{" + argument.name + "}", self.parameters[argument.name]) + }); + return path; + }; + + this.$write_errors = function (f, errors) { + if (!(errors && errors.length)) { + f.$write("* None\n"); + return null; + } + + return errors.forEach(function (error) { + + f.$write("* "); + if (!error.code) { + f.$write("[Please add a code for error]") + } else { + f.$write("**" + error.code + "**"); + } + + if (!error.reason) { + f.$write("") + } else { + f.$write(" - " + error.reason) + } + return f.$write("\n"); + }); + }; + + this.$write_arguments = function (f, args) { + if (!(args && args.length)) { + f.$write("* None\n"); + return null; + } + + return args.forEach(function (argument) { + f.$write("* "); + if (!argument.name) { + f.$write("[Please add a name for argument]") + } else { + f.$write("**" + argument.name + "**") + } + + if (!argument.description) { + f.$write("") + } else { + f.$write(" - " + argument.description) + } + + return f.$write("\n"); + }); + }; + + this.$write_code_block = function (f, text) { + return f.$write(" " + text) + }; + + this.$write_header = function (f, api_name, api_version, base_path) { + + f.$write(this.$build_markdown_header(api_name + " " + api_version + " REST API", 1)); + f.$write("Base Path: " + base_path + "\n\n"); + f.$write(this.$build_input_here()); + f.$write("\n\n"); + f.$write(this.$build_markdown_header("General Considerations", 2)); + f.$write(this.$build_input_here()); + return f.$write("\n\n"); + }; + + this.$extract_resource_name = function (path) { + return path.substring(1, path.indexOf('.')); + + }; + + this.$build_input_here = function () { + return "[Please add API specific content here]\n" + }; + + this.$build_markdown_header = function (text, level) { + var str = [] + while (level-- > 0) + str.push('#'); + if (text) + str.push(text); + + return str.join('') + "\n"; + }; + + +}; +module.exports = SwaggerToMarkdown \ No newline at end of file diff --git a/node_modules/swagger-to-markdown/test.md b/node_modules/swagger-to-markdown/test.md new file mode 100644 index 0000000..fdd8f5b --- /dev/null +++ b/node_modules/swagger-to-markdown/test.md @@ -0,0 +1,108 @@ +#Demo 0.2 REST API +Base Path: http://petstore.swagger.wordnik.com/api + +[Please add API specific content here] + + +##General Considerations +[Please add API specific content here] + + +##Pet Resource +Operations about pets + +###Find pet by ID + +Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions +####Definition + + + GET /pet.{format}/{petId} + +####Arguments +* **petId** - ID of pet that needs to be fetched + + +####Example Request + curl http://petstore.swagger.wordnik.com/api/pet.json/1 + +####Example Response + { + "id": 1, + "category": { + "id": 2, + "name": "Cats" + }, + "name": "Cat 1", + "photoUrls": [ + "url1", + "url2" + ], + "tags": [ + { + "id": 1, + "name": "tag1" + }, + { + "id": 2, + "name": "tag2" + } + ], + "status": "available" + } + +####Potential Errors +* **400** - Invalid ID supplied +* **404** - Pet not found + + +###Add a new pet to the store + +[Please add operation information to the notes section] + +####Definition + + + POST /pet.{format} + +####Arguments +* [Please add a name for argument] - Pet object that needs to be added to the store + + +####Example Request + curl -X POST -H "Content-Type:application/json" -d '{ "id": 1, "category": { "id": 2, "name": "Cats" }, "name": "Cat 1", "photoUrls": [ "url1", "url2" ], "tags": [ { "id": 1, "name": "tag1" }, { "id": 2, "name": "tag2" } ], "status": "available" }' http://petstore.swagger.wordnik.com/api/pet.json + +####Example Response + "SUCCESS" + +####Potential Errors +* **405** - Invalid input + + +###Update an existing pet + +[Please add operation information to the notes section] + +####Definition + + + PUT /pet.{format} + +####Arguments +* [Please add a name for argument] - Pet object that needs to be updated in the store + + +####Example Request + curl -X PUT -H "Content-Type:application/json" -d '{ "id": 1, "category": { "id": 2, "name": "Cats" }, "name": "Cat 1", "photoUrls": [ "url1", "url2" ], "tags": [ { "id": 1, "name": "tag1" }, { "id": 2, "name": "tag2" } ], "status": "available" }' http://petstore.swagger.wordnik.com/api/pet.json + +####Example Response + "SUCCESS" + +####Potential Errors +* **400** - Invalid ID supplied +* **404** - Pet not found +* **405** - Validation exception + + + + diff --git a/node_modules/swagger-to-markdown/test2.md b/node_modules/swagger-to-markdown/test2.md new file mode 100644 index 0000000..92f6c04 --- /dev/null +++ b/node_modules/swagger-to-markdown/test2.md @@ -0,0 +1,88 @@ +#Demo 0.2 REST API +Base Path: http://petstore.swagger.wordnik.com/api + +[Please add API specific content here] + + +##General Considerations +[Please add API specific content here] + + +## +pet +Operations about pets + +###Find pet by ID + +Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions +####Definition + + + GET /pet.{format}/{petId} + +####Arguments +* **petId** - ID of pet that needs to be fetched + + +####Example Request + curl http://petstore.swagger.wordnik.com/api/pet.json/1 + +####Example Response + undefined + +####Potential Errors +* **400** - Invalid ID supplied +* **404** - Pet not found + + +###Add a new pet to the store + +[Please add operation information to the notes section] + +####Definition + + + POST /pet.{format} + +####Arguments +* [Please add a name for argument] - Pet object that needs to be added to the store + + +####Example Request + curl -X POST -H "Content-Type:application/json" -d '{ "id": 1, "category": { "id": 2, "name": "Cats" }, "name": "Cat 1", "photoUrls": [ "url1", "url2" ], "tags": [ { "id": 1, "name": "tag1" }, { "id": 2, "name": "tag2" } ], "status": "available" }' http://petstore.swagger.wordnik.com/api/pet.json + +####Example Response + undefined + +####Potential Errors +* **405** - Invalid input + + +###Update an existing pet + +[Please add operation information to the notes section] + +####Definition + + + PUT /pet.{format} + +####Arguments +* [Please add a name for argument] - Pet object that needs to be updated in the store + + +####Example Request + curl -X PUT -H "Content-Type:application/json" -d 'undefined' http://petstore.swagger.wordnik.com/api/pet.json + +####Example Response + undefined + +####Potential Errors +* **400** - Invalid ID supplied +* **404** - Pet not found +* **405** - Validation exception + + + + +