-
Notifications
You must be signed in to change notification settings - Fork 1
/
htadaptor.go
123 lines (103 loc) · 3.17 KB
/
htadaptor.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
/*
Package htadaptor provides generic domain logic adaptors for HTTP handlers. Adaptors come in three flavors:
1. UnaryFunc: func(context, inputStruct) (outputStruct, error)
2. NullaryFunc: func(context) (outputStruct, error)
3. VoidFunc: func(context, inputStruct) error
Validation errors are decorated with the correct [http.StatusUnprocessableEntity] status code.
*/
package htadaptor
import (
"context"
"encoding/json"
"html/template"
"net/http"
)
// func New(withOptions ...Option) (func(any) (http.Handler, error), error) {
// return func(domainCall any) (http.Handler, error) {
// funcType, err := Detect(domainCall)
// if err != nil {
// return nil, err
// }
// switch funcType {
// case FuncTypeUnary:
// return &UnaryFuncAdaptor{
// domainCall: domainCall,
// decoder: o.Decoder,
// encoder: o.Encoder,
// errorHandler: o.ErrorHandler,
// logger: o.Logger,
// }, nil
// default:
// return nil, fmt.Errorf("unknown domain function type: %d", funcType)
// }
// }, nil
// }
// Validatable constrains a domain request. Validation errors are
// wrapped as [InvalidRequestError] by the adapter. [context.Context]
// is essential for passing locale information that can be
// retrieved using [LanguageFromContext] inside the validation
// method and other similar uses.
//
// DEPRECATED: will be removed from 1.0 release.
type Validatable interface {
Validate(context.Context) error
}
/*
Used this neat trick before to enforce pointer type on Validatable,
which also made it possible to pass to a Decoder by reference.
type Validatable[T any] interface {
*T
Validate(context.Context) error
}
*/
type Decoder interface {
Decode(any, *http.Request) error
}
type DecoderFunc func(any, *http.Request) error
func (f DecoderFunc) Decoder(v any, r *http.Request) error {
return f(v, r)
}
type Encoder interface {
Encode(http.ResponseWriter, *http.Request, int, any) error
}
type EncoderFunc func(http.ResponseWriter, *http.Request, int, any) error
func (f EncoderFunc) Encode(w http.ResponseWriter, r *http.Request, code int, v any) error {
return f(w, r, code, v)
}
var JSONEncoder = EncoderFunc(
func(w http.ResponseWriter, r *http.Request, code int, v any) error {
w.Header().Set("content-type", "application/json")
w.WriteHeader(code)
return json.NewEncoder(w).Encode(v)
},
)
type templateEncoder struct {
*template.Template
}
func (e *templateEncoder) Encode(w http.ResponseWriter, r *http.Request, code int, v any) error {
w.Header().Set("content-type", "text/html; charset=utf-8")
w.WriteHeader(code)
return e.Template.Execute(w, v)
}
func NewTemplateEncoder(t *template.Template) Encoder {
return &templateEncoder{t}
}
// Must panics if an [http.Handler] was created with an error.
func Must(h http.Handler, err error) http.Handler {
if err != nil {
panic(err)
}
return h
}
// Middleware modifies an [http.Handler].
type Middleware func(http.Handler) http.Handler
// Apply wraps an [http.Handler] into [Middleware] in reverse order.
func ApplyMiddleware(h http.Handler, mws ...Middleware) http.Handler {
if h == nil {
panic("cannot use <nil> handler")
}
for i := len(mws) - 1; i >= 0; i-- {
h = mws[i](h)
}
return h
}