11<p align =" center " >
2- <img src =" ./docs/assets/logo.png " width =" 300 " alt =" goforj/collection logo " >
2+ <img src =" ./docs/assets/logo.png " width =" 300 " alt =" goforj/web logo " >
33</p >
44
55<p align =" center " >
@@ -52,24 +52,22 @@ import (
5252)
5353
5454func main () {
55- // Pick an adapter that satisfies the app-facing web.Router contract.
5655 adapter := echoweb.New ()
5756 router := adapter.Router ()
5857
59- // Attach common app middleware once near the top of the stack.
6058 router.Use (
6159 webmiddleware.Recover (),
6260 webmiddleware.RequestID (),
6361 )
6462
65- // Register a basic health route for uptime checks and local smoke tests.
6663 router.GET (" /healthz" , func (c web.Context ) error {
67- return c.Text (http.StatusOK , " ok" )
64+ // GET /healthz -> 200 ok
65+ return c.Text (200 , " ok" )
6866 })
6967
70- // Register an actual application route that returns JSON.
7168 router.GET (" /users/:id" , func (c web.Context ) error {
72- return c.JSON (http.StatusOK , map [string ]any{
69+ // GET /users/42 -> 200 {"id":"42","name":"user-42"}
70+ return c.JSON (200 , map [string ]any{
7371 " id" : c.Param (" id" ),
7472 " name" : fmt.Sprintf (" user-%s " , c.Param (" id" )),
7573 })
@@ -85,81 +83,106 @@ func main() {
8583### Route Groups
8684
8785``` go
86+ adapter := echoweb.New ()
87+ router := adapter.Router ()
88+
8889routes := []web.Route {
8990 web.NewRoute (http.MethodGet , " /healthz" , func (c web.Context ) error {
91+ // GET /api/healthz -> 204
9092 return c.NoContent (http.StatusOK )
9193 }),
9294 web.NewRoute (http.MethodGet , " /users" , func (c web.Context ) error {
95+ // GET /api/users -> 200 [{"id":1}]
9396 return c.JSON (http.StatusOK , []map [string ]any{{" id" : 1 }})
9497 }),
9598}
9699
97100group := web.NewRouteGroup (" /api" , routes)
98101
99- adapter := echoweb.New ()
100- _ = web.RegisterRoutes (adapter.Router (), []web.RouteGroup {group})
102+ if err := web.RegisterRoutes (router, []web.RouteGroup {group}); err != nil {
103+ panic (err)
104+ }
101105```
102106
103- ### Compose Middleware Around A Handler
107+ ### Use Middleware
104108
105109``` go
106- requestID := webmiddleware.RequestID ()
107- recoverer := webmiddleware.Recover ()
108- limiter := webmiddleware.RateLimiter (
109- webmiddleware.NewRateLimiterMemoryStore (rate.Every (time.Second )),
110+ adapter := echoweb.New ()
111+ router := adapter.Router ()
112+
113+ store := webmiddleware.NewRateLimiterMemoryStore (rate.Every (time.Second ))
114+
115+ router.Use (
116+ webmiddleware.Recover (),
117+ webmiddleware.RequestID (),
118+ webmiddleware.RateLimiter (store),
110119)
111120
112- handler := web.Handler (func (c web.Context ) error {
113- return c.Text (http.StatusOK , " ok" )
121+ router.GET (" /api/messages" , func (c web.Context ) error {
122+ // GET /api/messages -> 200 [{"id":1,"subject":"Welcome"}]
123+ // Requests over the configured rate limit return 429.
124+ return c.JSON (200 , []map [string ]any{
125+ {" id" : 1 , " subject" : " Welcome" },
126+ })
114127})
115-
116- wrapped := requestID (recoverer (limiter (handler)))
117- _ = wrapped
118128```
119129
120- ### Test A Handler End To End
130+ ### Test A Route
121131
122132``` go
123- req := httptest.NewRequest (http.MethodGet , " /healthz" , nil )
124- ctx := webtest.NewContext (req, nil , " /healthz" , nil )
133+ func TestHealthRoute (t *testing .T ) {
134+ adapter := echoweb.New ()
135+ router := adapter.Router ()
125136
126- handler := webmiddleware. RequestID ()( func (c web.Context ) error {
127- return c.Text (http. StatusOK , " ok" )
128- })
137+ router. GET ( " /healthz " , func (c web.Context ) error {
138+ return c.Text (200 , " ok" )
139+ })
129140
130- _ = handler (ctx)
141+ req := httptest.NewRequest (http.MethodGet , " /healthz" , nil )
142+ rec := httptest.NewRecorder ()
131143
132- fmt.Println (ctx.StatusCode ())
133- fmt.Println (ctx.Response ().Header ().Get (" X-Request-ID" ) != " " )
134- fmt.Println (ctx.ResponseWriter ().(*httptest.ResponseRecorder ).Body .String ())
135- // 200
136- // true
137- // ok
144+ adapter.ServeHTTP (rec, req)
145+
146+ if rec.Code != 200 {
147+ t.Fatalf (" expected 200, got %d " , rec.Code )
148+ }
149+ if strings.TrimSpace (rec.Body .String ()) != " ok" {
150+ t.Fatalf (" expected ok, got %q " , rec.Body .String ())
151+ }
152+ // rec.Code -> 200
153+ // rec.Body -> ok
154+ }
138155```
139156
140157### Expose Prometheus Metrics
141158
142159``` go
143160adapter := echoweb.New ()
144- metrics , _ := webprometheus. New (webprometheus. Config {Namespace: " app " } )
161+ router := adapter. Router ( )
145162
146- adapter.Router ().Use (metrics.Middleware ())
147- adapter.Router ().GET (" /users" , func (c web.Context ) error {
163+ metrics := webprometheus.MustNew (webprometheus.Config {Namespace: " app" })
164+
165+ router.Use (metrics.Middleware ())
166+
167+ router.GET (" /users" , func (c web.Context ) error {
168+ // GET /users -> 204
148169 return c.NoContent (http.StatusOK )
149170})
150- adapter.Router ().GET (" /metrics" , metrics.Handler ())
171+ router.GET (" /metrics" , metrics.Handler ())
172+ // GET /metrics -> Prometheus text exposition
151173```
152174
153175### Generate A Route Index
154176
155177``` go
156- manifest , err := webindex.Run (context.Background (), webindex.IndexOptions {
178+ _ , err := webindex.Run (context.Background (), webindex.IndexOptions {
157179 Root : " ." ,
158180 OutPath : " webindex.json" ,
159181})
160-
161- fmt.Println (err == nil , manifest.Version != " " )
162- // true true
182+ if err != nil {
183+ panic (err)
184+ }
185+ // Writes webindex.json.
163186```
164187
165188## Packages
0 commit comments