mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
new 'Party.DI()' method to return the Party's instance of the new 'APIBuilderDI' and move the DI-relative Router to this new APIBuilderDI
Former-commit-id: 2fb81406c6e3162991c90e0918a3cac1b77c2b54
This commit is contained in:
parent
5852327f30
commit
1b02f048ef
45
HISTORY.md
45
HISTORY.md
|
@ -34,7 +34,7 @@ The most common scenario from a route to handle is to:
|
|||
- accept one or more path parameters and request data, a payload
|
||||
- send back a response, a payload (JSON, XML,...)
|
||||
|
||||
The new Iris Dependency Injection feature is about **33.2% faster** than its predecessor on the above case. This drops down even more the performance cost between native handlers and dynamic handlers with dependencies. This reason itself brings us, with safety and performance-wise, to the new `Party.HandleFunc(method, relativePath string, handlersFn ...interface{}) *Route` and `Party.RegisterDependency` method.
|
||||
The new Iris Dependency Injection feature is about **33.2% faster** than its predecessor on the above case. This drops down even more the performance cost between native handlers and dynamic handlers with dependencies. This reason itself brings us, with safety and performance-wise, to the new `Party.DI() *APIBuilderDI` method which returns methods such as `DI.Handle(method, relativePath string, handlersFn ...interface{}) *Route` and `DI.RegisterDependency`.
|
||||
|
||||
Look how clean your codebase can be when using Iris':
|
||||
|
||||
|
@ -63,31 +63,26 @@ func handler(id int, in testInput) testOutput {
|
|||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.HandleFunc(iris.MethodPost, "/{id:int}", handler)
|
||||
app.DI().Handle(iris.MethodPost, "/{id:int}", handler)
|
||||
app.Listen(":5000", iris.WithOptimizations)
|
||||
}
|
||||
```
|
||||
|
||||
Your eyes don't lie you. You read well, no `ctx.ReadJSON(&v)` and `ctx.JSON(send)` neither `error` handling are presented. It is a huge relief but if you ever need, you still have the control over those, even errors from dependencies. Any error may occur from request-scoped dependencies or your own handler is dispatched through `Party.GetContainer().GetErrorHandler` which defaults to the `hero.DefaultErrorHandler` which sends a `400 Bad Request` response with the error's text as its body contents, you can change it through `Party#OnErrorFunc`. If you want to handle `testInput` otherwise then just add a `Party.RegisterDependency(func(ctx iris.Context) testInput {...})` and you are ready to go. Here is a quick list of the new Party's methods:
|
||||
Your eyes don't lie you. You read well, no `ctx.ReadJSON(&v)` and `ctx.JSON(send)` neither `error` handling are presented. It is a huge relief but if you ever need, you still have the control over those, even errors from dependencies. Any error may occur from request-scoped dependencies or your own handler is dispatched through `Party.DI().Container.GetErrorHandler` which defaults to the `hero.DefaultErrorHandler` which sends a `400 Bad Request` response with the error's text as its body contents, you can change it through `Party.DI().OnError`. If you want to handle `testInput` otherwise then just add a `Party.DI().RegisterDependency(func(ctx iris.Context) testInput {...})` and you are ready to go. Here is a quick list of the new Party.DI's fields and methods:
|
||||
|
||||
```go
|
||||
// GetContainer returns the DI Container of this Party.
|
||||
// Container holds the DI Container of this Party featured Dependency Injection.
|
||||
// Use it to manually convert functions or structs(controllers) to a Handler.
|
||||
//
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
GetContainer() *hero.Container
|
||||
Container *hero.Container
|
||||
```
|
||||
|
||||
```go
|
||||
// OnErrorFunc adds an error handler for this Party's DI Hero Container and its handlers (or controllers).
|
||||
// OnError adds an error handler for this Party's DI Hero Container and its handlers (or controllers).
|
||||
// The "errorHandler" handles any error may occurred and returned
|
||||
// during dependencies injection of the Party's hero handlers or from the handlers themselves.
|
||||
//
|
||||
// Same as:
|
||||
// GetContainer().GetErrorHandler = func(ctx iris.Context) hero.ErrorHandler { return errorHandler }
|
||||
//
|
||||
// See `RegisterDependency`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
OnErrorFunc(errorHandler func(context.Context, error))
|
||||
OnError(errorHandler func(context.Context, error))
|
||||
```
|
||||
|
||||
```go
|
||||
// RegisterDependency adds a dependency.
|
||||
// The value can be a single struct value or a function.
|
||||
|
@ -106,20 +101,18 @@ OnErrorFunc(errorHandler func(context.Context, error))
|
|||
// - RegisterDependency(loggerService{prefix: "dev"})
|
||||
// - RegisterDependency(func(ctx iris.Context) User {...})
|
||||
// - RegisterDependency(func(User) OtherResponse {...})
|
||||
//
|
||||
// See `OnErrorFunc`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
RegisterDependency(dependency interface{})
|
||||
```
|
||||
|
||||
```go
|
||||
// UseFunc same as "Use" but it accepts dynamic functions as its "handlersFn" input.
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `DoneFunc` and `HandleFunc` for more.
|
||||
UseFunc(handlersFn ...interface{})
|
||||
// DoneFunc same as "Done" but it accepts dynamic functions as its "handlersFn" input.
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc` and `HandleFunc` for more.
|
||||
DoneFunc(handlersFn ...interface{})
|
||||
// Use same as a common Party's "Use" but it accepts dynamic functions as its "handlersFn" input.
|
||||
Use(handlersFn ...interface{})
|
||||
// Done same as a common Party's but it accepts dynamic functions as its "handlersFn" input.
|
||||
Done(handlersFn ...interface{})
|
||||
```
|
||||
|
||||
```go
|
||||
// HandleFunc same as `HandleFunc` but it accepts one or more "handlersFn" functions which each one of them
|
||||
// Handle same as a common Party's `Handle` but it accepts one or more "handlersFn" functions which each one of them
|
||||
// can accept any input arguments that match with the Party's registered Container's `Dependencies` and
|
||||
// any output result; like custom structs <T>, string, []byte, int, error,
|
||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||
|
@ -128,9 +121,7 @@ DoneFunc(handlersFn ...interface{})
|
|||
// the "handlersFn" will call `ctx.Next()` automatically when not called manually.
|
||||
// To stop the execution and not continue to the next "handlersFn"
|
||||
// the end-developer should output an error and return `iris.ErrStopExecution`.
|
||||
//
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc` and `DoneFunc` too.
|
||||
HandleFunc(method, relativePath string, handlersFn ...interface{}) *Route
|
||||
Handle(method, relativePath string, handlersFn ...interface{}) *Route
|
||||
```
|
||||
|
||||
Prior to this version the `iris.Context` was the only one dependency that has been automatically binded to the handler's input or a controller's fields and methods, read below to see what types are automatically binded:
|
||||
|
@ -172,7 +163,7 @@ Other Improvements:
|
|||
|
||||
- `ctx.JSON, JSONP, XML`: if `iris.WithOptimizations` is NOT passed on `app.Run/Listen` then the indentation defaults to `" "` (two spaces) otherwise it is empty or the provided value.
|
||||
|
||||
- Hero Handlers (and `app.HandleFunc`) do not have to require `iris.Context` just to call `ctx.Next()` anymore, this is done automatically now.
|
||||
- Hero Handlers (and `app.DI().Handle`) do not have to require `iris.Context` just to call `ctx.Next()` anymore, this is done automatically now.
|
||||
|
||||
New Context Methods:
|
||||
|
||||
|
|
|
@ -22,6 +22,6 @@ func handler(id int, in testInput) testOutput {
|
|||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.HandleFunc(iris.MethodPost, "/{id:int}", handler)
|
||||
app.DI().Post("/{id:int}", handler)
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
|
|
@ -46,8 +46,11 @@ func newApp() *iris.Application {
|
|||
// a JSON and 200 status code
|
||||
// or 202 status code and empty body
|
||||
// or a 409 status code and "my_error" body.
|
||||
app.UseFunc(middleware)
|
||||
app.HandleFunc(iris.MethodPost, "/{id:int}", handler)
|
||||
di := app.DI()
|
||||
{
|
||||
di.Use(middleware)
|
||||
di.Post("/{id:int}", handler)
|
||||
}
|
||||
|
||||
app.Configure(
|
||||
iris.WithOptimizations, /* optional */
|
||||
|
|
|
@ -34,6 +34,11 @@ func runServer() {
|
|||
}
|
||||
|
||||
func showAndWaitWindow() {
|
||||
webview.Open("My App",
|
||||
addr, 800, 600, true)
|
||||
debug := true
|
||||
w := webview.New(debug)
|
||||
defer w.Destroy()
|
||||
w.SetTitle("Minimal webview example")
|
||||
w.SetSize(800, 600, webview.HintNone)
|
||||
w.Navigate("https://iris-go.com")
|
||||
w.Run()
|
||||
}
|
||||
|
|
|
@ -4039,7 +4039,7 @@ func (n *NegotiationBuilder) JSON(v ...interface{}) *NegotiationBuilder {
|
|||
return n.MIME(ContentJSONHeaderValue, content)
|
||||
}
|
||||
|
||||
// Problem registers the "application/problem+xml" or "application/problem+xml" content type and, optionally,
|
||||
// Problem registers the "application/problem+json" or "application/problem+xml" content type and, optionally,
|
||||
// a value that `Context.Negotiate` will render
|
||||
// when a client accepts the "application/problem+json" or the "application/problem+xml" content type.
|
||||
//
|
||||
|
@ -4251,7 +4251,7 @@ func negotiationMatch(in []string, priorities []string) string {
|
|||
type NegotiationAcceptBuilder struct {
|
||||
// initialized with "Accept" request header values.
|
||||
accept []string
|
||||
// initialized with "Accept-Encoding" request header. and if was empty then the
|
||||
// initialized with "Accept-Charset" request header. and if was empty then the
|
||||
// application's default (which defaults to utf-8).
|
||||
charset []string
|
||||
// initialized with "Accept-Encoding" request header values.
|
||||
|
@ -4356,6 +4356,18 @@ func (n *NegotiationAcceptBuilder) YAML() *NegotiationAcceptBuilder {
|
|||
return n.MIME(ContentYAMLHeaderValue)
|
||||
}
|
||||
|
||||
// Protobuf adds the "application/x-protobuf" as accepted client content type.
|
||||
// Returns itself.
|
||||
func (n *NegotiationAcceptBuilder) Protobuf() *NegotiationAcceptBuilder {
|
||||
return n.MIME(ContentYAMLHeaderValue)
|
||||
}
|
||||
|
||||
// MsgPack adds the "application/msgpack" and "application/x-msgpack" as accepted client content types.
|
||||
// Returns itself.
|
||||
func (n *NegotiationAcceptBuilder) MsgPack() *NegotiationAcceptBuilder {
|
||||
return n.MIME(ContentYAMLHeaderValue)
|
||||
}
|
||||
|
||||
// Charset adds one or more client accepted charsets.
|
||||
// Returns itself.
|
||||
func (n *NegotiationAcceptBuilder) Charset(charset ...string) *NegotiationAcceptBuilder {
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
// to store the "offline" routes.
|
||||
const MethodNone = "NONE"
|
||||
|
||||
// AllMethods contains the valid http methods:
|
||||
// AllMethods contains the valid HTTP Methods:
|
||||
// "GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD",
|
||||
// "PATCH", "OPTIONS", "TRACE".
|
||||
var AllMethods = []string{
|
||||
|
@ -112,6 +112,9 @@ func (repo *repository) register(route *Route, rule RouteRegisterRule) (*Route,
|
|||
// APIBuilder the visible API for constructing the router
|
||||
// and child routers.
|
||||
type APIBuilder struct {
|
||||
// the per-party APIBuilder with DI.
|
||||
apiBuilderDI *APIBuilderDI
|
||||
|
||||
// the api builder global macros registry
|
||||
macros *macro.Macros
|
||||
// the api builder global handlers per status code registry (used for custom http errors)
|
||||
|
@ -152,8 +155,6 @@ type APIBuilder struct {
|
|||
handlerExecutionRules ExecutionRules
|
||||
// the per-party (and its children) route registration rule, see `SetRegisterRule`.
|
||||
routeRegisterRule RouteRegisterRule
|
||||
// the per-party (and its children gets a clone) DI container. See `HandleFunc`, `UseFunc`, `DoneFunc` too.
|
||||
container *hero.Container
|
||||
}
|
||||
|
||||
var _ Party = (*APIBuilder)(nil)
|
||||
|
@ -168,12 +169,21 @@ func NewAPIBuilder() *APIBuilder {
|
|||
errors: errgroup.New("API Builder"),
|
||||
relativePath: "/",
|
||||
routes: new(repository),
|
||||
container: hero.New(),
|
||||
}
|
||||
|
||||
api.apiBuilderDI = &APIBuilderDI{
|
||||
Self: api,
|
||||
Container: hero.New(),
|
||||
}
|
||||
|
||||
return api
|
||||
}
|
||||
|
||||
// DI returns the APIBuilder featured with Dependency Injection.
|
||||
func (api *APIBuilder) DI() *APIBuilderDI {
|
||||
return api.apiBuilderDI
|
||||
}
|
||||
|
||||
// GetRelPath returns the current party's relative path.
|
||||
// i.e:
|
||||
// if r := app.Party("/users"), then the `r.GetRelPath()` is the "/users".
|
||||
|
@ -249,86 +259,6 @@ func (api *APIBuilder) SetRegisterRule(rule RouteRegisterRule) Party {
|
|||
return api
|
||||
}
|
||||
|
||||
// GetContainer returns the DI Container of this Party.
|
||||
// Use it to manually convert functions or structs(controllers) to a Handler.
|
||||
//
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
func (api *APIBuilder) GetContainer() *hero.Container {
|
||||
return api.container
|
||||
}
|
||||
|
||||
// OnErrorFunc adds an error handler for this Party's DI Hero Container and its handlers (or controllers).
|
||||
// The "errorHandler" handles any error may occurred and returned
|
||||
// during dependencies injection of the Party's hero handlers or from the handlers themselves.
|
||||
//
|
||||
// Same as:
|
||||
// GetContainer().GetErrorHandler = func(ctx iris.Context) hero.ErrorHandler { return errorHandler }
|
||||
//
|
||||
// See `RegisterDependency`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
func (api *APIBuilder) OnErrorFunc(errorHandler func(context.Context, error)) {
|
||||
errHandler := hero.ErrorHandlerFunc(errorHandler)
|
||||
api.GetContainer().GetErrorHandler = func(ctx context.Context) hero.ErrorHandler {
|
||||
return errHandler
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterDependency adds a dependency.
|
||||
// The value can be a single struct value or a function.
|
||||
// Follow the rules:
|
||||
// * <T>{structValue}
|
||||
// * func(accepts <T>) returns <D> or (<D>, error)
|
||||
// * func(accepts iris.Context) returns <D> or (<D>, error)
|
||||
// * func(accepts1 iris.Context, accepts2 *hero.Input) returns <D> or (<D>, error)
|
||||
//
|
||||
// A Dependency can accept a previous registered dependency and return a new one or the same updated.
|
||||
// * func(accepts1 <D>, accepts2 <T>) returns <E> or (<E>, error) or error
|
||||
// * func(acceptsPathParameter1 string, id uint64) returns <T> or (<T>, error)
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// - RegisterDependency(loggerService{prefix: "dev"})
|
||||
// - RegisterDependency(func(ctx iris.Context) User {...})
|
||||
// - RegisterDependency(func(User) OtherResponse {...})
|
||||
//
|
||||
// See `OnErrorFunc`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
func (api *APIBuilder) RegisterDependency(dependency interface{}) *hero.Dependency {
|
||||
return api.container.Register(dependency)
|
||||
}
|
||||
|
||||
// convertHandlerFuncs accepts Iris hero handlers and returns a slice of native Iris handlers.
|
||||
func (api *APIBuilder) convertHandlerFuncs(relativePath string, handlersFn ...interface{}) context.Handlers {
|
||||
fullpath := api.relativePath + relativePath
|
||||
paramsCount := macro.CountParams(fullpath, *api.macros)
|
||||
|
||||
handlers := make(context.Handlers, 0, len(handlersFn))
|
||||
for _, h := range handlersFn {
|
||||
handlers = append(handlers, api.container.HandlerWithParams(h, paramsCount))
|
||||
}
|
||||
|
||||
// On that type of handlers the end-developer does not have to include the Context in the handler,
|
||||
// so the ctx.Next is automatically called unless an `ErrStopExecution` returned (implementation inside hero pkg).
|
||||
o := ExecutionOptions{Force: true}
|
||||
o.apply(&handlers)
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
// HandleFunc same as `HandleFunc` but it accepts one or more "handlersFn" functions which each one of them
|
||||
// can accept any input arguments that match with the Party's registered Container's `Dependencies` and
|
||||
// any output result; like custom structs <T>, string, []byte, int, error,
|
||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||
//
|
||||
// It's common from a hero handler to not even need to accept a `Context`, for that reason,
|
||||
// the "handlersFn" will call `ctx.Next()` automatically when not called manually.
|
||||
// To stop the execution and not continue to the next "handlersFn"
|
||||
// the end-developer should output an error and return `iris.ErrStopExecution`.
|
||||
//
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc` and `DoneFunc` too.
|
||||
func (api *APIBuilder) HandleFunc(method, relativePath string, handlersFn ...interface{}) *Route {
|
||||
handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
|
||||
return api.Handle(method, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Handle registers a route to the server's api.
|
||||
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
|
||||
//
|
||||
|
@ -578,11 +508,7 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
|||
allowMethods := make([]string, len(api.allowMethods))
|
||||
copy(allowMethods, api.allowMethods)
|
||||
|
||||
// attach a new Container with correct dynamic path parameter start index for input arguments
|
||||
// based on the fullpath.
|
||||
childContainer := api.container.Clone()
|
||||
|
||||
return &APIBuilder{
|
||||
childAPI := &APIBuilder{
|
||||
// global/api builder
|
||||
macros: api.macros,
|
||||
routes: api.routes,
|
||||
|
@ -597,8 +523,18 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
|||
allowMethods: allowMethods,
|
||||
handlerExecutionRules: api.handlerExecutionRules,
|
||||
routeRegisterRule: api.routeRegisterRule,
|
||||
container: childContainer,
|
||||
}
|
||||
|
||||
// attach a new Container with correct dynamic path parameter start index for input arguments
|
||||
// based on the fullpath.
|
||||
childContainer := api.apiBuilderDI.Container.Clone()
|
||||
|
||||
childAPI.apiBuilderDI = &APIBuilderDI{
|
||||
Self: childAPI,
|
||||
Container: childContainer,
|
||||
}
|
||||
|
||||
return childAPI
|
||||
}
|
||||
|
||||
// PartyFunc same as `Party`, groups routes that share a base path or/and same handlers.
|
||||
|
@ -740,14 +676,6 @@ func (api *APIBuilder) Use(handlers ...context.Handler) {
|
|||
api.middleware = append(api.middleware, handlers...)
|
||||
}
|
||||
|
||||
// UseFunc same as "Use" but it accepts dynamic functions as its "handlersFn" input.
|
||||
//
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `DoneFunc` and `HandleFunc` for more.
|
||||
func (api *APIBuilder) UseFunc(handlersFn ...interface{}) {
|
||||
handlers := api.convertHandlerFuncs("/", handlersFn...)
|
||||
api.Use(handlers...)
|
||||
}
|
||||
|
||||
// UseGlobal registers handlers that should run at the very beginning.
|
||||
// It prepends those handler(s) to all routes,
|
||||
// including all parties, subdomains.
|
||||
|
@ -774,13 +702,6 @@ func (api *APIBuilder) Done(handlers ...context.Handler) {
|
|||
api.doneHandlers = append(api.doneHandlers, handlers...)
|
||||
}
|
||||
|
||||
// DoneFunc same as "Done" but it accepts dynamic functions as its "handlersFn" input.
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc` and `HandleFunc` for more.
|
||||
func (api *APIBuilder) DoneFunc(handlersFn ...interface{}) {
|
||||
handlers := api.convertHandlerFuncs("/", handlersFn...)
|
||||
api.Done(handlers...)
|
||||
}
|
||||
|
||||
// DoneGlobal registers handlers that should run at the very end.
|
||||
// It appends those handler(s) to all routes,
|
||||
// including all parties, subdomains.
|
||||
|
@ -822,71 +743,79 @@ func (api *APIBuilder) None(relativePath string, handlers ...context.Handler) *R
|
|||
return api.Handle(MethodNone, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Get registers a route for the Get http method.
|
||||
// Get registers a route for the Get HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Get(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodGet, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Post registers a route for the Post http method.
|
||||
// Post registers a route for the Post HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Post(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodPost, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Put registers a route for the Put http method.
|
||||
// Put registers a route for the Put HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Put(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodPut, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Delete registers a route for the Delete http method.
|
||||
// Delete registers a route for the Delete HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Delete(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodDelete, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Connect registers a route for the Connect http method.
|
||||
// Connect registers a route for the Connect HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Connect(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodConnect, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Head registers a route for the Head http method.
|
||||
// Head registers a route for the Head HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Head(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodHead, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Options registers a route for the Options http method.
|
||||
// Options registers a route for the Options HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Options(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodOptions, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Patch registers a route for the Patch http method.
|
||||
// Patch registers a route for the Patch HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Patch(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodPatch, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Trace registers a route for the Trace http method.
|
||||
// Trace registers a route for the Trace HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilder) Trace(relativePath string, handlers ...context.Handler) *Route {
|
||||
return api.Handle(http.MethodTrace, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Any registers a route for ALL of the http methods
|
||||
// (Get,Post,Put,Head,Patch,Options,Connect,Delete).
|
||||
// Any registers a route for ALL of the HTTP methods:
|
||||
// Get
|
||||
// Post
|
||||
// Put
|
||||
// Delete
|
||||
// Head
|
||||
// Patch
|
||||
// Options
|
||||
// Connect
|
||||
// Trace
|
||||
func (api *APIBuilder) Any(relativePath string, handlers ...context.Handler) (routes []*Route) {
|
||||
for _, m := range AllMethods {
|
||||
r := api.HandleMany(m, relativePath, handlers...)
|
||||
|
|
197
core/router/api_builder_di.go
Normal file
197
core/router/api_builder_di.go
Normal file
|
@ -0,0 +1,197 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/hero"
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
)
|
||||
|
||||
// APIBuilderDI is a wrapper of a common `Party` features Dependency Injection.
|
||||
type APIBuilderDI struct {
|
||||
// Self returns the original `Party` without DI features.
|
||||
Self Party
|
||||
|
||||
// Container is the per-party (and its children gets a clone) DI container..
|
||||
Container *hero.Container
|
||||
}
|
||||
|
||||
// Party returns a child of this `APIBuilderDI` featured with Dependency Injection.
|
||||
// Like the `Self.Party` method does for the common Router Groups.
|
||||
func (api *APIBuilderDI) Party(relativePath string, handlersFn ...interface{}) *APIBuilderDI {
|
||||
handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
|
||||
p := api.Self.Party(relativePath, handlers...)
|
||||
return p.DI()
|
||||
}
|
||||
|
||||
// OnError adds an error handler for this Party's DI Hero Container and its handlers (or controllers).
|
||||
// The "errorHandler" handles any error may occurred and returned
|
||||
// during dependencies injection of the Party's hero handlers or from the handlers themselves.
|
||||
//
|
||||
// Same as:
|
||||
// Container.GetErrorHandler = func(ctx iris.Context) hero.ErrorHandler { return errorHandler }
|
||||
//
|
||||
// See `RegisterDependency`, `Use`, `Done` and `Handle` too.
|
||||
func (api *APIBuilderDI) OnError(errorHandler func(context.Context, error)) {
|
||||
errHandler := hero.ErrorHandlerFunc(errorHandler)
|
||||
api.Container.GetErrorHandler = func(ctx context.Context) hero.ErrorHandler {
|
||||
return errHandler
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterDependency adds a dependency.
|
||||
// The value can be a single struct value or a function.
|
||||
// Follow the rules:
|
||||
// * <T>{structValue}
|
||||
// * func(accepts <T>) returns <D> or (<D>, error)
|
||||
// * func(accepts iris.Context) returns <D> or (<D>, error)
|
||||
// * func(accepts1 iris.Context, accepts2 *hero.Input) returns <D> or (<D>, error)
|
||||
//
|
||||
// A Dependency can accept a previous registered dependency and return a new one or the same updated.
|
||||
// * func(accepts1 <D>, accepts2 <T>) returns <E> or (<E>, error) or error
|
||||
// * func(acceptsPathParameter1 string, id uint64) returns <T> or (<T>, error)
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// - RegisterDependency(loggerService{prefix: "dev"})
|
||||
// - RegisterDependency(func(ctx iris.Context) User {...})
|
||||
// - RegisterDependency(func(User) OtherResponse {...})
|
||||
//
|
||||
// See `OnError`, `Use`, `Done` and `Handle` too.
|
||||
func (api *APIBuilderDI) RegisterDependency(dependency interface{}) *hero.Dependency {
|
||||
return api.Container.Register(dependency)
|
||||
}
|
||||
|
||||
// convertHandlerFuncs accepts Iris hero handlers and returns a slice of native Iris handlers.
|
||||
func (api *APIBuilderDI) convertHandlerFuncs(relativePath string, handlersFn ...interface{}) context.Handlers {
|
||||
fullpath := api.Self.GetRelPath() + relativePath
|
||||
paramsCount := macro.CountParams(fullpath, *api.Self.Macros())
|
||||
|
||||
handlers := make(context.Handlers, 0, len(handlersFn))
|
||||
for _, h := range handlersFn {
|
||||
handlers = append(handlers, api.Container.HandlerWithParams(h, paramsCount))
|
||||
}
|
||||
|
||||
// On that type of handlers the end-developer does not have to include the Context in the handler,
|
||||
// so the ctx.Next is automatically called unless an `ErrStopExecution` returned (implementation inside hero pkg).
|
||||
o := ExecutionOptions{Force: true}
|
||||
o.apply(&handlers)
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
// Use same as `Self.Use` but it accepts dynamic functions as its "handlersFn" input.
|
||||
//
|
||||
// See `OnError`, `RegisterDependency`, `Done` and `Handle` for more.
|
||||
func (api *APIBuilderDI) Use(handlersFn ...interface{}) {
|
||||
handlers := api.convertHandlerFuncs("/", handlersFn...)
|
||||
api.Self.Use(handlers...)
|
||||
}
|
||||
|
||||
// Done same as `Self.Done` but it accepts dynamic functions as its "handlersFn" input.
|
||||
// See `OnError`, `RegisterDependency`, `Use` and `Handle` for more.
|
||||
func (api *APIBuilderDI) Done(handlersFn ...interface{}) {
|
||||
handlers := api.convertHandlerFuncs("/", handlersFn...)
|
||||
api.Self.Done(handlers...)
|
||||
}
|
||||
|
||||
// Handle same as `Self.Handle` but it accepts one or more "handlersFn" functions which each one of them
|
||||
// can accept any input arguments that match with the Party's registered Container's `Dependencies` and
|
||||
// any output result; like custom structs <T>, string, []byte, int, error,
|
||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||
//
|
||||
// It's common from a hero handler to not even need to accept a `Context`, for that reason,
|
||||
// the "handlersFn" will call `ctx.Next()` automatically when not called manually.
|
||||
// To stop the execution and not continue to the next "handlersFn"
|
||||
// the end-developer should output an error and return `iris.ErrStopExecution`.
|
||||
//
|
||||
// See `OnError`, `RegisterDependency`, `Use`, `Done`, `Get`, `Post`, `Put`, `Patch` and `Delete` too.
|
||||
func (api *APIBuilderDI) Handle(method, relativePath string, handlersFn ...interface{}) *Route {
|
||||
handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
|
||||
return api.Self.Handle(method, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// Get registers a route for the Get HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Get(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodGet, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Post registers a route for the Post HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Post(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodPost, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Put registers a route for the Put HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Put(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodPut, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Delete registers a route for the Delete HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Delete(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodDelete, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Connect registers a route for the Connect HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Connect(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodConnect, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Head registers a route for the Head HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Head(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodHead, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Options registers a route for the Options HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Options(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodOptions, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Patch registers a route for the Patch HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Patch(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodPatch, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Trace registers a route for the Trace HTTP Method.
|
||||
//
|
||||
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
|
||||
func (api *APIBuilderDI) Trace(relativePath string, handlersFn ...interface{}) *Route {
|
||||
return api.Handle(http.MethodTrace, relativePath, handlersFn...)
|
||||
}
|
||||
|
||||
// Any registers a route for ALL of the HTTP methods:
|
||||
// Get
|
||||
// Post
|
||||
// Put
|
||||
// Delete
|
||||
// Head
|
||||
// Patch
|
||||
// Options
|
||||
// Connect
|
||||
// Trace
|
||||
func (api *APIBuilderDI) Any(relativePath string, handlersFn ...interface{}) (routes []*Route) {
|
||||
handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
|
||||
|
||||
for _, m := range AllMethods {
|
||||
r := api.Self.HandleMany(m, relativePath, handlers...)
|
||||
routes = append(routes, r...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -3,7 +3,6 @@ package router
|
|||
import (
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/core/errgroup"
|
||||
"github.com/kataras/iris/v12/hero"
|
||||
"github.com/kataras/iris/v12/macro"
|
||||
)
|
||||
|
||||
|
@ -12,6 +11,9 @@ import (
|
|||
//
|
||||
// Look the "APIBuilder" for its implementation.
|
||||
type Party interface {
|
||||
// DI returns the APIBuilder featured with Dependency Injection.
|
||||
DI() *APIBuilderDI
|
||||
|
||||
// GetRelPath returns the current party's relative path.
|
||||
// i.e:
|
||||
// if r := app.Party("/users"), then the `r.GetRelPath()` is the "/users".
|
||||
|
@ -57,15 +59,9 @@ type Party interface {
|
|||
// Use appends Handler(s) to the current Party's routes and child routes.
|
||||
// If the current Party is the root, then it registers the middleware to all child Parties' routes too.
|
||||
Use(middleware ...context.Handler)
|
||||
// UseFunc same as "Use" but it accepts dynamic functions as its "handlersFn" input.
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `DoneFunc` and `HandleFunc` for more.
|
||||
UseFunc(handlersFn ...interface{})
|
||||
// Done appends to the very end, Handler(s) to the current Party's routes and child routes.
|
||||
// The difference from .Use is that this/or these Handler(s) are being always running last.
|
||||
Done(handlers ...context.Handler)
|
||||
// DoneFunc same as "Done" but it accepts dynamic functions as its "handlersFn" input.
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc` and `HandleFunc` for more.
|
||||
DoneFunc(handlersFn ...interface{})
|
||||
// Reset removes all the begin and done handlers that may derived from the parent party via `Use` & `Done`,
|
||||
// and the execution rules.
|
||||
// Note that the `Reset` will not reset the handlers that are registered via `UseGlobal` & `DoneGlobal`.
|
||||
|
@ -108,53 +104,6 @@ type Party interface {
|
|||
// Available values are: RouteOverride (the default one), RouteSkip and RouteError.
|
||||
SetRegisterRule(rule RouteRegisterRule) Party
|
||||
|
||||
// GetContainer returns the DI Container of this Party.
|
||||
// Use it to manually convert functions or structs(controllers) to a Handler.
|
||||
//
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
GetContainer() *hero.Container
|
||||
// OnErrorFunc adds an error handler for this Party's DI Hero Container and its handlers (or controllers).
|
||||
// The "errorHandler" handles any error may occurred and returned
|
||||
// during dependencies injection of the Party's hero handlers or from the handlers themselves.
|
||||
//
|
||||
// Same as:
|
||||
// GetContainer().GetErrorHandler = func(ctx iris.Context) hero.ErrorHandler { return errorHandler }
|
||||
//
|
||||
// See `RegisterDependency`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
OnErrorFunc(errorHandler func(context.Context, error))
|
||||
// RegisterDependency adds a dependency.
|
||||
// The value can be a single struct value or a function.
|
||||
// Follow the rules:
|
||||
// * <T>{structValue}
|
||||
// * func(accepts <T>) returns <D> or (<D>, error)
|
||||
// * func(accepts iris.Context) returns <D> or (<D>, error)
|
||||
// * func(accepts1 iris.Context, accepts2 *hero.Input) returns <D> or (<D>, error)
|
||||
//
|
||||
// A Dependency can accept a previous registered dependency and return a new one or the same updated.
|
||||
// * func(accepts1 <D>, accepts2 <T>) returns <E> or (<E>, error) or error
|
||||
// * func(acceptsPathParameter1 string, id uint64) returns <T> or (<T>, error)
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// - RegisterDependency(loggerService{prefix: "dev"})
|
||||
// - RegisterDependency(func(ctx iris.Context) User {...})
|
||||
// - RegisterDependency(func(User) OtherResponse {...})
|
||||
//
|
||||
// See `OnErrorFunc`, `UseFunc`, `DoneFunc` and `HandleFunc` too.
|
||||
RegisterDependency(dependency interface{}) *hero.Dependency
|
||||
// HandleFunc same as `HandleFunc` but it accepts one or more "handlersFn" functions which each one of them
|
||||
// can accept any input arguments that match with the Party's registered Container's `Dependencies` and
|
||||
// any output result; like custom structs <T>, string, []byte, int, error,
|
||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||
//
|
||||
// It's common from a hero handler to not even need to accept a `Context`, for that reason,
|
||||
// the "handlersFn" will call `ctx.Next()` automatically when not called manually.
|
||||
// To stop the execution and not continue to the next "handlersFn"
|
||||
// the end-developer should output an error and return `iris.ErrStopExecution`.
|
||||
//
|
||||
// See `OnErrorFunc`, `RegisterDependency`, `UseFunc` and `DoneFunc` too.
|
||||
HandleFunc(method, relativePath string, handlersFn ...interface{}) *Route
|
||||
|
||||
// Handle registers a route to the server's router.
|
||||
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
|
||||
//
|
||||
|
@ -201,44 +150,52 @@ type Party interface {
|
|||
// Returns the read-only route information.
|
||||
None(path string, handlers ...context.Handler) *Route
|
||||
|
||||
// Get registers a route for the Get http method.
|
||||
// Get registers a route for the Get HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Get(path string, handlers ...context.Handler) *Route
|
||||
// Post registers a route for the Post http method.
|
||||
// Post registers a route for the Post HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Post(path string, handlers ...context.Handler) *Route
|
||||
// Put registers a route for the Put http method.
|
||||
// Put registers a route for the Put HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Put(path string, handlers ...context.Handler) *Route
|
||||
// Delete registers a route for the Delete http method.
|
||||
// Delete registers a route for the Delete HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Delete(path string, handlers ...context.Handler) *Route
|
||||
// Connect registers a route for the Connect http method.
|
||||
// Connect registers a route for the Connect HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Connect(path string, handlers ...context.Handler) *Route
|
||||
// Head registers a route for the Head http method.
|
||||
// Head registers a route for the Head HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Head(path string, handlers ...context.Handler) *Route
|
||||
// Options registers a route for the Options http method.
|
||||
// Options registers a route for the Options HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Options(path string, handlers ...context.Handler) *Route
|
||||
// Patch registers a route for the Patch http method.
|
||||
// Patch registers a route for the Patch HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Patch(path string, handlers ...context.Handler) *Route
|
||||
// Trace registers a route for the Trace http method.
|
||||
// Trace registers a route for the Trace HTTP Method.
|
||||
//
|
||||
// Returns the read-only route information.
|
||||
Trace(path string, handlers ...context.Handler) *Route
|
||||
// Any registers a route for ALL of the http methods
|
||||
// (Get,Post,Put,Head,Patch,Options,Connect,Delete).
|
||||
// Any registers a route for ALL of the HTTP methods:
|
||||
// Get
|
||||
// Post
|
||||
// Put
|
||||
// Delete
|
||||
// Head
|
||||
// Patch
|
||||
// Options
|
||||
// Connect
|
||||
// Trace
|
||||
Any(registeredPath string, handlers ...context.Handler) []*Route
|
||||
// CreateRoutes returns a list of Party-based Routes.
|
||||
// It does NOT registers the route. Use `Handle, Get...` methods instead.
|
||||
|
|
|
@ -118,8 +118,8 @@ func getBindingsFor(inputs []reflect.Type, deps []*Dependency, paramsCount int)
|
|||
// That way the above will work as expected:
|
||||
// 1. mvc.New(app.Party("/path/{firstparam}")).Handle(....Controller.GetBy(secondparam string))
|
||||
// 2. mvc.New(app.Party("/path/{firstparam}/{secondparam}")).Handle(...Controller.GetBy(firstparam, secondparam string))
|
||||
// 3. usersRouter := app.Party("/users/{id:uint64}"); usersRouter.HandleFunc(method, "/", handler(id uint64))
|
||||
// 4. usersRouter.Party("/friends").HandleFunc(method, "/{friendID:uint64}", handler(friendID uint64))
|
||||
// 3. usersRouter := app.Party("/users/{id:uint64}"); usersRouter.DI().Handle(method, "/", handler(id uint64))
|
||||
// 4. usersRouter.Party("/friends").DI().Handle(method, "/{friendID:uint64}", handler(friendID uint64))
|
||||
//
|
||||
// Therefore, count the inputs that can be path parameters first.
|
||||
shouldBindParams := make(map[int]struct{})
|
||||
|
|
|
@ -221,15 +221,15 @@ func TestHandlerPathParams(t *testing.T) {
|
|||
}
|
||||
|
||||
app.PartyFunc("/users", func(r iris.Party) {
|
||||
r.HandleFunc(iris.MethodGet, "/{id:uint64}", handler)
|
||||
r.DI().Get("/{id:uint64}", handler)
|
||||
})
|
||||
|
||||
app.PartyFunc("/editors/{id:uint64}", func(r iris.Party) {
|
||||
r.HandleFunc(iris.MethodGet, "/", handler)
|
||||
r.DI().Get("/", handler)
|
||||
})
|
||||
|
||||
// should receive the last one, as we expected only one useful for MVC (there is a similar test there too).
|
||||
app.HandleFunc(iris.MethodGet, "/{ownerID:uint64}/book/{booKID:uint64}", handler)
|
||||
app.DI().Get("/{ownerID:uint64}/book/{booKID:uint64}", handler)
|
||||
|
||||
e := httptest.New(t, app)
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ func newApp(subRouter router.Party, container *hero.Container) *Application {
|
|||
//
|
||||
// Example: `New(app.Party("/todo"))` or `New(app)` as it's the same as `New(app.Party("/"))`.
|
||||
func New(party router.Party) *Application {
|
||||
return newApp(party, party.GetContainer())
|
||||
return newApp(party, party.DI().Container)
|
||||
}
|
||||
|
||||
// Configure creates a new controller and configures it,
|
||||
|
|
Loading…
Reference in New Issue
Block a user