added sinatra server generator

This commit is contained in:
Tony Tam 2012-09-05 17:25:01 -07:00
parent 66f98ebaa8
commit 5662891d62
7 changed files with 344 additions and 0 deletions

View File

@ -0,0 +1,76 @@
/**
* Copyright 2012 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.wordnik.swagger.codegen.BasicScalaGenerator
import com.wordnik.swagger.core._
import java.io.File
import scala.collection.mutable.{ HashMap, ListBuffer }
object SinatraServerGenerator extends BasicScalaGenerator {
def main(args: Array[String]) = generateClient(args)
override def templateDir = "samples/server-generator/sinatra/templates"
val outputFolder = "samples/server-generator/sinatra/output"
// where to write generated code
override def destinationDir = outputFolder + ""
override def modelPackage = Some("com.wordnik.client.model")
// template used for apis
apiTemplateFiles ++= Map("api.mustache" -> ".rb")
modelTemplateFiles.clear
override def apiPackage = Some("lib")
// supporting classes
override def supportingFiles = List(
("README.md", outputFolder, "README.md"),
("config.ru", outputFolder, "config.ru"),
("MyApp.rb", outputFolder, "MyApp.rb"),
("lib/Swaggering.rb", outputFolder + File.separator + "lib", "Swaggering.rb"))
override def processApiMap(m: Map[String, AnyRef]): Map[String, AnyRef] = {
val mutable = scala.collection.mutable.Map() ++ m
mutable.map(k => {
k._1 match {
// the scalatra templates like lower-case httpMethods
case e: String if (e == "httpMethod") => mutable += "httpMethod" -> k._2.toString.toLowerCase
// convert path into ruby-ish syntax without basePart (i.e. /pet.{format}/{petId} => /:petId
case e: String if (e == "path") => {
val path = {
val arr = k._2.toString.split("/")
if (arr.length >= 2) {
mutable += "basePart" -> (arr.slice(2, arr.length).mkString("", "/", ""))
"/" + arr.slice(2, arr.length).mkString("", "/", "")
} else
k._2.toString
}
mutable += "path" -> path.replaceAll("\\{", ":").replaceAll("\\}", "")
}
case _ =>
}
})
mutable.toMap
}
}

View File

@ -0,0 +1,12 @@
require './lib/swaggering'
# only need to extend if you want special configuration!
class MyApp < Swaggering
self.configure do |config|
config.api_version = '0.2'
end
end
require './lib/PetApi.rb'
require './lib/StoreApi.rb'
require './lib/UserApi.rb'

View File

@ -0,0 +1 @@
## empty

View File

@ -0,0 +1,57 @@
require 'json'
{{#operations}}
{{#operation}}
MyApp.add_route('{{httpMethod}}', '{{path}}', {
"resourcePath" => "/{{name}}",
"summary" => "{{{summary}}}",
"nickname" => "{{nickname}}",
"responseClass" => "{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}",
"endpoint" => "{{path}}",
"notes" => "{{{notes}}}",
"parameters" => [
{{#queryParams}}
{
"name" => "{{paramName}}",
"description" => "{{description}}",
"dataType" => "{{swaggerDataType}}",
"paramType" => "query",
"allowMultiple" => {{allowMultiple}},
"allowableValues" => "{{allowableValues}}",
{{#defaultValue}}"defaultValue" => {{{defaultValue}}}{{/defaultValue}}
},
{{/queryParams}}
{{#pathParams}}
{
"name" => "{{paramName}}",
"description" => "{{description}}",
"dataType" => "{{swaggerDataType}}",
"paramType" => "path",
},
{{/pathParams}}
{{#headerParams}}
{
"name" => "{{paramName}}",
"description" => "{{description}}",
"dataType" => "{{swaggerDataType}}",
"paramType" => "header",
},
{{/headerParams}}
{{#bodyParams}}
{
"name" => "body",
"description" => "{{description}}",
"dataType" => "{{swaggerDataType}}",
"paramType" => "body",
}
{{/bodyParams}}
]}) do
cross_origin
# the guts live here
{"message" => "yes, it worked"}.to_json
end
{{/operation}}
{{/operations}}

View File

@ -0,0 +1,2 @@
require './myapp'
run MyApp

View File

@ -0,0 +1,154 @@
require 'json'
require 'sinatra/base'
require 'sinatra/cross_origin'
class Configuration
attr_accessor :base_path, :api_version, :swagger_version, :format_specifier
def initialize
@api_version = '1.0'
@base_path = 'http://localhost:4567'
@swagger_version = '1.1'
@format_specifier = ".json"
end
end
class Swaggering < Sinatra::Base
register Sinatra::CrossOrigin
@@routes = {}
@@configuration = Configuration.new
attr_accessor :configuration
def self.configure
get("/resources" + @@configuration.format_specifier) {
cross_origin
Swaggering.to_resource_listing
}
@@configuration ||= Configuration.new
yield(@@configuration) if block_given?
end
def self.add_route(method, path, swag={}, opts={}, &block)
fullPath = swag["resourcePath"].to_s + @@configuration.format_specifier + path
accepted = case method
when 'get'
get(fullPath, opts, &block)
true
when 'post'
post(fullPath, opts, &block)
true
when 'delete'
delete(fullPath, opts, &block)
true
when 'put'
put(fullPath, opts, &block)
true
else
false
end
if accepted then
resourcePath = swag["resourcePath"].to_s
ops = @@routes[resourcePath]
if ops.nil?
ops = Array.new
@@routes.merge!(resourcePath => ops)
get(resourcePath + @@configuration.format_specifier) do
cross_origin
Swaggering.to_api(resourcePath)
end
end
swag.merge!("httpMethod" => method.to_s.upcase)
ops.push(swag)
end
end
def self.to_resource_listing
apis = Array.new
(@@routes.keys).each do |key|
api = {
"path" => (key + ".{format}"),
"description" => "no description"
}
apis.push api
end
resource = {
"apiVersion" => @@configuration.api_version,
"swaggerVersion" => @@configuration.swagger_version,
"apis" => apis
}
resource.to_json
end
def self.to_api(resourcePath)
apis = {}
models = []
@@routes[resourcePath].each do |route|
endpoint = route["endpoint"].gsub(/:(\w+)(\/?)/,'{\1}\2')
path = (resourcePath + ".{format}" + endpoint)
api = apis[path]
if api.nil?
api = {"path" => path, "description" => "description", "operations" => []}
apis.merge!(path => api)
end
parameters = route["parameters"]
unless parameters.nil? then
parameters.each do |param|
av_string = param["allowableValues"]
unless av_string.nil?
if av_string.count('[') > 0
pattern = /^([A-Z]*)\[(.*)\]/
match = pattern.match av_string
case match.to_a[1]
when "LIST"
allowables = match.to_a[2].split(',')
param["allowableValues"] = {
"valueType" => "LIST",
"values" => allowables
}
when "RANGE"
allowables = match.to_a[2].split(',')
param["allowableValues"] = {
"valueType" => "RANGE",
"min" => allowables[0],
"max" => allowables[1]
}
end
end
end
end
end
op = {
"httpMethod" => route["httpMethod"],
"description" => route["summary"],
"responseClass" => route["responseClass"],
"notes" => route["notes"],
"nickname" => route["nickname"],
"summary" => route["summary"],
"parameters" => route["parameters"]
}
api["operations"].push(op)
end
api_listing = {
"apiVersion" => @@configuration.api_version,
"swaggerVersion" => @@configuration.swagger_version,
"basePath" => @@configuration.base_path,
"resourcePath" => resourcePath,
"apis" => apis.values,
"models" => models
}
api_listing.to_json
end
end

View File

@ -0,0 +1,42 @@
require 'json'
require './lib/swaggering'
require 'sinatra/cross_origin'
configure do
end
# only need to extend if you want special configuration!
class MyApp < Swaggering
self.configure do |config|
config.api_version = '0.2'
end
end
# add all your routes
{{#apis}}
{{#operations}}
MyApp.add_route('{{httpMethod}}', '{{path}}', {
"resourcePath" => "{{resourcePath}}",
"summary" => "{{{summary}}}",
"nickname" => "{{nickname}}",
"responseClass" => "{{responseClass}}",
"endpoint" => "{{name}}",
"notes" => "{{{notes}}}",
"parameters" => [{
"name" => "status",
"description" => "Status values that need to be considered for filter",
"dataType" => "string",
"paramType" => "path",
"allowMultiple" => true,
"allowableValues" => "LIST[available,pending,sold]",
"defaultValue" => "available"}]}) do
cross_origin
# the guts live here
{"message" => "yes, it worked"}.to_json
end
{{/operations}}
{{/apis}}