Skip to content

Commit 7d95fa4

Browse files
committed
test: added Validator middleware powered by reflection
1 parent 5a3474a commit 7d95fa4

File tree

8 files changed

+161
-6
lines changed

8 files changed

+161
-6
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ require (
66
github.com/ralvarezdev/go-flags v0.3.1
77
github.com/ralvarezdev/go-jwt v0.4.8
88
github.com/ralvarezdev/go-logger v0.4.5
9-
github.com/ralvarezdev/go-validator v0.5.21
9+
github.com/ralvarezdev/go-reflect v0.2.1
10+
github.com/ralvarezdev/go-validator v0.5.22
1011
)
1112

1213
require (
1314
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
14-
github.com/ralvarezdev/go-reflect v0.1.0 // indirect
1515
github.com/ralvarezdev/go-strings v0.1.6 // indirect
1616
golang.org/x/crypto v0.32.0 // indirect
1717
)

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ github.com/ralvarezdev/go-jwt v0.4.8 h1:ugZ0Lyfen7QzmgweLnJynya3yih8rPev48Xjj7HY
66
github.com/ralvarezdev/go-jwt v0.4.8/go.mod h1:RGGbn72uT5av5Hlo50H4xSXg6chmnpecl/a2yGAFNzQ=
77
github.com/ralvarezdev/go-logger v0.4.5 h1:Lw7DdZUb4YSQDA7J9nv79soojw1eFHVVzO8wdE9d+Qg=
88
github.com/ralvarezdev/go-logger v0.4.5/go.mod h1:vq47onxpED19/o3dh5/YbBKK0eZhqJENPgACYkqNNi8=
9-
github.com/ralvarezdev/go-reflect v0.1.0 h1:q0CypQURgOgxkLHilYVFazYi3nlSxNdkjSoYpuhFYOA=
10-
github.com/ralvarezdev/go-reflect v0.1.0/go.mod h1:jv3EqQfUixWtNeJd/Rnzf0IDcYZ1z3GApRdAGQHdHZQ=
9+
github.com/ralvarezdev/go-reflect v0.2.1 h1:Q200FruGvc8INRRpnmvK+iRKTnCslRAWnwGAj1fXMak=
10+
github.com/ralvarezdev/go-reflect v0.2.1/go.mod h1:jv3EqQfUixWtNeJd/Rnzf0IDcYZ1z3GApRdAGQHdHZQ=
1111
github.com/ralvarezdev/go-strings v0.1.6 h1:NWI+XCipWaOo0vhSNpZz+7Eb4igk/GXD5RaFsk4ZPqY=
1212
github.com/ralvarezdev/go-strings v0.1.6/go.mod h1:8sFOqmPJpqzS7bTjf91EzUCITnwpmkfifwY80GxV5r8=
13-
github.com/ralvarezdev/go-validator v0.5.21 h1:Y2ndLcDUlgjHNG6pVSu4poE30OvWAGnKdtU+Gu9bBPg=
14-
github.com/ralvarezdev/go-validator v0.5.21/go.mod h1:q24kfA3gLlcYkMo/W6Ip7JEpWtZGEJBN6Rvn0N1IOF0=
13+
github.com/ralvarezdev/go-validator v0.5.22 h1:mjvWKwhQyqQ6FwJUWIPfsywjOK0nMYf7HKDYAojh1xo=
14+
github.com/ralvarezdev/go-validator v0.5.22/go.mod h1:q24kfA3gLlcYkMo/W6Ip7JEpWtZGEJBN6Rvn0N1IOF0=
1515
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
1616
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=

http/context/constants.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package context
2+
3+
const (
4+
// CtxBodyKey is the context key for the body
5+
CtxBodyKey = "body"
6+
)

