代码拉取完成,页面将自动刷新
package expr
import (
"fmt"
"goa.design/goa/eval"
)
type (
// StreamKind is a type denoting the kind of stream.
StreamKind int
// MethodExpr defines a single method.
MethodExpr struct {
// DSLFunc contains the DSL used to initialize the expression.
eval.DSLFunc
// Name of method.
Name string
// Description of method for consumption by humans.
Description string
// Docs points to the method external documentation if any.
Docs *DocsExpr
// Payload attribute
Payload *AttributeExpr
// Result attribute
Result *AttributeExpr
// Errors lists the error responses.
Errors []*ErrorExpr
// Requirements contains the security requirements for the
// method. One requirement is composed of potentially multiple
// schemes. Incoming requests must validate at least one
// requirement to be authorized.
Requirements []*SecurityExpr
// Service that owns method.
Service *ServiceExpr
// Meta is an arbitrary set of key/value pairs, see dsl.Meta
Meta MetaExpr
// Stream is the kind of stream (none, payload, result, or both)
// the method defines.
Stream StreamKind
// StreamingPayload is the payload sent across the stream.
StreamingPayload *AttributeExpr
}
)
const (
// NoStreamKind represents no payload or result stream in method.
NoStreamKind StreamKind = iota + 1
// ClientStreamKind represents client sends a streaming payload to
// method.
ClientStreamKind
// ServerStreamKind represents server sends a streaming result from
// method.
ServerStreamKind
// BidirectionalStreamKind represents client and server sending payload
// and result respectively via a stream.
BidirectionalStreamKind
)
// Error returns the error with the given name. It looks up recursively in the
// endpoint then the service and finally the root expression.
func (m *MethodExpr) Error(name string) *ErrorExpr {
for _, err := range m.Errors {
if err.Name == name {
return err
}
}
return m.Service.Error(name)
}
// EvalName returns the generic expression name used in error messages.
func (m *MethodExpr) EvalName() string {
var prefix, suffix string
if m.Name != "" {
suffix = fmt.Sprintf("method %#v", m.Name)
} else {
suffix = "unnamed method"
}
if m.Service != nil {
prefix = m.Service.EvalName() + " "
}
return prefix + suffix
}
// Prepare makes sure the payload and result types are initialized (to the Empty
// type if nil).
func (m *MethodExpr) Prepare() {
if m.Payload == nil {
m.Payload = &AttributeExpr{Type: Empty}
}
if m.StreamingPayload == nil {
m.StreamingPayload = &AttributeExpr{Type: Empty}
}
if m.Result == nil {
m.Result = &AttributeExpr{Type: Empty}
}
}
// Validate validates the method payloads, results, and errors (if any).
func (m *MethodExpr) Validate() error {
verr := new(eval.ValidationErrors)
verr.Merge(m.Payload.Validate("payload", m))
// validate security scheme requirements
var requirements []*SecurityExpr
if len(m.Requirements) > 0 {
requirements = m.Requirements
} else if len(m.Service.Requirements) > 0 {
requirements = m.Service.Requirements
}
var (
hasBasicAuth bool
hasAPIKey bool
hasJWT bool
hasOAuth bool
)
for _, r := range requirements {
for _, s := range r.Schemes {
verr.Merge(s.Validate())
switch s.Kind {
case BasicAuthKind:
hasBasicAuth = true
if !hasTag(m.Payload, "security:username") {
verr.Add(m, "payload of method %q of service %q does not define a username attribute, use Username to define one", m.Name, m.Service.Name)
}
if !hasTag(m.Payload, "security:password") {
verr.Add(m, "payload of method %q of service %q does not define a password attribute, use Password to define one", m.Name, m.Service.Name)
}
case APIKeyKind:
hasAPIKey = true
if !hasTag(m.Payload, "security:apikey:"+s.SchemeName) {
verr.Add(m, "payload of method %q of service %q does not define an API key attribute, use APIKey to define one", m.Name, m.Service.Name)
}
case JWTKind:
hasJWT = true
if !hasTag(m.Payload, "security:token") {
verr.Add(m, "payload of method %q of service %q does not define a JWT attribute, use Token to define one", m.Name, m.Service.Name)
}
case OAuth2Kind:
hasOAuth = true
if !hasTag(m.Payload, "security:accesstoken") {
verr.Add(m, "payload of method %q of service %q does not define a OAuth2 access token attribute, use AccessToken to define one", m.Name, m.Service.Name)
}
}
}
for _, scope := range r.Scopes {
found := false
for _, s := range r.Schemes {
if s.Kind == BasicAuthKind || s.Kind == APIKeyKind || s.Kind == OAuth2Kind || s.Kind == JWTKind {
for _, se := range s.Scopes {
if se.Name == scope {
found = true
break
}
}
}
}
if !found {
verr.Add(m, "security scope %q not found in any of the security schemes.", scope)
}
}
}
if !hasBasicAuth {
if hasTag(m.Payload, "security:username") {
verr.Add(m, "payload of method %q of service %q defines a username attribute, but no basic auth security scheme exist", m.Name, m.Service.Name)
}
if hasTag(m.Payload, "security:password") {
verr.Add(m, "payload of method %q of service %q defines a password attribute, but no basic auth security scheme exist", m.Name, m.Service.Name)
}
}
if !hasAPIKey {
if hasTagPrefix(m.Payload, "security:apikey") {
verr.Add(m, "payload of method %q of service %q defines an API key attribute, but no APIKey security scheme exist", m.Name, m.Service.Name)
}
}
if !hasJWT {
if hasTag(m.Payload, "security:token") {
verr.Add(m, "payload of method %q of service %q defines a JWT token attribute, but no JWT auth security scheme exist", m.Name, m.Service.Name)
}
}
if !hasOAuth {
if hasTag(m.Payload, "security:accesstoken") {
verr.Add(m, "payload of method %q of service %q defines a OAuth2 access token attribute, but no OAuth2 security scheme exist", m.Name, m.Service.Name)
}
}
if m.StreamingPayload.Type != Empty {
verr.Merge(m.StreamingPayload.Validate("streaming_payload", m))
}
if m.Result.Type != Empty {
verr.Merge(m.Result.Validate("result", m))
}
for i, e := range m.Errors {
if err := e.Validate(); err != nil {
if verrs, ok := err.(*eval.ValidationErrors); ok {
verr.Merge(verrs)
}
}
for j, e2 := range m.Errors {
// If an object type is used to define more than one errors validate the
// presence of struct:error:name meta in the object type.
if i != j && e.Type == e2.Type && IsObject(e.Type) {
var found bool
walkAttribute(e.AttributeExpr, func(name string, att *AttributeExpr) error {
if _, ok := att.Meta["struct:error:name"]; ok {
found = true
return fmt.Errorf("struct:error:name found: stop iteration")
}
return nil
})
if !found {
verr.Add(e, "type %q is used to define multiple errors and must identify the attribute containing error name. Use Meta with the key 'struct:error:name' on the error name attribute", e.AttributeExpr.Type.Name())
break
}
}
}
}
return verr
}
// hasTag is a helper function that traverses the given attribute and all its
// bases recursively looking for an attribute with the given tag meta. This
// recursion is only needed for attributes that have not been finalized yet.
func hasTag(p *AttributeExpr, tag string) bool {
if p.HasTag(tag) {
return true
}
for _, base := range p.Bases {
ut, ok := base.(UserType)
if !ok {
continue
}
if hasTag(ut.Attribute(), tag) {
return true
}
}
if ut, ok := p.Type.(UserType); ok {
return hasTag(ut.Attribute(), tag)
}
return false
}
// hasTag is a helper function that traverses the given attribute and all its
// bases recursively looking for an attribute with the given tag meta prefix. This
// recursion is only needed for attributes that have not been finalized yet.
func hasTagPrefix(p *AttributeExpr, prefix string) bool {
if p.HasTagPrefix(prefix) {
return true
}
for _, base := range p.Bases {
ut, ok := base.(UserType)
if !ok {
continue
}
if hasTagPrefix(ut.Attribute(), prefix) {
return true
}
}
if ut, ok := p.Type.(UserType); ok {
return hasTagPrefix(ut.Attribute(), prefix)
}
return false
}
// Finalize makes sure the method payload and result types are set. It also
// projects the result if it is a result type and a view is explicitly set in
// the design or a result type having at most one view.
func (m *MethodExpr) Finalize() {
if m.Payload == nil {
m.Payload = &AttributeExpr{Type: Empty}
} else {
m.Payload.Finalize()
}
if m.StreamingPayload == nil {
m.StreamingPayload = &AttributeExpr{Type: Empty}
} else {
m.StreamingPayload.Finalize()
}
if m.Result == nil {
m.Result = &AttributeExpr{Type: Empty}
} else {
m.Result.Finalize()
if rt, ok := m.Result.Type.(*ResultTypeExpr); ok {
rt.Finalize()
}
}
for _, e := range m.Errors {
e.Finalize()
}
// Inherit security requirements
noreq := false
for _, r := range m.Requirements {
// Handle special case of no security
for _, s := range r.Schemes {
if s.Kind == NoKind {
noreq = true
break
}
}
if noreq {
break
}
}
if noreq {
m.Requirements = nil
} else if len(m.Requirements) == 0 && len(m.Service.Requirements) > 0 {
m.Requirements = copyReqs(m.Service.Requirements)
}
}
// IsStreaming determines whether the method streams payload or result.
func (m *MethodExpr) IsStreaming() bool {
return m.IsPayloadStreaming() || m.IsResultStreaming()
}
// IsPayloadStreaming determines whether the method streams payload.
func (m *MethodExpr) IsPayloadStreaming() bool {
return m.Stream == ClientStreamKind || m.Stream == BidirectionalStreamKind
}
// IsResultStreaming determines whether the method streams payload.
func (m *MethodExpr) IsResultStreaming() bool {
return m.Stream == ServerStreamKind || m.Stream == BidirectionalStreamKind
}
// helper function that duplicates just enough of a security expression so that
// its scheme names can be overridden without affecting the original.
func copyReqs(reqs []*SecurityExpr) []*SecurityExpr {
reqs2 := make([]*SecurityExpr, len(reqs))
for i, req := range reqs {
req2 := &SecurityExpr{Scopes: req.Scopes}
schs := make([]*SchemeExpr, len(req.Schemes))
for j, sch := range req.Schemes {
schs[j] = &SchemeExpr{
Kind: sch.Kind,
SchemeName: sch.SchemeName,
Description: sch.Description,
In: sch.In,
Name: sch.Name,
Scopes: sch.Scopes,
Flows: sch.Flows,
Meta: sch.Meta,
}
}
req2.Schemes = schs
reqs2[i] = req2
}
return reqs2
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。