/
v2.go
74 lines (65 loc) · 1.9 KB
/
v2.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// Package v2 is the new Exoscale client API binding.
// Reference: https://openapi-v2.exoscale.com/
package v2
import (
"context"
"errors"
"fmt"
"reflect"
"strings"
)
type getter interface {
get(ctx context.Context, client *Client, zone, id string) (interface{}, error)
}
// validateOperationParams is a helper function that returns an error if
// fields of the struct res tagged with `req-for:"<OPERATIONS|*>"` are set
// to a nil value. Fields tagged with "req-for" MUST be of type pointer.
// The expected format for the `req-for:` tag value is a comma-separated
// list of required operations, or "*" for any operation (i.e. the field
// is always required).
func validateOperationParams(res interface{}, op string) error {
rv := reflect.ValueOf(res)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return errors.New("field must be a non-nil pointer value")
}
if op == "" {
return errors.New("no operation specified")
}
structValue := reflect.ValueOf(res).Elem()
for i := 0; i < structValue.NumField(); i++ {
structField := structValue.Type().Field(i)
reqOp, required := structField.Tag.Lookup("req-for")
if required {
if structField.Type.Kind() != reflect.Ptr {
return fmt.Errorf(
"%s.%s field is tagged with req-for but its type is not a pointer",
structValue.Type().String(),
structField.Name,
)
}
switch {
case
reqOp == op,
reqOp == "*":
if structValue.Field(i).IsNil() {
return fmt.Errorf(
"%s.%s field is required for this operation",
structValue.Type().String(),
structField.Name,
)
}
case strings.Contains(reqOp, ","):
for _, o := range strings.Split(reqOp, ",") {
if strings.TrimSpace(o) == op && structValue.Field(i).IsNil() {
return fmt.Errorf(
"%s.%s field is required for this operation",
structValue.Type().String(),
structField.Name,
)
}
}
}
}
}
return nil
}