forked from ThalesGroup/requests
-
Notifications
You must be signed in to change notification settings - Fork 0
/
marshaling.go
138 lines (118 loc) · 4.18 KB
/
marshaling.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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package requests
import (
"encoding/json"
"encoding/xml"
"fmt"
goquery "github.com/google/go-querystring/query"
"net/url"
"strings"
)
// DefaultMarshaler is used by Requests if Requests.Marshaler is nil.
var DefaultMarshaler BodyMarshaler = &JSONMarshaler{}
// DefaultUnmarshaler is used by Requests if Requests.Unmarshaler is nil.
var DefaultUnmarshaler BodyUnmarshaler = &MultiUnmarshaler{}
// BodyMarshaler marshals structs into a []byte, and supplies a matching
// Content-Type header.
type BodyMarshaler interface {
Marshal(v interface{}) (data []byte, contentType string, err error)
}
// BodyUnmarshaler unmarshals a []byte response body into a value. It is provided
// the value of the Content-Type header from the response.
type BodyUnmarshaler interface {
Unmarshal(data []byte, contentType string, v interface{}) error
}
// MarshalFunc adapts a function to the BodyMarshaler interface.
type MarshalFunc func(v interface{}) ([]byte, string, error)
// Marshal implements the BodyMarshaler interface.
func (f MarshalFunc) Marshal(v interface{}) ([]byte, string, error) {
return f(v)
}
// UnmarshalFunc adapts a function to the BodyUnmarshaler interface.
type UnmarshalFunc func(data []byte, contentType string, v interface{}) error
// Unmarshal implements the BodyUnmarshaler interface.
func (f UnmarshalFunc) Unmarshal(data []byte, contentType string, v interface{}) error {
return f(data, contentType, v)
}
// JSONMarshaler implement BodyMarshaler and BodyUnmarshaler. It marshals values to and
// from JSON. If Indent is true, marshaled JSON will be indented.
//
// r := requests.Requests{
// Body: &JSONMarshaler{},
// }
//
type JSONMarshaler struct {
Indent bool
}
// Unmarshal implements BodyUnmarshaler.
func (m *JSONMarshaler) Unmarshal(data []byte, contentType string, v interface{}) error {
return json.Unmarshal(data, v)
}
// Marshal implements BodyMarshaler.
func (m *JSONMarshaler) Marshal(v interface{}) (data []byte, contentType string, err error) {
if m.Indent {
data, err = json.MarshalIndent(v, "", " ")
} else {
data, err = json.Marshal(v)
}
return data, ContentTypeJSON, err
}
// XMLMarshaler implements BodyMarshaler and BodyUnmarshaler. It marshals values to
// and from XML. If Indent is true, marshaled XML will be indented.
//
// r := requests.Requests{
// Marshaler: &XMLMarshaler{},
// }
//
type XMLMarshaler struct {
Indent bool
}
// Unmarshal implements BodyUnmarshaler.
func (*XMLMarshaler) Unmarshal(data []byte, contentType string, v interface{}) error {
return xml.Unmarshal(data, v)
}
// Marshal implements BodyMarshaler.
func (m *XMLMarshaler) Marshal(v interface{}) (data []byte, contentType string, err error) {
if m.Indent {
data, err = xml.MarshalIndent(v, "", " ")
} else {
data, err = xml.Marshal(v)
}
return data, ContentTypeXML, err
}
// FormMarshaler implements BodyMarshaler. It marshals values into URL-Encoded form data.
//
// The value can be either a map[string][]string, url.Values, or a struct with `url` tags.
type FormMarshaler struct{}
// Marshal implements BodyMarshaler.
func (*FormMarshaler) Marshal(v interface{}) (data []byte, contentType string, err error) {
switch t := v.(type) {
case map[string][]string:
urlV := url.Values(t)
return []byte(urlV.Encode()), ContentTypeForm, nil
case url.Values:
return []byte(t.Encode()), ContentTypeForm, nil
default:
values, err := goquery.Values(v)
if err != nil {
return nil, "", err
}
return []byte(values.Encode()), ContentTypeForm, nil
}
}
// MultiUnmarshaler implements BodyUnmarshaler. It uses the value of the Content-Type header in the
// response to choose between the JSON and XML unmarshalers. If Content-Type is something else,
// an error is returned.
type MultiUnmarshaler struct {
jsonMar JSONMarshaler
xmlMar XMLMarshaler
}
// Unmarshal implements BodyUnmarshaler.
func (m *MultiUnmarshaler) Unmarshal(data []byte, contentType string, v interface{}) error {
switch {
case strings.Contains(contentType, ContentTypeJSON):
return m.jsonMar.Unmarshal(data, contentType, v)
case strings.Contains(contentType, ContentTypeXML):
return m.xmlMar.Unmarshal(data, contentType, v)
}
return fmt.Errorf("unsupported content type: %s", contentType)
}