github.com/vcilabs/webrpc@v0.5.2-0.20201116131534-162e27b1b33b/schema/service.go (about) 1 package schema 2 3 import ( 4 "strings" 5 6 "github.com/pkg/errors" 7 ) 8 9 type Service struct { 10 Name VarName `json:"name"` 11 Methods []*Method `json:"methods"` 12 13 Schema *WebRPCSchema `json:"-"` // denormalize/back-reference 14 } 15 16 type Method struct { 17 Name VarName `json:"name"` 18 19 StreamInput bool `json:"streamInput,omitempty"` 20 StreamOutput bool `json:"streamOutput,omitempty"` 21 Proxy bool `json:"-"` // TODO: actual implementation 22 23 Inputs []*MethodArgument `json:"inputs"` 24 Outputs []*MethodArgument `json:"outputs"` 25 26 Service *Service `json:"-"` // denormalize/back-reference 27 } 28 29 type MethodArgument struct { 30 Name VarName `json:"name"` 31 Type *VarType `json:"type"` 32 Optional bool `json:"optional"` 33 34 InputArg bool `json:"-"` // denormalize/back-reference 35 OutputArg bool `json:"-"` // denormalize/back-reference 36 } 37 38 func (s *Service) Parse(schema *WebRPCSchema) error { 39 s.Schema = schema // back-ref 40 41 // Service name 42 serviceName := string(s.Name) 43 if string(s.Name) == "" { 44 return errors.Errorf("schema error: service name cannot be empty") 45 } 46 47 // Ensure we don't have dupe service names (w/ normalization) 48 name := strings.ToLower(string(s.Name)) 49 for _, svc := range schema.Services { 50 if svc != s && name == strings.ToLower(string(svc.Name)) { 51 return errors.Errorf("schema error: duplicate service name detected in service '%s'", serviceName) 52 } 53 } 54 55 // Ensure methods is defined 56 if len(s.Methods) == 0 { 57 return errors.Errorf("schema error: methods cannot be empty for service '%s'", serviceName) 58 } 59 60 // Verify method names and ensure we don't have any duplicate method names 61 methodList := map[string]string{} 62 for _, method := range s.Methods { 63 if string(method.Name) == "" { 64 return errors.Errorf("schema error: detected empty method name in service '%s", serviceName) 65 } 66 67 methodName := string(method.Name) 68 nMethodName := strings.ToLower(methodName) 69 70 if _, ok := methodList[nMethodName]; ok { 71 return errors.Errorf("schema error: detected duplicate method name of '%s' in service '%s'", methodName, serviceName) 72 } 73 methodList[nMethodName] = methodName 74 } 75 76 // Parse+validate methods 77 for _, method := range s.Methods { 78 err := method.Parse(schema, s) 79 if err != nil { 80 return err 81 } 82 } 83 84 return nil 85 } 86 87 func (m *Method) Parse(schema *WebRPCSchema, service *Service) error { 88 if service == nil { 89 return errors.Errorf("parse error, service arg cannot be nil") 90 } 91 m.Service = service // back-ref 92 serviceName := string(service.Name) 93 94 // Parse+validate inputs 95 for _, input := range m.Inputs { 96 input.InputArg = true // back-ref 97 if input.Name == "" { 98 return errors.Errorf("schema error: detected empty input argument name for method '%s' in service '%s'", m.Name, serviceName) 99 } 100 err := input.Type.Parse(schema) 101 if err != nil { 102 return err 103 } 104 } 105 106 // Parse+validate outputs 107 for _, output := range m.Outputs { 108 output.OutputArg = true // back-ref 109 if output.Name == "" { 110 return errors.Errorf("schema error: detected empty output name for method '%s' in service '%s'", m.Name, serviceName) 111 } 112 err := output.Type.Parse(schema) 113 if err != nil { 114 return err 115 } 116 } 117 118 // Note, we allow zero inputs and zero outputs 119 120 return nil 121 }