-
Notifications
You must be signed in to change notification settings - Fork 714
/
apiutil.go
88 lines (76 loc) · 2.21 KB
/
apiutil.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package apiutil
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strconv"
"github.com/pkg/errors"
)
// DeferClose captures the error returned from closing (if an error occurs).
// This is designed to be used in a defer statement.
func DeferClose(c io.Closer, err *error) {
if cerr := c.Close(); cerr != nil && *err == nil {
*err = errors.WithStack(cerr)
}
}
// JSONError lets callers check for just one error type
type JSONError struct {
Err error
}
func (e JSONError) Error() string {
return e.Err.Error()
}
func tagJSONError(err error) error {
switch err.(type) {
case *json.SyntaxError, *json.UnmarshalTypeError:
return JSONError{err}
}
return err
}
// ReadJSON reads a JSON data from r and then closes it.
// An error due to invalid json will be returned as a JSONError
func ReadJSON(r io.ReadCloser, data interface{}) error {
var err error
defer DeferClose(r, &err)
b, err := ioutil.ReadAll(r)
if err != nil {
return errors.WithStack(err)
}
err = json.Unmarshal(b, data)
if err != nil {
return tagJSONError(err)
}
return err
}
// FieldError connects an error to a particular field
type FieldError struct {
error
field string
}
// ParseUint64VarsField connects strconv.ParseUint with request variables
// It hardcodes the base to 10 and bitsize to 64
// Any error returned will connect the requested field to the error via FieldError
func ParseUint64VarsField(vars map[string]string, varName string) (uint64, *FieldError) {
str, ok := vars[varName]
if !ok {
return 0, &FieldError{field: varName, error: fmt.Errorf("field %s not present", varName)}
}
parsed, err := strconv.ParseUint(str, 10, 64)
if err == nil {
return parsed, nil
}
return parsed, &FieldError{field: varName, error: err}
}