mirror of
https://github.com/kataras/iris.git
synced 2025-02-09 02:34:55 +01:00
example: write our own customized router using the high-level API which gives access to the correct context and routes
Former-commit-id: d2369c20490619cad0dd6f7b6ed01cdbef51a853
This commit is contained in:
parent
97e96ed6ca
commit
120b5fb635
|
@ -1,5 +0,0 @@
|
||||||
FROM irisgo/cloud-native-go:latest
|
|
||||||
|
|
||||||
ENV APPSOURCES /go/src/github.com/iris-contrib/cloud-native-go
|
|
||||||
|
|
||||||
RUN ${APPSOURCES}/cloud-native-go
|
|
|
@ -1,12 +0,0 @@
|
||||||
FROM golang:1.9.3-alpine
|
|
||||||
|
|
||||||
RUN apk update && apk upgrade && apk add --no-cache bash git
|
|
||||||
RUN go get github.com/iris-contrib/cloud-native-go
|
|
||||||
|
|
||||||
ENV SOURCES /go/src/github.com/iris-contrib/cloud-native-go
|
|
||||||
# COPY . ${SOURCES}
|
|
||||||
|
|
||||||
RUN cd ${SOURCES} $$ CGO_ENABLED=0 go build
|
|
||||||
|
|
||||||
ENTRYPOINT cloud-native-go
|
|
||||||
EXPOSE 8080
|
|
|
@ -146,8 +146,11 @@ Navigate through examples for a better understanding.
|
||||||
- [Custom HTTP Errors](routing/http-errors/main.go)
|
- [Custom HTTP Errors](routing/http-errors/main.go)
|
||||||
- [Dynamic Path](routing/dynamic-path/main.go)
|
- [Dynamic Path](routing/dynamic-path/main.go)
|
||||||
* [root level wildcard path](routing/dynamic-path/root-wildcard/main.go)
|
* [root level wildcard path](routing/dynamic-path/root-wildcard/main.go)
|
||||||
|
- [Write your own custom parameter types](routing/macros/main.go) **NEW**
|
||||||
- [Reverse routing](routing/reverse/main.go)
|
- [Reverse routing](routing/reverse/main.go)
|
||||||
- [Custom wrapper](routing/custom-wrapper/main.go)
|
- [Custom Router (high-level)](routing/custom-high-level-router/main.go) **NEW**
|
||||||
|
- [Custom Router (low-level)](routing/custom-low-level-router/main.go) **NEW**
|
||||||
|
- [Custom Wrapper](routing/custom-wrapper/main.go)
|
||||||
- Custom Context
|
- Custom Context
|
||||||
* [method overriding](routing/custom-context/method-overriding/main.go)
|
* [method overriding](routing/custom-context/method-overriding/main.go)
|
||||||
* [new implementation](routing/custom-context/new-implementation/main.go)
|
* [new implementation](routing/custom-context/new-implementation/main.go)
|
||||||
|
|
|
@ -105,7 +105,10 @@ app.Get("{root:path}", rootWildcardHandler)
|
||||||
- [自定义 HTTP 错误](routing/http-errors/main.go)
|
- [自定义 HTTP 错误](routing/http-errors/main.go)
|
||||||
- [动态路径](routing/dynamic-path/main.go)
|
- [动态路径](routing/dynamic-path/main.go)
|
||||||
* [根级通配符路径](routing/dynamic-path/root-wildcard/main.go)
|
* [根级通配符路径](routing/dynamic-path/root-wildcard/main.go)
|
||||||
|
- [Write your own custom parameter types](routing/macros/main.go) **NEW**
|
||||||
- [反向路由](routing/reverse/main.go)
|
- [反向路由](routing/reverse/main.go)
|
||||||
|
- [Custom Router (high-level)](routing/custom-high-level-router/main.go) **NEW**
|
||||||
|
- [Custom Router (low-level)](routing/custom-low-level-router/main.go) **NEW**
|
||||||
- [自定义包装](routing/custom-wrapper/main.go)
|
- [自定义包装](routing/custom-wrapper/main.go)
|
||||||
- 自定义上下文
|
- 自定义上下文
|
||||||
* [方法重写](routing/custom-context/method-overriding/main.go)
|
* [方法重写](routing/custom-context/method-overriding/main.go)
|
||||||
|
|
103
_examples/routing/custom-high-level-router/main.go
Normal file
103
_examples/routing/custom-high-level-router/main.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/context"
|
||||||
|
"github.com/kataras/iris/core/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* A Router should contain all three of the following methods:
|
||||||
|
- HandleRequest should handle the request based on the Context.
|
||||||
|
HandleRequest(ctx context.Context)
|
||||||
|
- Build should builds the handler, it's being called on router's BuildRouter.
|
||||||
|
Build(provider router.RoutesProvider) error
|
||||||
|
- RouteExists reports whether a particular route exists.
|
||||||
|
RouteExists(ctx context.Context, method, path string) bool
|
||||||
|
|
||||||
|
For a more detailed, complete and useful example
|
||||||
|
you can take a look at the iris' router itself which is located at:
|
||||||
|
https://github.com/kataras/iris/tree/master/core/router/handler.go
|
||||||
|
which completes this exact interface, the `router#RequestHandler`.
|
||||||
|
*/
|
||||||
|
type customRouter struct {
|
||||||
|
// a copy of routes (safer because you will not be able to alter a route on serve-time without a `app.RefreshRouter` call):
|
||||||
|
// []router.Route
|
||||||
|
// or just expect the whole routes provider:
|
||||||
|
provider router.RoutesProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleRequest a silly example which finds routes based only on the first part of the requested path
|
||||||
|
// which must be a static one as well, the rest goes to fill the parameters.
|
||||||
|
func (r *customRouter) HandleRequest(ctx context.Context) {
|
||||||
|
path := ctx.Path()
|
||||||
|
ctx.Application().Logger().Infof("Requested resource path: %s", path)
|
||||||
|
|
||||||
|
parts := strings.Split(path, "/")[1:]
|
||||||
|
staticPath := "/" + parts[0]
|
||||||
|
for _, route := range r.provider.GetRoutes() {
|
||||||
|
if strings.HasPrefix(route.Path, staticPath) {
|
||||||
|
paramParts := parts[1:]
|
||||||
|
for _, paramValue := range paramParts {
|
||||||
|
for _, p := range route.Tmpl().Params {
|
||||||
|
ctx.Params().Set(p.Name, paramValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetCurrentRouteName(route.Name)
|
||||||
|
ctx.Do(route.Handlers)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if nothing found...
|
||||||
|
ctx.StatusCode(iris.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *customRouter) Build(provider router.RoutesProvider) error {
|
||||||
|
for _, route := range provider.GetRoutes() {
|
||||||
|
// do any necessary validation or conversations based on your custom logic here
|
||||||
|
// but always run the "BuildHandlers" for each registered route.
|
||||||
|
route.BuildHandlers()
|
||||||
|
// [...] r.routes = append(r.routes, *route)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.provider = provider
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *customRouter) RouteExists(ctx context.Context, method, path string) bool {
|
||||||
|
// [...]
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
// In case you are wondering, the parameter types and macros like "{param:string $func()}" still work inside
|
||||||
|
// your custom router if you fetch by the Route's Handler
|
||||||
|
// because they are middlewares under the hood, so you don't have to implement the logic of handling them manually,
|
||||||
|
// though you have to match what requested path is what route and fill the ctx.Params(), this is the work of your custom router.
|
||||||
|
app.Get("/hello/{name}", func(ctx context.Context) {
|
||||||
|
name := ctx.Params().Get("name")
|
||||||
|
ctx.Writef("Hello %s\n", name)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/cs/{num:uint64 min(10) else 400}", func(ctx context.Context) {
|
||||||
|
num := ctx.Params().GetUint64Default("num", 0)
|
||||||
|
ctx.Writef("num is: %d\n", num)
|
||||||
|
})
|
||||||
|
|
||||||
|
// To replace the existing router with a customized one by using the iris/context.Context
|
||||||
|
// you have to use the `app.BuildRouter` method before `app.Run` and after the routes registered.
|
||||||
|
// You should pass your custom router's instance as the second input arg, which must completes the `router#RequestHandler`
|
||||||
|
// interface as shown above.
|
||||||
|
//
|
||||||
|
// To see how you can build something even more low-level without direct iris' context support (you can do that manually as well)
|
||||||
|
// navigate to the "custom-wrapper" example instead.
|
||||||
|
myCustomRouter := new(customRouter)
|
||||||
|
app.BuildRouter(app.ContextPool, myCustomRouter, app.APIBuilder, true)
|
||||||
|
|
||||||
|
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
|
||||||
|
}
|
6
_examples/routing/custom-low-level-router/main.go
Normal file
6
_examples/routing/custom-low-level-router/main.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/// TODO: showcase the `app.Downgrade` feature tomorrow if not already existing elsewhere.
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
|
@ -17,10 +17,9 @@ import (
|
||||||
// RequestHandler the middle man between acquiring a context and releasing it.
|
// RequestHandler the middle man between acquiring a context and releasing it.
|
||||||
// By-default is the router algorithm.
|
// By-default is the router algorithm.
|
||||||
type RequestHandler interface {
|
type RequestHandler interface {
|
||||||
// HandleRequest is same as context.Handler but its usage is only about routing,
|
// HandleRequest should handle the request based on the Context.
|
||||||
// separate the concept here.
|
|
||||||
HandleRequest(context.Context)
|
HandleRequest(context.Context)
|
||||||
// Build should builds the handler, it's being called on router's BuildRouter.
|
// Build should builds the handler, it's being called on router's BuildRouter.
|
||||||
Build(provider RoutesProvider) error
|
Build(provider RoutesProvider) error
|
||||||
// RouteExists reports whether a particular route exists.
|
// RouteExists reports whether a particular route exists.
|
||||||
RouteExists(ctx context.Context, method, path string) bool
|
RouteExists(ctx context.Context, method, path string) bool
|
||||||
|
|
|
@ -31,7 +31,7 @@ func NewRouter() *Router { return &Router{} }
|
||||||
// RefreshRouter re-builds the router. Should be called when a route's state
|
// RefreshRouter re-builds the router. Should be called when a route's state
|
||||||
// changed (i.e Method changed at serve-time).
|
// changed (i.e Method changed at serve-time).
|
||||||
func (router *Router) RefreshRouter() error {
|
func (router *Router) RefreshRouter() error {
|
||||||
return router.BuildRouter(router.cPool, router.requestHandler, router.routesProvider)
|
return router.BuildRouter(router.cPool, router.requestHandler, router.routesProvider, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildRouter builds the router based on
|
// BuildRouter builds the router based on
|
||||||
|
@ -41,7 +41,7 @@ func (router *Router) RefreshRouter() error {
|
||||||
// its wrapper.
|
// its wrapper.
|
||||||
//
|
//
|
||||||
// Use of RefreshRouter to re-build the router if needed.
|
// Use of RefreshRouter to re-build the router if needed.
|
||||||
func (router *Router) BuildRouter(cPool *context.Pool, requestHandler RequestHandler, routesProvider RoutesProvider) error {
|
func (router *Router) BuildRouter(cPool *context.Pool, requestHandler RequestHandler, routesProvider RoutesProvider, force bool) error {
|
||||||
|
|
||||||
if requestHandler == nil {
|
if requestHandler == nil {
|
||||||
return errors.New("router: request handler is nil")
|
return errors.New("router: request handler is nil")
|
||||||
|
@ -60,9 +60,23 @@ func (router *Router) BuildRouter(cPool *context.Pool, requestHandler RequestHan
|
||||||
defer router.mu.Unlock()
|
defer router.mu.Unlock()
|
||||||
|
|
||||||
// store these for RefreshRouter's needs.
|
// store these for RefreshRouter's needs.
|
||||||
router.cPool = cPool
|
if force {
|
||||||
router.requestHandler = requestHandler
|
router.cPool = cPool
|
||||||
router.routesProvider = routesProvider
|
router.requestHandler = requestHandler
|
||||||
|
router.routesProvider = routesProvider
|
||||||
|
} else {
|
||||||
|
if router.cPool == nil {
|
||||||
|
router.cPool = cPool
|
||||||
|
}
|
||||||
|
|
||||||
|
if router.requestHandler == nil {
|
||||||
|
router.requestHandler = requestHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
if router.routesProvider == nil && routesProvider != nil {
|
||||||
|
router.routesProvider = routesProvider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the important
|
// the important
|
||||||
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
2
iris.go
2
iris.go
|
@ -761,7 +761,7 @@ func (app *Application) Build() error {
|
||||||
// create the request handler, the default routing handler
|
// create the request handler, the default routing handler
|
||||||
routerHandler := router.NewDefaultHandler()
|
routerHandler := router.NewDefaultHandler()
|
||||||
|
|
||||||
rp.Describe("router: %v", app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder))
|
rp.Describe("router: %v", app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false))
|
||||||
// re-build of the router from outside can be done with;
|
// re-build of the router from outside can be done with;
|
||||||
// app.RefreshRouter()
|
// app.RefreshRouter()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user