Skip to content

Commit 12ec806

Browse files
committed
Added Middleware and Route Groups
1 parent 98b6da2 commit 12ec806

25 files changed

+862
-481
lines changed

README.md

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,26 @@ package main
4444
import (
4545
"github.com/thinkoner/thinkgo"
4646
"fmt"
47-
"github.com/thinkoner/thinkgo/route"
47+
"github.com/thinkoner/thinkgo/router"
4848
"github.com/thinkoner/thinkgo/context"
4949
)
5050

5151
func main() {
5252
app := thinkgo.BootStrap()
53-
app.RegisterRoute(func(route *route.Route) {
53+
app.RegisterRoute(func(route *router.Route) {
5454

55-
route.Get("/", func(req *context.Request) thinkgo.Response {
55+
route.Get("/", func(req *context.Request) *context.Response {
5656
return thinkgo.Text("Hello ThinkGo !")
5757
})
5858

59-
route.Get("/ping", func(req *context.Request) thinkgo.Response {
59+
route.Get("/ping", func(req *context.Request) *context.Response {
6060
return thinkgo.Json(map[string]string{
6161
"message": "pong",
6262
})
6363
})
6464

6565
// Dependency injection
66-
route.Get("/user/{name}", func(req *context.Request, name string) thinkgo.Response {
66+
route.Get("/user/{name}", func(req *context.Request, name string) *context.Response {
6767
return thinkgo.Text(fmt.Sprintf("Hello %s !", name))
6868
})
6969
})
@@ -75,6 +75,7 @@ func main() {
7575
## Features
7676

7777
- [Routing](#routing)
78+
- [Middleware](#middleware)
7879
- [Controller](#controller)
7980
- [Request](#http-request)
8081
- [Response](#http-response)
@@ -90,8 +91,8 @@ func main() {
9091
The most basic routes accept a URI and a Closure, providing a very simple and expressive method of defining routes:
9192

9293
```go
93-
app.RegisterRoute(func(route *route.Route) {
94-
route.Get("/foo", func(req *context.Request) thinkgo.Response {
94+
app.RegisterRoute(func(route *router.Route) {
95+
route.Get("/foo", func(req *context.Request) *context.Response {
9596
return thinkgo.Text("Hello ThinkGo !")
9697
})
9798
})
@@ -121,19 +122,81 @@ route.Any("/someAny", any)
121122
Of course, sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters:
122123

123124
```go
124-
route.Get("/user/{id}", func(req *context.Request, id string) thinkgo.Response {
125+
route.Get("/user/{id}", func(req *context.Request, id string) *context.Response {
125126
return thinkgo.Text(fmt.Sprintf("User %s", id))
126127
})
127128
```
128129

129130
You may define as many route parameters as required by your route:
130131

131132
```go
132-
route.Get("/posts/{post}/comments/{comment}", func(req *context.Request, postId, commentId string) thinkgo.Response {
133+
route.Get("/posts/{post}/comments/{comment}", func(req *context.Request, postId, commentId string) *context.Response {
133134
//
134135
})
135136
```
136137

138+
#### Route Prefixes
139+
140+
The prefix method may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with `admin`:
141+
142+
```go
143+
route.Prefix("/admin").Group(func(group *router.Route) {
144+
group.Prefix("user").Group(func(group *router.Route) {
145+
// ...
146+
})
147+
group.Prefix("posts").Group(func(group *router.Route) {
148+
// ...
149+
})
150+
})
151+
```
152+
153+
## Middleware
154+
155+
Middleware provide a convenient mechanism for filtering HTTP requests entering your application. You only need to implement the `Middleware` interface.
156+
157+
```go
158+
route.Get("/foo", func(request *context.Request) *context.Response {
159+
return thinkgo.Text("Hello ThinkGo !")
160+
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
161+
if _, err := request.Input("name"); err != nil {
162+
return thinkgo.Text("Invalid parameters")
163+
}
164+
return next(request)
165+
})
166+
```
167+
168+
#### Route Groups
169+
170+
Route groups allow you to share route attributes, such as middleware or prefix, across a large number of routes without needing to define those attributes on each individual route.
171+
172+
```go
173+
route.Prefix("/admin").Group(func(group *router.Route) {
174+
group.Prefix("user").Group(func(group *router.Route) {
175+
group.Get("", func(request *context.Request) *context.Response {
176+
return thinkgo.Text("admin user !")
177+
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
178+
if _, err := request.Input("id"); err != nil {
179+
return thinkgo.Text("Invalid parameters")
180+
}
181+
return next(request)
182+
})
183+
group.Get("edit", func(request *context.Request) *context.Response {
184+
return thinkgo.Text("admin user edit !")
185+
})
186+
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
187+
if _, err := request.Input("user"); err != nil {
188+
return thinkgo.Text("Invalid parameters")
189+
}
190+
return next(request)
191+
})
192+
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
193+
if _, err := request.Input("token"); err != nil {
194+
return thinkgo.Text("Invalid parameters")
195+
}
196+
return next(request)
197+
})
198+
```
199+
137200
## Controller
138201

139202
#### Basic Controller
@@ -148,7 +211,7 @@ import (
148211
"github.com/thinkoner/thinkgo/context"
149212
)
150213

151-
func Index(req *context.Request) thinkgo.Response {
214+
func Index(req *context.Request) *context.Response {
152215
return thinkgo.Text("Hello ThinkGo !")
153216
}
154217

@@ -171,7 +234,7 @@ This feature will be supported in a future release.
171234
To obtain an instance of the current HTTP request via dependency injection
172235

173236
```go
174-
func Handler(req *context.Request) thinkgo.Response {
237+
func Handler(req *context.Request) *context.Response {
175238
name := req.Input("name")
176239
}
177240
```
@@ -181,7 +244,7 @@ func Handler(req *context.Request) thinkgo.Response {
181244
If your controller method is also expecting input from a route parameter you should list your route parameters after the request dependencies. For example, you can access your route parameter `name` like so:
182245

183246
```go
184-
route.Put("/user/{name}", func(req *context.Request, name string) thinkgo.Response {
247+
route.Put("/user/{name}", func(req *context.Request, name string) *context.Response {
185248
//
186249
})
187250
```
@@ -208,7 +271,7 @@ name, _ := request.Cookie("name")
208271

209272
## HTTP Response
210273

211-
an HTTP Response Must implement the `thinkgo.Response` interface
274+
an HTTP Response Must implement the `*context.Response` interface
212275

213276
#### Creating Responses
214277

@@ -228,6 +291,14 @@ thinkgo.Json(map[string]string{
228291
response.Cookie("name", "alice")
229292
```
230293

294+
#### Redirects
295+
296+
```go
297+
route.Get("/redirect", func(request *context.Request) *context.Response {
298+
return context.Redirect("https://www.google.com")
299+
})
300+
```
301+
231302
## View
232303

233304
views are stored in the `views` directory, A simple view might look something like this:
@@ -261,7 +332,7 @@ views are stored in the `views` directory, A simple view might look something li
261332
we may return it using the `Render` function like so:
262333

263334
```go
264-
route.Get("/tpl", func(request *context.Request) thinkgo.Response {
335+
route.Get("/tpl", func(request *context.Request) *context.Response {
265336
data := map[string]interface{}{"Title": "ThinkGo", "Message": "Hello ThinkGo !"}
266337
return thinkgo.Render("tpl.html", data)
267338
})

app.go

Lines changed: 0 additions & 26 deletions
This file was deleted.

app/app.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package app
2+
3+
import (
4+
"github.com/thinkoner/thinkgo/router"
5+
"github.com/thinkoner/thinkgo/view"
6+
)
7+
8+
// Application the ThinkGo Application
9+
type Application struct {
10+
view *view.View
11+
route *router.Route
12+
}
13+
14+
// NewApplication returns a new ThinkGo Application
15+
func NewApplication() *Application {
16+
return &Application{}
17+
}
18+
19+
// RegisterRoute Register Route for Application
20+
func (a *Application) RegisterRoute(r *router.Route) {
21+
a.route = r
22+
}
23+
24+
// RegisterView Register View for Application
25+
func (a *Application) RegisterView(v *view.View) {
26+
a.view = v
27+
}
28+
29+
// GetRoute Get the router of the application
30+
func (a *Application) GetRoute() *router.Route {
31+
return a.route
32+
}
33+
34+
// GetView Get the view of the application
35+
func (a *Application) GetView() *view.View {
36+
return a.view
37+
}

app/handler.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package app
2+
3+
import (
4+
"github.com/thinkoner/thinkgo/context"
5+
)
6+
7+
// HandlerFunc Handle the application.
8+
type HandlerFunc func(app *Application) Handler
9+
10+
// Closure Anonymous function, Used in Middleware Handler
11+
type Closure func(req *context.Request) interface{}
12+
13+
// Handler Middleware Handler interface
14+
type Handler interface {
15+
Process(request *context.Request, next Closure) interface{}
16+
}

app/route_hendler.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package app
2+
3+
import (
4+
"github.com/thinkoner/thinkgo/context"
5+
"github.com/thinkoner/thinkgo/router"
6+
)
7+
8+
type RouteHandler struct {
9+
Route *router.Route
10+
}
11+
12+
// NewRouteHandler The default RouteHandler
13+
func NewRouteHandler(app *Application) Handler {
14+
return &RouteHandler{
15+
Route: app.GetRoute(),
16+
}
17+
}
18+
19+
// Process Process the request to a router and return the response.
20+
func (h *RouteHandler) Process(request *context.Request, next Closure) interface{} {
21+
rule, err := h.Route.Dispatch(request)
22+
23+
if err != nil {
24+
return context.NotFoundResponse()
25+
}
26+
27+
return router.RunRoute(request, rule)
28+
}

app/session_handler.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package app
2+
3+
import (
4+
"github.com/thinkoner/thinkgo/config"
5+
"github.com/thinkoner/thinkgo/context"
6+
"github.com/thinkoner/thinkgo/session"
7+
)
8+
9+
type SessionHandler struct {
10+
manager *session.Manager
11+
app *Application
12+
}
13+
14+
// SessionHandler The default SessionHandler
15+
func NewSessionHandler(app *Application) Handler {
16+
handler := &SessionHandler{}
17+
handler.manager = session.NewManager(&session.Config{
18+
Driver: config.Session.Driver,
19+
CookieName: config.Session.CookieName,
20+
Lifetime: config.Session.Lifetime,
21+
Encrypt: config.Session.Encrypt,
22+
Files: config.Session.Files,
23+
})
24+
25+
handler.app = app
26+
27+
return handler
28+
}
29+
30+
func (h *SessionHandler) Process(req *context.Request, next Closure) interface{} {
31+
store := h.startSession(req)
32+
33+
req.SetSession(store)
34+
35+
result := next(req)
36+
37+
if res, ok := result.(session.Response); ok {
38+
h.saveSession(res)
39+
}
40+
41+
return result
42+
}
43+
44+
func (h *SessionHandler) startSession(req *context.Request) *session.Store {
45+
return h.manager.SessionStart(req)
46+
}
47+
48+
func (h *SessionHandler) saveSession(res session.Response) {
49+
h.manager.SessionSave(res)
50+
}

context/cookie.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"net/http"
66
"net/url"
77
"time"
8+
9+
"github.com/thinkoner/thinkgo/config"
810
)
911

1012
type CookieConfig struct {
@@ -91,3 +93,17 @@ func (c *Cookie) Set(name interface{}, params ...interface{}) (*http.Cookie, err
9193
}
9294
return cookie, nil
9395
}
96+
97+
func ParseCookieHandler() *Cookie {
98+
return &Cookie{
99+
Config: &CookieConfig{
100+
Prefix: config.Cookie.Prefix,
101+
Path: config.Cookie.Path,
102+
Domain: config.Cookie.Domain,
103+
Expires: time.Now().Add(config.Cookie.Expires),
104+
MaxAge: config.Cookie.MaxAge,
105+
Secure: config.Cookie.Secure,
106+
HttpOnly: config.Cookie.HttpOnly,
107+
},
108+
}
109+
}

0 commit comments

Comments
 (0)