mirror of
https://github.com/kataras/iris.git
synced 2026-01-09 13:05:56 +00:00
new feature: versioned controllers
Former-commit-id: c797e23c78b1e74bbe9ba56673f3a98f17f5e2f7
This commit is contained in:
@@ -78,6 +78,12 @@ type ControllerActivator struct {
|
||||
// End-devs can change some properties of the *Route on the `BeforeActivator` by using the
|
||||
// `GetRoute/GetRoutes(functionName)`.
|
||||
routes map[string][]*router.Route
|
||||
// BeginHandlers is a slice of middleware for this controller.
|
||||
// These handlers will be prependend to each one of
|
||||
// the route that this controller will register(Handle/HandleMany/struct methods)
|
||||
// to the targeted Party.
|
||||
// Look the `Use` method too.
|
||||
BeginHandlers context.Handlers
|
||||
|
||||
// true if this controller listens and serves to websocket events.
|
||||
servesWebsocket bool
|
||||
@@ -199,6 +205,15 @@ func (c *ControllerActivator) GetRoutes(methodName string) []*router.Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use registers a middleware for this Controller.
|
||||
// It appends one or more handlers to the `BeginHandlers`.
|
||||
// It's like the `Party.Use` but specifically
|
||||
// for the routes that this controller will register to the targeted `Party`.
|
||||
func (c *ControllerActivator) Use(handlers ...context.Handler) *ControllerActivator {
|
||||
c.BeginHandlers = append(c.BeginHandlers, handlers...)
|
||||
return c
|
||||
}
|
||||
|
||||
// Singleton returns new if all incoming clients' requests
|
||||
// have the same controller instance.
|
||||
// This is done automatically by iris to reduce the creation
|
||||
@@ -343,6 +358,7 @@ func (c *ControllerActivator) handleMany(method, path, funcName string, override
|
||||
}
|
||||
|
||||
handler := c.handlerOf(path, funcName)
|
||||
middleware = context.JoinHandlers(c.BeginHandlers, middleware)
|
||||
|
||||
// register the handler now.
|
||||
routes := c.app.Router.HandleMany(method, path, append(middleware, handler)...)
|
||||
|
||||
@@ -703,6 +703,31 @@ func TestControllerOverlapping(t *testing.T) {
|
||||
m.Handle(new(publicController))
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET("/").WithQuery("name", "kataras").Expect().Status(httptest.StatusOK).JSON().Equal(iris.Map{"id": 1})
|
||||
e.GET("/").Expect().Status(httptest.StatusOK).JSON().Equal(iris.Map{"data": "things"})
|
||||
e.GET("/").WithQuery("name", "kataras").Expect().Status(httptest.StatusOK).
|
||||
JSON().Equal(iris.Map{"id": 1})
|
||||
e.GET("/").Expect().Status(httptest.StatusOK).
|
||||
JSON().Equal(iris.Map{"data": "things"})
|
||||
}
|
||||
|
||||
type testControllerMethodHandlerBindStruct struct{}
|
||||
|
||||
type queryData struct {
|
||||
Name string `json:"name" url:"name"`
|
||||
}
|
||||
|
||||
func (*testControllerMethodHandlerBindStruct) Any(data queryData) queryData {
|
||||
return data
|
||||
}
|
||||
|
||||
func TestControllerMethodHandlerBindStruct(t *testing.T) {
|
||||
app := iris.New()
|
||||
|
||||
New(app).Handle(new(testControllerMethodHandlerBindStruct))
|
||||
|
||||
data := iris.Map{"name": "kataras"}
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET("/").WithQueryObject(data).Expect().Status(httptest.StatusOK).JSON().Equal(data)
|
||||
e.PATCH("/").WithJSON(data).Expect().Status(httptest.StatusOK).JSON().Equal(data)
|
||||
// more tests inside the hero package itself.
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ type GRPC struct {
|
||||
Strict bool
|
||||
}
|
||||
|
||||
var _ Option = GRPC{}
|
||||
|
||||
// Apply parses the controller's methods and registers gRPC handlers to the application.
|
||||
func (g GRPC) Apply(c *ControllerActivator) {
|
||||
defer c.Activated()
|
||||
|
||||
26
mvc/mvc.go
26
mvc/mvc.go
@@ -146,13 +146,25 @@ func (app *Application) Register(dependencies ...interface{}) *Application {
|
||||
return app
|
||||
}
|
||||
|
||||
// Option is an interface which does contain a single `Apply` method that accepts
|
||||
// a `ControllerActivator`. It can be passed on `Application.Handle` method to
|
||||
// mdoify the behavior right after the `BeforeActivation` state.
|
||||
//
|
||||
// See `GRPC` package-level structure too.
|
||||
type Option interface {
|
||||
Apply(*ControllerActivator)
|
||||
type (
|
||||
// Option is an interface which does contain a single `Apply` method that accepts
|
||||
// a `ControllerActivator`. It can be passed on `Application.Handle` method to
|
||||
// mdoify the behavior right after the `BeforeActivation` state.
|
||||
//
|
||||
// See `GRPC` package-level structure
|
||||
// and `Version` package-level function too.
|
||||
Option interface {
|
||||
Apply(*ControllerActivator)
|
||||
}
|
||||
|
||||
// OptionFunc is the functional type of `Option`.
|
||||
// Read `Option` docs.
|
||||
OptionFunc func(*ControllerActivator)
|
||||
)
|
||||
|
||||
// Apply completes the `Option` interface.
|
||||
func (opt OptionFunc) Apply(c *ControllerActivator) {
|
||||
opt(c)
|
||||
}
|
||||
|
||||
// Handle serves a controller for the current mvc application's Router.
|
||||
|
||||
38
mvc/versioning.go
Normal file
38
mvc/versioning.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
"github.com/kataras/iris/v12/versioning"
|
||||
)
|
||||
|
||||
// Version returns a valid `Option` that can be passed to the `Application.Handle` method.
|
||||
// It requires a specific "version" constraint for a Controller,
|
||||
// e.g. ">1, <=2" or just "1".
|
||||
//
|
||||
//
|
||||
// Usage:
|
||||
// m := mvc.New(dataRouter)
|
||||
// m.Handle(new(v1Controller), mvc.Version("1"))
|
||||
// m.Handle(new(v2Controller), mvc.Version("2.3"))
|
||||
// m.Handle(new(v3Controller), mvc.Version(">=3, <4"))
|
||||
// m.Handle(new(noVersionController))
|
||||
//
|
||||
// See the `versioning` package's documentation for more information on
|
||||
// how the version is extracted from incoming requests.
|
||||
//
|
||||
// Note that this Option will set the route register rule to `RouteOverlap`.
|
||||
func Version(version string) OptionFunc {
|
||||
return func(c *ControllerActivator) {
|
||||
c.Router().SetRegisterRule(router.RouteOverlap) // required for this feature.
|
||||
|
||||
c.Use(func(ctx context.Context) {
|
||||
if !versioning.Match(ctx, version) {
|
||||
ctx.StopExecution()
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user