Go-Back-Skeleton/vendor/github.com/go-chi/docgen/raml/raml.go
2017-09-28 21:58:25 +02:00

159 lines
3.7 KiB
Go

package raml
import (
"errors"
"fmt"
"strings"
yaml "gopkg.in/yaml.v2"
)
var header = `#%RAML 1.0
---
`
type RAML struct {
Title string `yaml:"title,omitempty"`
BaseUri string `yaml:"baseUri,omitempty"`
Protocols []string `yaml:"protocols,omitempty"`
MediaType string `yaml:"mediaType,omitempty"`
Version string `yaml:"version,omitempty"`
Documentation []Documentation `yaml:"documentation,omitempty"`
Resources `yaml:",inline"`
}
func (r *RAML) String() string {
bytes, _ := yaml.Marshal(r)
return fmt.Sprintf("%s%s", header, bytes)
}
type Documentation struct {
Title string `yaml:"title"`
Content string `yaml:"content"`
}
type Resources map[string]*Resource
type Resource struct {
DisplayName string `yaml:"displayName,omitempty"`
Description string `yaml:"description,omitempty"`
Responses Responses `yaml:"responses,omitempty"`
Body Body `yaml:"body,omitempty"`
Is []string `yaml:"is,omitempty"`
Type string `yaml:"type,omitempty"`
SecuredBy []string `yaml:"securedBy,omitempty"`
UriParameters []string `yaml:"uirParameters,omitempty"`
QueryParameters []string `yaml:"queryParameters,omitempty"`
Resources `yaml:",inline"`
}
type Responses map[int]Response
type Response struct {
Body `yaml:"body,omitempty"`
}
type Body map[string]Example // Content-Type to Example
type Example struct {
Example string `yaml:"example,omitempty"`
}
func (r *RAML) Add(method string, route string, resource *Resource) error {
if resource == nil {
return errors.New("raml.Add(): resource can't be nil")
}
if r.Resources == nil {
r.Resources = Resources{}
}
return r.Resources.upsert(method, route, resource)
}
func (r *RAML) AddUnder(parentRoute string, method string, route string, resource *Resource) error {
if resource == nil {
return errors.New("raml.Add(): resource can't be nil")
}
if r.Resources == nil {
r.Resources = Resources{}
}
if parentRoute == "" || parentRoute == "/" {
return errors.New("raml.AddUnderParent(): parentRoute can't be empty or '/'")
}
if !strings.HasPrefix(route, parentRoute) {
return errors.New("raml.AddUnderParent(): parentRoute must be present in the route string")
}
route = strings.TrimPrefix(route, parentRoute)
if route == "" {
route = "/"
}
parentNode, found := r.Resources[parentRoute]
if !found {
parentNode = &Resource{
Resources: Resources{},
Responses: Responses{},
}
r.Resources[parentRoute] = parentNode
}
return parentNode.Resources.upsert(method, route, resource)
}
// Find or create node tree from a given route and inject the resource.
func (r Resources) upsert(method string, route string, resource *Resource) error {
currentNode := r
parts := strings.Split(route, "/")
if len(parts) > 0 {
last := len(parts) - 1
// Upsert route of the resource.
for _, part := range parts[:last] {
if part == "" {
continue
}
part = "/" + part
node, found := currentNode[part]
if !found {
node = &Resource{
Resources: Resources{},
Responses: Responses{},
}
currentNode[part] = node
}
currentNode = node.Resources
}
if parts[last] != "" {
// Upsert resource into the very bottom of the node tree.
part := "/" + parts[last]
node, found := currentNode[part]
if !found {
node = &Resource{
Resources: Resources{},
Responses: Responses{},
}
}
currentNode[part] = node
currentNode = node.Resources
}
}
method = strings.ToLower(method)
if _, found := currentNode[method]; found {
return nil
// return fmt.Errorf("duplicated method route: %v %v", method, route)
}
currentNode[method] = resource
return nil
}