forked from srfrog/go-relax
-
Notifications
You must be signed in to change notification settings - Fork 0
/
encoder.go
111 lines (94 loc) · 3.48 KB
/
encoder.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
// Copyright 2014 Codehack.com All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package relax
import (
"encoding/json"
"errors"
"io"
)
// ErrBodyTooLarge is returned by Encoder.Decode when the read length exceeds the
// maximum size set for payload.
var ErrBodyTooLarge = errors.New("encoder: Body too large")
/*
Encoder objects provide new data encoding formats.
Once a request enters service context, all responses are encoded according to the
assigned encoder. Relax includes support for JSON encoding. Other types of encoding
can be added by implementing the Encoder interface.
*/
type Encoder interface {
// Accept returns the media type used in HTTP Accept header.
Accept() string
// ContentType returns the media type, and optionally character set,
// for decoding used in Content-Type header.
ContentType() string
// Encode function encodes the value of an interface and writes it to an
// io.Writer stream (usually an http.ResponseWriter object).
Encode(io.Writer, interface{}) error
// Decode function decodes input from an io.Reader (usually Request.Body) and
// tries to save it to an interface variable.
Decode(io.Reader, interface{}) error
}
// EncoderJSON implements the Encoder interface. It encode/decodes JSON data.
type EncoderJSON struct {
// MaxBodySize is the maximum size (in bytes) of JSON payload to read.
// Defaults to 2097152 (2MB)
MaxBodySize int64
// Indented indicates whether or not to output indented JSON.
// Note: indented JSON is slower to encode.
// Defaults to false
Indented bool
// AcceptHeader is the media type used in Accept HTTP header.
// Defaults to "application/json"
AcceptHeader string
// ContentTypeHeader is the media type used in Content-Type HTTP header
// Defaults to "application/json;charset=utf-8"
ContentTypeHeader string
}
// NewEncoderJSON returns an EncoderJSON object. This function will initiallize
// the object with sane defaults, for use with Service.encoders.
// Returns the new EncoderJSON object.
func NewEncoderJSON() *EncoderJSON {
return &EncoderJSON{
MaxBodySize: 2097152, // 2MB
Indented: false,
AcceptHeader: "application/json",
ContentTypeHeader: "application/json;charset=utf-8",
}
}
// Accept returns the media type for JSON content, used in Accept header.
func (e *EncoderJSON) Accept() string {
return e.AcceptHeader
}
// ContentType returns the media type for JSON content, used in the
// Content-Type header.
func (e *EncoderJSON) ContentType() string {
return e.ContentTypeHeader
}
// Encode will try to encode the value of v into JSON. If EncoderJSON.Indented
// is true, then the JSON will be indented with tabs.
// Returns nil on success, error on failure.
func (e *EncoderJSON) Encode(writer io.Writer, v interface{}) error {
if e.Indented {
// indented is much slower...
b, err := json.MarshalIndent(v, "", "\t")
if err != nil {
return err
}
_, err = writer.Write(b)
return err
}
return json.NewEncoder(writer).Encode(v)
}
// Decode reads a JSON payload (usually from Request.Body) and tries to
// save it to a variable v. If the payload is too large, with maximum
// EncoderJSON.MaxBodySize, it will fail with error ErrBodyTooLarge
// Returns nil on success and error on failure.
func (e *EncoderJSON) Decode(reader io.Reader, v interface{}) error {
r := &io.LimitedReader{reader, e.MaxBodySize}
err := json.NewDecoder(r).Decode(v)
if err != nil && r.N == 0 {
return ErrBodyTooLarge
}
return err
}