http/context/context.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package context
2+
3+
import (
4+
"context"
5+
"net/http"
6+
)
7+
8+
// SetCtxBody sets the body in the context
9+
func SetCtxBody(r *http.Request, body interface{}) *http.Request {
10+
ctx := context.WithValue(r.Context(), CtxBodyKey, body)
11+
return r.WithContext(ctx)
12+
}
13+
14+
// GetCtxBody tries to get the body from the context
15+
func GetCtxBody(r *http.Request) (interface{}, error) {
16+
// Get the token claims from the context
17+
value := r.Context().Value(CtxBodyKey)
18+
if value == nil {
19+
return nil, ErrMissingBodyInContext
20+
}
21+
return value, nil
22+
}

http/context/errors.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package context
2+
3+
import (
4+
"errors"
5+
)
6+
7+
var (
8+
ErrMissingBodyInContext = errors.New("missing body in context")
9+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package validator
2+
3+
import (
4+
"errors"
5+
)
6+
7+
var (
8+
ErrNilValidateFn = errors.New("validate function is nil")
9+
ErrInvalidValidateFn = errors.New("validate function is invalid")
10+
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package validator
2+
3+
import (
4+
"context"
5+
gonethttpctx "github.com/ralvarezdev/go-net/http/context"
6+
gonethttphandler "github.com/ralvarezdev/go-net/http/handler"
7+
goreflect "github.com/ralvarezdev/go-reflect"
8+
govalidatorstructmapper "github.com/ralvarezdev/go-validator/struct/mapper"
9+
"net/http"
10+
)
11+
12+
// Middleware struct
13+
type Middleware struct {
14+
handler gonethttphandler.Handler
15+
generator govalidatorstructmapper.Generator
16+
}
17+
18+
// NewMiddleware creates a new Middleware instance
19+
func NewMiddleware(
20+
handler gonethttphandler.Handler,
21+
generator govalidatorstructmapper.Generator,
22+
) (*Middleware, error) {
23+
// Check if the handler or the generator is nil
24+
if handler == nil {
25+
return nil, gonethttphandler.ErrNilHandler
26+
}
27+
if generator == nil {
28+
return nil, govalidatorstructmapper.ErrNilGenerator
29+
}
30+
31+
return &Middleware{
32+
handler: handler,
33+
}, nil
34+
}
35+
36+
// Validate validates the request body and stores it in the context
37+
func (m *Middleware) Validate(
38+
body interface{},
39+
createValidateFn interface{},
40+
) func(next http.Handler) http.Handler {
41+
// Get the type of the body
42+
bodyType := goreflect.GetTypeOf(body)
43+
44+
// Create the mapper
45+
mapper, err := m.generator.NewMapper(body)
46+
if err != nil {
47+
panic(err)
48+
}
49+
50+
return func(next http.Handler) http.Handler {
51+
return http.HandlerFunc(
52+
func(w http.ResponseWriter, r *http.Request) {
53+
// Get a new instance of the body
54+
dest := goreflect.NewInstanceFromType(bodyType)
55+
56+
// Get the validate function
57+
results, err := goreflect.CallFunction(
58+
createValidateFn,
59+
dest,
60+
mapper,
61+
)
62+
if err != nil {
63+
panic(err)
64+
}
65+
validateFn := results[0]
66+
67+
// Parse the validate function
68+
if validateFn == nil {
69+
panic(ErrNilValidateFn)
70+
}
71+
parsedValidateFn, ok := validateFn.(func() (interface{}, error))
72+
if !ok {
73+
panic(ErrInvalidValidateFn)
74+
}
75+
76+
// Decode the request body
77+
if !m.handler.Parse(
78+
w,
79+
r,
80+
dest,
81+
parsedValidateFn,
82+
) {
83+
return
84+
}
85+
86+
// Store the validated body in the context
87+
ctx := context.WithValue(
88+
r.Context(),
89+
gonethttpctx.CtxBodyKey,
90+
dest,
91+
)
92+
next.ServeHTTP(w, r.WithContext(ctx))
93+
},
94+
)
95+
}
96+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package validator
2+
3+
import (
4+
"net/http"
5+
)
6+
7+
// Validator interface
8+
type Validator interface {
9+
Validate(
10+
createValidateFn func() (interface{}, func() (interface{}, error)),
11+
) func(next http.Handler) http.Handler
12+
}

0 commit comments

Comments
 (0)