forked from harness/harness
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
25d6a8c
commit 2b00d12
Showing
7 changed files
with
579 additions
and
501 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
// +build ignore | ||
|
||
// This program generates api documentation from a | ||
// swaggerfile using an amber template. | ||
|
||
package main | ||
|
||
import ( | ||
"crypto/md5" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
|
||
"github.com/eknkc/amber" | ||
"github.com/go-swagger/go-swagger/spec" | ||
) | ||
|
||
var ( | ||
templ = flag.String("template", "index.amber", "") | ||
input = flag.String("input", "swagger.json", "") | ||
output = flag.String("output", "", "") | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
|
||
// parses the swagger spec file | ||
spec, err := spec.YAMLSpec(*input) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
swag := spec.Spec() | ||
|
||
// create output source for file. defaults to | ||
// stdout but may be file. | ||
var w io.WriteCloser = os.Stdout | ||
if *output != "" { | ||
w, err = os.Create(*output) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%v\n", err) | ||
return | ||
} | ||
defer w.Close() | ||
} | ||
|
||
// we wrap the swagger file in a map, otherwise it | ||
// won't work with our existing templates, which expect | ||
// a map as the root parameter. | ||
var data = map[string]interface{}{ | ||
"Swagger": normalize(swag), | ||
} | ||
|
||
t := amber.MustCompileFile(*templ, amber.DefaultOptions) | ||
err = t.Execute(w, data) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
// Swagger is a simplified representation of the swagger | ||
// document with a subset of the fields used to generate | ||
// our API documentation. | ||
type Swagger struct { | ||
Tags []Tag | ||
} | ||
|
||
type Tag struct { | ||
Name string | ||
Ops []Operation | ||
} | ||
|
||
type Operation struct { | ||
ID string | ||
Method string | ||
Path string | ||
Desc string | ||
Summary string | ||
|
||
Params []Param | ||
Results []Result | ||
} | ||
|
||
type Param struct { | ||
Name string | ||
Desc string | ||
Type string | ||
Example interface{} | ||
InputTo string | ||
IsObject bool | ||
} | ||
|
||
type Result struct { | ||
Status int | ||
Desc string | ||
Example interface{} | ||
IsObject bool | ||
IsArray bool | ||
} | ||
|
||
// normalize is a helper function that normalizes the swagger | ||
// file to a simpler format that makes it easier to work with | ||
// inside the template. | ||
func normalize(swag *spec.Swagger) Swagger { | ||
swag_ := Swagger{} | ||
|
||
for _, tag := range swag.Tags { | ||
tag_ := Tag{Name: tag.Name} | ||
|
||
// group the paths based on their tag value. | ||
for route, path := range swag.Paths.Paths { | ||
|
||
var ops = []*spec.Operation{ | ||
path.Get, | ||
path.Put, | ||
path.Post, | ||
path.Patch, | ||
path.Delete, | ||
} | ||
|
||
// flatten the operations into an array and convert | ||
// the underlying data so that it is a bit easier to | ||
// work with. | ||
for _, op := range ops { | ||
|
||
// the operation must have a tag to | ||
// be rendered in our custom template. | ||
if op == nil || !hasTag(tag.Name, op.Tags) { | ||
continue | ||
} | ||
|
||
item := Operation{} | ||
item.Path = route | ||
item.Method = getMethod(op, path) | ||
item.Desc = op.Description | ||
item.Summary = op.Summary | ||
item.ID = fmt.Sprintf("%x", md5.Sum([]byte(item.Path+item.Method))) | ||
|
||
// convert the operation input parameters into | ||
// our internal format so that it is easier to | ||
// work with in the template. | ||
for _, param := range op.Parameters { | ||
param_ := Param{} | ||
param_.Name = param.Name | ||
param_.Desc = param.Description | ||
param_.Type = param.Type | ||
param_.IsObject = param.Schema != nil | ||
param_.InputTo = param.In | ||
|
||
if param_.IsObject { | ||
param_.Type = param.Schema.Ref.GetPointer().String()[13:] | ||
param_.Example = param.Schema.Example | ||
} | ||
item.Params = append(item.Params, param_) | ||
} | ||
|
||
// convert the operation response types into | ||
// our internal format so that it is easier to | ||
// work with in the template. | ||
for code, resp := range op.Responses.StatusCodeResponses { | ||
result := Result{} | ||
result.Desc = resp.Description | ||
result.Status = code | ||
result.IsObject = resp.Schema != nil | ||
if result.IsObject { | ||
result.IsArray = resp.Schema.Items != nil | ||
|
||
name := resp.Schema.Ref.GetPointer().String() | ||
if len(name) != 0 { | ||
def, _ := swag.Definitions[name[13:]] | ||
result.Example = def.Example | ||
} | ||
} | ||
if result.IsArray { | ||
name := resp.Schema.Items.Schema.Ref.GetPointer().String() | ||
def, _ := swag.Definitions[name[13:]] | ||
result.Example = def.Example | ||
} | ||
item.Results = append(item.Results, result) | ||
} | ||
tag_.Ops = append(tag_.Ops, item) | ||
} | ||
} | ||
|
||
swag_.Tags = append(swag_.Tags, tag_) | ||
} | ||
|
||
return swag_ | ||
} | ||
|
||
// hasTag is a helper function that returns true if | ||
// an operation has the specified tag label. | ||
func hasTag(want string, in []string) bool { | ||
for _, got := range in { | ||
if got == want { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// getMethod is a helper function that returns the http | ||
// method for the specified operation in a path. | ||
func getMethod(op *spec.Operation, path spec.PathItem) string { | ||
switch { | ||
case op == path.Get: | ||
return "GET" | ||
case op == path.Put: | ||
return "PUT" | ||
case op == path.Patch: | ||
return "PATCH" | ||
case op == path.Post: | ||
return "POST" | ||
case op == path.Delete: | ||
return "DELETE" | ||
} | ||
return "" | ||
} |
Oops, something went wrong.