forked from go-openapi/spec
-
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
0 parents
commit cb9ba12
Showing
38 changed files
with
3,449 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package spec | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/casualjim/go-swagger/util" | ||
) | ||
|
||
// type operationRef struct { | ||
// operation *Operation | ||
// parameter *Parameter | ||
// } | ||
|
||
// specAnalyzer takes a swagger spec object and turns it into a registry | ||
// with a bunch of utility methods to act on the information in the spec | ||
type specAnalyzer struct { | ||
spec *Swagger | ||
consumes map[string]struct{} | ||
produces map[string]struct{} | ||
authSchemes map[string]struct{} | ||
operations map[string]map[string]*Operation | ||
} | ||
|
||
func (s *specAnalyzer) initialize() { | ||
for _, c := range s.spec.Consumes { | ||
s.consumes[c] = struct{}{} | ||
} | ||
for _, c := range s.spec.Produces { | ||
s.produces[c] = struct{}{} | ||
} | ||
for path, pathItem := range s.AllPaths() { | ||
s.analyzeOperations(path, &pathItem) | ||
} | ||
} | ||
|
||
func (s *specAnalyzer) analyzeOperations(path string, op *PathItem) { | ||
s.analyzeOperation("GET", path, op.Get) | ||
s.analyzeOperation("PUT", path, op.Put) | ||
s.analyzeOperation("POST", path, op.Post) | ||
s.analyzeOperation("PATCH", path, op.Patch) | ||
s.analyzeOperation("DELETE", path, op.Delete) | ||
s.analyzeOperation("HEAD", path, op.Head) | ||
s.analyzeOperation("OPTIONS", path, op.Options) | ||
} | ||
|
||
func (s *specAnalyzer) analyzeOperation(method, path string, op *Operation) { | ||
if op != nil { | ||
for _, c := range op.Consumes { | ||
s.consumes[c] = struct{}{} | ||
} | ||
for _, c := range op.Produces { | ||
s.produces[c] = struct{}{} | ||
} | ||
if _, ok := s.operations[method]; !ok { | ||
s.operations[method] = make(map[string]*Operation) | ||
} | ||
s.operations[method][path] = op | ||
} | ||
} | ||
|
||
// ConsumesFor gets the mediatypes for the operation | ||
func (s *specAnalyzer) ConsumesFor(operation *Operation) []string { | ||
cons := make(map[string]struct{}) | ||
for k := range s.consumes { | ||
cons[k] = struct{}{} | ||
} | ||
for _, c := range operation.Consumes { | ||
cons[c] = struct{}{} | ||
} | ||
return s.structMapKeys(cons) | ||
} | ||
|
||
// ProducesFor gets the mediatypes for the operation | ||
func (s *specAnalyzer) ProducesFor(operation *Operation) []string { | ||
prod := make(map[string]struct{}) | ||
for k := range s.produces { | ||
prod[k] = struct{}{} | ||
} | ||
for _, c := range operation.Produces { | ||
prod[c] = struct{}{} | ||
} | ||
return s.structMapKeys(prod) | ||
} | ||
|
||
func fieldNameFromParam(param *Parameter) string { | ||
if nm, ok := param.Extensions.GetString("go-name"); ok { | ||
return nm | ||
} | ||
return util.ToGoName(param.Name) | ||
} | ||
|
||
func (s *specAnalyzer) paramsAsMap(parameters []Parameter, res map[string]Parameter) { | ||
for _, param := range parameters { | ||
res[fieldNameFromParam(¶m)] = param | ||
} | ||
} | ||
|
||
func (s *specAnalyzer) ParamsFor(method, path string) map[string]Parameter { | ||
res := make(map[string]Parameter) | ||
for _, param := range s.spec.Parameters { | ||
res[fieldNameFromParam(¶m)] = param | ||
} | ||
if pi, ok := s.spec.Paths.Paths[path]; ok { | ||
s.paramsAsMap(pi.Parameters, res) | ||
s.paramsAsMap(s.operations[strings.ToUpper(method)][path].Parameters, res) | ||
} | ||
return res | ||
} | ||
|
||
func (s *specAnalyzer) OperationFor(method, path string) (*Operation, bool) { | ||
if mp, ok := s.operations[strings.ToUpper(method)]; ok { | ||
op, fn := mp[path] | ||
return op, fn | ||
} | ||
return nil, false | ||
} | ||
|
||
func (s *specAnalyzer) Operations() map[string]map[string]*Operation { | ||
return s.operations | ||
} | ||
|
||
func (s *specAnalyzer) structMapKeys(mp map[string]struct{}) []string { | ||
var result []string | ||
for k := range mp { | ||
result = append(result, k) | ||
} | ||
return result | ||
} | ||
|
||
// AllPaths returns all the paths in the swagger spec | ||
func (s *specAnalyzer) AllPaths() map[string]PathItem { | ||
return s.spec.Paths.Paths | ||
} | ||
|
||
func (s *specAnalyzer) OperationIDs() []string { | ||
var result []string | ||
for _, v := range s.operations { | ||
for _, vv := range v { | ||
result = append(result, vv.ID) | ||
} | ||
} | ||
return result | ||
} | ||
|
||
func (s *specAnalyzer) RequiredConsumes() []string { | ||
return s.structMapKeys(s.consumes) | ||
} | ||
|
||
func (s *specAnalyzer) RequiredProduces() []string { | ||
return s.structMapKeys(s.produces) | ||
} |
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,97 @@ | ||
package spec | ||
|
||
import ( | ||
"sort" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func newAnalyzer(spec *Swagger) *specAnalyzer { | ||
a := &specAnalyzer{ | ||
spec: spec, | ||
consumes: make(map[string]struct{}), | ||
produces: make(map[string]struct{}), | ||
authSchemes: make(map[string]struct{}), | ||
operations: make(map[string]map[string]*Operation), | ||
} | ||
a.initialize() | ||
return a | ||
} | ||
|
||
func TestAnalyzer(t *testing.T) { | ||
formatParam := QueryParam() | ||
formatParam.Name = "format" | ||
formatParam.Type = "string" | ||
|
||
limitParam := QueryParam() | ||
limitParam.Name = "limit" | ||
limitParam.Type = "integer" | ||
limitParam.Format = "int32" | ||
limitParam.Extensions = Extensions(map[string]interface{}{}) | ||
limitParam.Extensions.Add("go-name", "Limit") | ||
|
||
skipParam := QueryParam() | ||
skipParam.Name = "skip" | ||
skipParam.Type = "integer" | ||
skipParam.Format = "int32" | ||
pi := PathItem{} | ||
pi.Parameters = []Parameter{*limitParam} | ||
|
||
op := &Operation{} | ||
op.Consumes = []string{"application/x-yaml"} | ||
op.Produces = []string{"application/x-yaml"} | ||
op.ID = "someOperation" | ||
op.Parameters = []Parameter{*skipParam} | ||
pi.Get = op | ||
|
||
spec := &Swagger{ | ||
Consumes: []string{"application/json"}, | ||
Produces: []string{"application/json"}, | ||
Parameters: map[string]Parameter{"format": *formatParam}, | ||
Paths: &Paths{ | ||
Paths: map[string]PathItem{ | ||
"/": pi, | ||
}, | ||
}, | ||
} | ||
analyzer := newAnalyzer(spec) | ||
|
||
assert.Len(t, analyzer.consumes, 2) | ||
assert.Len(t, analyzer.produces, 2) | ||
assert.Len(t, analyzer.operations, 1) | ||
assert.Equal(t, analyzer.operations["GET"]["/"], spec.Paths.Paths["/"].Get) | ||
|
||
expected := []string{"application/json", "application/x-yaml"} | ||
sort.Sort(sort.StringSlice(expected)) | ||
consumes := analyzer.ConsumesFor(spec.Paths.Paths["/"].Get) | ||
sort.Sort(sort.StringSlice(consumes)) | ||
assert.Equal(t, expected, consumes) | ||
|
||
produces := analyzer.ProducesFor(spec.Paths.Paths["/"].Get) | ||
sort.Sort(sort.StringSlice(produces)) | ||
assert.Equal(t, expected, produces) | ||
|
||
parameters := analyzer.ParamsFor("GET", "/") | ||
assert.Len(t, parameters, 3) | ||
|
||
operations := analyzer.OperationIDs() | ||
assert.Len(t, operations, 1) | ||
|
||
producers := analyzer.RequiredProduces() | ||
assert.Len(t, producers, 2) | ||
consumers := analyzer.RequiredConsumes() | ||
assert.Len(t, consumers, 2) | ||
|
||
ops := analyzer.Operations() | ||
assert.Len(t, ops, 1) | ||
assert.Len(t, ops["GET"], 1) | ||
|
||
op, ok := analyzer.OperationFor("get", "/") | ||
assert.True(t, ok) | ||
assert.NotNil(t, op) | ||
|
||
op, ok = analyzer.OperationFor("delete", "/") | ||
assert.False(t, ok) | ||
assert.Nil(t, op) | ||
} |
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,123 @@ | ||
package spec | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/smartystreets/goconvey/convey" | ||
) | ||
|
||
func TestAuthSerialization(t *testing.T) { | ||
Convey("Auth should", t, func() { | ||
Convey("serialize", func() { | ||
Convey("basic auth security scheme", func() { | ||
auth := BasicAuth() | ||
So(auth, ShouldSerializeJSON, `{"type":"basic"}`) | ||
}) | ||
|
||
Convey("header key model", func() { | ||
auth := APIKeyAuth("api-key", "header") | ||
So(auth, ShouldSerializeJSON, `{"type":"apiKey","name":"api-key","in":"header"}`) | ||
}) | ||
|
||
Convey("oauth2 implicit flow model", func() { | ||
auth := OAuth2Implicit("http://foo.com/authorization") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"implicit","authorizationUrl":"http://foo.com/authorization"}`) | ||
}) | ||
|
||
Convey("oauth2 password flow model", func() { | ||
auth := OAuth2Password("http://foo.com/token") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"password","tokenUrl":"http://foo.com/token"}`) | ||
}) | ||
|
||
Convey("oauth2 application flow model", func() { | ||
auth := OAuth2Application("http://foo.com/token") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token"}`) | ||
}) | ||
|
||
Convey("oauth2 access code flow model", func() { | ||
auth := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"accessCode","authorizationUrl":"http://foo.com/authorization","tokenUrl":"http://foo.com/token"}`) | ||
}) | ||
|
||
Convey("oauth2 implicit flow model with scopes", func() { | ||
auth := OAuth2Implicit("http://foo.com/authorization") | ||
auth.AddScope("email", "read your email") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"implicit","authorizationUrl":"http://foo.com/authorization","scopes":{"email":"read your email"}}`) | ||
}) | ||
|
||
Convey("oauth2 password flow model with scopes", func() { | ||
auth := OAuth2Password("http://foo.com/token") | ||
auth.AddScope("email", "read your email") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"password","tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`) | ||
}) | ||
|
||
Convey("oauth2 application flow model with scopes", func() { | ||
auth := OAuth2Application("http://foo.com/token") | ||
auth.AddScope("email", "read your email") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`) | ||
}) | ||
|
||
Convey("oauth2 access code flow model with scopes", func() { | ||
auth := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") | ||
auth.AddScope("email", "read your email") | ||
So(auth, ShouldSerializeJSON, `{"type":"oauth2","flow":"accessCode","authorizationUrl":"http://foo.com/authorization","tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`) | ||
}) | ||
}) | ||
|
||
Convey("deserialize", func() { | ||
Convey("basic auth security scheme", func() { | ||
auth := BasicAuth() | ||
So(`{"type":"basic"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("header key model", func() { | ||
auth := APIKeyAuth("api-key", "header") | ||
So(`{"in":"header","name":"api-key","type":"apiKey"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 implicit flow model", func() { | ||
auth := OAuth2Implicit("http://foo.com/authorization") | ||
So(`{"authorizationUrl":"http://foo.com/authorization","flow":"implicit","type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 password flow model", func() { | ||
auth := OAuth2Password("http://foo.com/token") | ||
So(`{"flow":"password","tokenUrl":"http://foo.com/token","type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 application flow model", func() { | ||
auth := OAuth2Application("http://foo.com/token") | ||
So(`{"flow":"application","tokenUrl":"http://foo.com/token","type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 access code flow model", func() { | ||
auth := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") | ||
So(`{"authorizationUrl":"http://foo.com/authorization","flow":"accessCode","tokenUrl":"http://foo.com/token","type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 implicit flow model with scopes", func() { | ||
auth := OAuth2Implicit("http://foo.com/authorization") | ||
auth.AddScope("email", "read your email") | ||
So(`{"authorizationUrl":"http://foo.com/authorization","flow":"implicit","scopes":{"email":"read your email"},"type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 password flow model with scopes", func() { | ||
auth := OAuth2Password("http://foo.com/token") | ||
auth.AddScope("email", "read your email") | ||
So(`{"flow":"password","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 application flow model with scopes", func() { | ||
auth := OAuth2Application("http://foo.com/token") | ||
auth.AddScope("email", "read your email") | ||
So(`{"flow":"application","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
|
||
Convey("oauth2 access code flow model with scopes", func() { | ||
auth := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") | ||
auth.AddScope("email", "read your email") | ||
So(`{"authorizationUrl":"http://foo.com/authorization","flow":"accessCode","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, ShouldParseJSON, auth) | ||
}) | ||
}) | ||
}) | ||
} |
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,10 @@ | ||
package spec | ||
|
||
// ContactInfo contact information for the exposed API. | ||
// | ||
// For more information: http://goo.gl/8us55a#contactObject | ||
type ContactInfo struct { | ||
Name string `json:"name,omitempty"` | ||
URL string `json:"url,omitempty"` | ||
Email string `json:"email,omitempty"` | ||
} |
Oops, something went wrong.