~repos /gromer

#golang#htmx#ssr

git clone https://pyrossh.dev/repos/gromer.git

gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.


24b34a7c Peter John

4 years ago
add validation errors
Files changed (5) hide show
  1. go.mod +2 -0
  2. go.sum +18 -0
  3. hooks_test.go +7 -5
  4. html_test.go +3 -2
  5. http.go +24 -3
go.mod CHANGED
@@ -8,9 +8,11 @@ require (
8
8
  github.com/bradleyjkemp/cupaloy v2.3.0+incompatible
9
9
  github.com/fatih/color v1.13.0
10
10
  github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf
11
+ github.com/go-playground/validator/v10 v10.9.0 // indirect
11
12
  github.com/gobuffalo/velvet v0.0.0-20170320144106-d97471bf5d8f
12
13
  github.com/google/uuid v1.3.0
13
14
  github.com/gorilla/mux v1.8.0
15
+ github.com/iancoleman/strcase v0.2.0 // indirect
14
16
  github.com/lib/pq v1.10.4
15
17
  github.com/markbates/inflect v1.0.4
16
18
  github.com/microcosm-cc/bluemonday v1.0.15 // indirect
go.sum CHANGED
@@ -136,6 +136,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht
136
136
  github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
137
137
  github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
138
138
  github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
139
+ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
139
140
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
140
141
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
141
142
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -168,8 +169,14 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
168
169
  github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
169
170
  github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
170
171
  github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
172
+ github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
173
+ github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
171
174
  github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
175
+ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
176
+ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
172
177
  github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
178
+ github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
179
+ github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
173
180
  github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
174
181
  github.com/gobuffalo/envy v1.6.5 h1:X3is06x7v0nW2xiy2yFbbIjwHz57CD6z6MkvqULTCm8=
175
182
  github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
@@ -273,6 +280,8 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
273
280
  github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
274
281
  github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
275
282
  github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
283
+ github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
284
+ github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
276
285
  github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
277
286
  github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
278
287
  github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -289,10 +298,14 @@ github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
289
298
  github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
290
299
  github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
291
300
  github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
301
+ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
292
302
  github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
293
303
  github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
294
304
  github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
305
+ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
295
306
  github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
307
+ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
308
+ github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
296
309
  github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
297
310
  github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
298
311
  github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
@@ -311,6 +324,7 @@ github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
311
324
  github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
312
325
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
313
326
  github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
327
+ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
314
328
  github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
315
329
  github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
316
330
  github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -319,6 +333,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
319
333
  github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
320
334
  github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
321
335
  github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
336
+ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
337
+ github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
322
338
  github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
323
339
  github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
324
340
  github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
@@ -395,6 +411,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
395
411
  golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
396
412
  golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
397
413
  golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
414
+ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
415
+ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
398
416
  golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
399
417
  golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
400
418
  golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
hooks_test.go CHANGED
@@ -1,6 +1,7 @@
1
1
  package gromer
2
2
 
3
3
  import (
4
+ "context"
4
5
  "testing"
5
6
 
6
7
  . "github.com/franela/goblin"
@@ -9,13 +10,14 @@ import (
9
10
  func TestHooks(t *testing.T) {
10
11
  g := Goblin(t)
11
12
  g.Describe("useState", func() {
12
- ctx := &Context{index: 0, datas: []interface{}{}}
13
+ ctx := WithState(context.Background())
14
+ stateCtx := getState(ctx)
13
15
  getValue, setValue := UseState(ctx, 12)
14
16
 
15
17
  g.It("should be initialized ", func() {
16
- g.Assert(1).Equal(ctx.index)
18
+ g.Assert(1).Equal(stateCtx.index)
17
- g.Assert(1).Equal(len(ctx.datas))
19
+ g.Assert(1).Equal(len(stateCtx.datas))
18
- g.Assert(ctx.datas[0]).Equal(12)
20
+ g.Assert(stateCtx.datas[0]).Equal(12)
19
21
  })
20
22
 
21
23
  g.It("should get value ", func() {
@@ -24,7 +26,7 @@ func TestHooks(t *testing.T) {
24
26
 
25
27
  g.It("should set value", func() {
26
28
  setValue(15)
27
- g.Assert(ctx.datas[0]).Equal(15)
29
+ g.Assert(stateCtx.datas[0]).Equal(15)
28
30
  g.Assert(getValue()).Equal(15)
29
31
  })
30
32
  })
html_test.go CHANGED
@@ -2,6 +2,7 @@ package gromer
2
2
 
3
3
  import (
4
4
  "bytes"
5
+ "context"
5
6
  "strconv"
6
7
  "testing"
7
8
 
@@ -27,7 +28,7 @@ func Col(uis ...interface{}) *Element {
27
28
  return NewElement("div", false, append([]interface{}{Css("flex flex-col justify-center items-center")}, uis...)...)
28
29
  }
29
30
 
30
- func Counter(c *Context, start int) *Element {
31
+ func Counter(c context.Context, start int) *Element {
31
32
  count, setCount := UseState(c, start)
32
33
  increment := func() {
33
34
  setCount(count().(int) + 1)
@@ -80,7 +81,7 @@ func TestHtml(t *testing.T) {
80
81
  g := Goblin(t)
81
82
  g.Describe("Html", func() {
82
83
  g.It("should match snapshot", func() {
83
- ctx := &Context{index: 0, datas: []interface{}{}}
84
+ ctx := WithState(context.Background())
84
85
  b := bytes.NewBuffer(nil)
85
86
  p := Html(
86
87
  Head(
http.go CHANGED
@@ -10,7 +10,9 @@ import (
10
10
  "strings"
11
11
 
12
12
  "github.com/fatih/color"
13
+ "github.com/go-playground/validator/v10"
13
14
  "github.com/gorilla/mux"
15
+ "github.com/iancoleman/strcase"
14
16
  "github.com/rs/zerolog"
15
17
  "github.com/rs/zerolog/log"
16
18
  )
@@ -21,11 +23,30 @@ func init() {
21
23
  }
22
24
 
23
25
  func RespondError(w http.ResponseWriter, status int, err error) {
24
- w.WriteHeader(status)
25
26
  w.Header().Set("Content-Type", "application/json")
27
+ w.WriteHeader(status) // always write status last
26
- data, _ := json.Marshal(map[string]string{
28
+ merror := map[string]interface{}{
27
29
  "error": err.Error(),
28
- })
30
+ }
31
+ validationErrors, ok := err.(validator.ValidationErrors)
32
+ if ok {
33
+ emap := map[string]string{}
34
+ for _, e := range validationErrors {
35
+ parts := strings.Split(e.StructNamespace(), ".")
36
+ lowerParts := []string{}
37
+ for _, p := range parts[1:] {
38
+ lowerParts = append(lowerParts, strcase.ToLowerCamel(p))
39
+ }
40
+ k := strings.Join(lowerParts, ".")
41
+ if e.Tag() == "required" {
42
+ emap[k] = "is required"
43
+ } else {
44
+ emap[k] = e.Error()
45
+ }
46
+ }
47
+ merror["error"] = emap
48
+ }
49
+ data, _ := json.Marshal(merror)
29
50
  w.Write(data)
30
51
  }
31
52