.DI() to ConfigureContainer(...builders)

Former-commit-id: 169671a8b5b706dc8f136e68c1a060f27a2c421b
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-04-17 15:56:36 +03:00
parent eafa63da50
commit 1bb76853a9
12 changed files with 108 additions and 65 deletions

View File

@ -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 - accept one or more path parameters and request data, a payload
- send back a response, a payload (JSON, XML,...) - 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.DI() *APIBuilderDI` method which returns methods such as `DI.Handle(method, relativePath string, handlersFn ...interface{}) *Route` and `DI.RegisterDependency`. 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.ConfigureContainer(builder ...func(*iris.APIContainer)) *APIContainer` method which returns methods such as `Handle(method, relativePath string, handlersFn ...interface{}) *Route` and `RegisterDependency`.
Look how clean your codebase can be when using Iris': Look how clean your codebase can be when using Iris':
@ -63,12 +63,14 @@ func handler(id int, in testInput) testOutput {
func main() { func main() {
app := iris.New() app := iris.New()
app.DI().Handle(iris.MethodPost, "/{id:int}", handler) app.ConfigureContainer(func(api *iris.APIContainer) {
api.Post("/{id:int}", handler)
})
app.Listen(":5000", iris.WithOptimizations) 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.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: 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. Here is a quick list of the new Party.ConfigureContainer()'s fields and methods:
```go ```go
// Container holds the DI Container of this Party featured Dependency Injection. // Container holds the DI Container of this Party featured Dependency Injection.
@ -122,6 +124,10 @@ Done(handlersFn ...interface{})
// To stop the execution and not continue to the next "handlersFn" // To stop the execution and not continue to the next "handlersFn"
// the end-developer should output an error and return `iris.ErrStopExecution`. // the end-developer should output an error and return `iris.ErrStopExecution`.
Handle(method, relativePath string, handlersFn ...interface{}) *Route Handle(method, relativePath string, handlersFn ...interface{}) *Route
// Get registers a GET route, same as `Handle("GET", relativePath, handlersFn....)`.
Get(relativePath string, handlersFn ...interface{}) *Route
// and so on...
``` ```
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: 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:
@ -165,7 +171,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. - `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.DI().Handle`) do not have to require `iris.Context` just to call `ctx.Next()` anymore, this is done automatically now. - Hero Handlers (and `app.ConfigureContainer().Handle`) do not have to require `iris.Context` just to call `ctx.Next()` anymore, this is done automatically now.
New Context Methods: New Context Methods:

View File

@ -22,6 +22,8 @@ func handler(id int, in testInput) testOutput {
func main() { func main() {
app := iris.New() app := iris.New()
app.DI().Post("/{id:int}", handler) app.ConfigureContainer(func(api *iris.APIContainer) {
api.Post("/{id:int}", handler)
})
app.Listen(":8080") app.Listen(":8080")
} }

View File

@ -46,11 +46,10 @@ func newApp() *iris.Application {
// a JSON and 200 status code // a JSON and 200 status code
// or 202 status code and empty body // or 202 status code and empty body
// or a 409 status code and "my_error" body. // or a 409 status code and "my_error" body.
di := app.DI() app.ConfigureContainer(func(api *iris.APIContainer) {
{ api.Use(middleware)
di.Use(middleware) api.Post("/{id:int}", handler)
di.Post("/{id:int}", handler) })
}
app.Configure( app.Configure(
iris.WithOptimizations, /* optional */ iris.WithOptimizations, /* optional */

View File

@ -1994,18 +1994,19 @@ func (ctx *context) GetContentType() string {
return ctx.writer.Header().Get(ContentTypeHeaderKey) return ctx.writer.Header().Get(ContentTypeHeaderKey)
} }
func trimHeaderValue(cType string) string { // TrimHeaderValue returns the "v[0:first space or semicolon]".
for i, char := range cType { func TrimHeaderValue(v string) string {
for i, char := range v {
if char == ' ' || char == ';' { if char == ' ' || char == ';' {
return cType[:i] return v[:i]
} }
} }
return cType return v
} }
// GetContentType returns the request's header value of "Content-Type". // GetContentType returns the request's header value of "Content-Type".
func (ctx *context) GetContentTypeRequested() string { func (ctx *context) GetContentTypeRequested() string {
return trimHeaderValue(ctx.GetHeader(ContentTypeHeaderKey)) return TrimHeaderValue(ctx.GetHeader(ContentTypeHeaderKey))
} }
// GetContentLength returns the request's header value of "Content-Length". // GetContentLength returns the request's header value of "Content-Length".

View File

@ -113,7 +113,7 @@ func (repo *repository) register(route *Route, rule RouteRegisterRule) (*Route,
// and child routers. // and child routers.
type APIBuilder struct { type APIBuilder struct {
// the per-party APIBuilder with DI. // the per-party APIBuilder with DI.
apiBuilderDI *APIBuilderDI apiBuilderDI *APIContainer
// the api builder global macros registry // the api builder global macros registry
macros *macro.Macros macros *macro.Macros
@ -171,7 +171,7 @@ func NewAPIBuilder() *APIBuilder {
routes: new(repository), routes: new(repository),
} }
api.apiBuilderDI = &APIBuilderDI{ api.apiBuilderDI = &APIContainer{
Self: api, Self: api,
Container: hero.New(), Container: hero.New(),
} }
@ -179,8 +179,22 @@ func NewAPIBuilder() *APIBuilder {
return api return api
} }
// DI returns the APIBuilder featured with Dependency Injection. // ConfigureContainer accepts one or more functions that can be used
func (api *APIBuilder) DI() *APIBuilderDI { // to configure dependency injection features of this Party
// such as register dependency and register handlers that will automatically inject any valid dependency.
// However, if the "builder" parameter is nil or not provided then it just returns the *APIContainer,
// which automatically initialized on Party allocation.
//
// It returns the same `APIBuilder` featured with Dependency Injection.
func (api *APIBuilder) ConfigureContainer(builder ...func(*APIContainer)) *APIContainer {
for _, b := range builder {
if b == nil {
continue
}
b(api.apiBuilderDI)
}
return api.apiBuilderDI return api.apiBuilderDI
} }
@ -529,7 +543,7 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
// based on the fullpath. // based on the fullpath.
childContainer := api.apiBuilderDI.Container.Clone() childContainer := api.apiBuilderDI.Container.Clone()
childAPI.apiBuilderDI = &APIBuilderDI{ childAPI.apiBuilderDI = &APIContainer{
Self: childAPI, Self: childAPI,
Container: childContainer, Container: childContainer,
} }

View File

@ -8,8 +8,9 @@ import (
"github.com/kataras/iris/v12/macro" "github.com/kataras/iris/v12/macro"
) )
// APIBuilderDI is a wrapper of a common `Party` features Dependency Injection. // APIContainer is a wrapper of a common `Party` featured by Dependency Injection.
type APIBuilderDI struct { // See `Party.ConfigureContainer` for more.
type APIContainer struct {
// Self returns the original `Party` without DI features. // Self returns the original `Party` without DI features.
Self Party Self Party
@ -17,12 +18,12 @@ type APIBuilderDI struct {
Container *hero.Container Container *hero.Container
} }
// Party returns a child of this `APIBuilderDI` featured with Dependency Injection. // Party returns a child of this `APIContainer` featured with Dependency Injection.
// Like the `Self.Party` method does for the common Router Groups. // Like the `Self.Party` method does for the common Router Groups.
func (api *APIBuilderDI) Party(relativePath string, handlersFn ...interface{}) *APIBuilderDI { func (api *APIContainer) Party(relativePath string, handlersFn ...interface{}) *APIContainer {
handlers := api.convertHandlerFuncs(relativePath, handlersFn...) handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
p := api.Self.Party(relativePath, handlers...) p := api.Self.Party(relativePath, handlers...)
return p.DI() return p.ConfigureContainer()
} }
// OnError 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).
@ -33,7 +34,7 @@ func (api *APIBuilderDI) Party(relativePath string, handlersFn ...interface{}) *
// Container.GetErrorHandler = func(ctx iris.Context) hero.ErrorHandler { return errorHandler } // Container.GetErrorHandler = func(ctx iris.Context) hero.ErrorHandler { return errorHandler }
// //
// See `RegisterDependency`, `Use`, `Done` and `Handle` too. // See `RegisterDependency`, `Use`, `Done` and `Handle` too.
func (api *APIBuilderDI) OnError(errorHandler func(context.Context, error)) { func (api *APIContainer) OnError(errorHandler func(context.Context, error)) {
errHandler := hero.ErrorHandlerFunc(errorHandler) errHandler := hero.ErrorHandlerFunc(errorHandler)
api.Container.GetErrorHandler = func(ctx context.Context) hero.ErrorHandler { api.Container.GetErrorHandler = func(ctx context.Context) hero.ErrorHandler {
return errHandler return errHandler
@ -59,12 +60,12 @@ func (api *APIBuilderDI) OnError(errorHandler func(context.Context, error)) {
// - RegisterDependency(func(User) OtherResponse {...}) // - RegisterDependency(func(User) OtherResponse {...})
// //
// See `OnError`, `Use`, `Done` and `Handle` too. // See `OnError`, `Use`, `Done` and `Handle` too.
func (api *APIBuilderDI) RegisterDependency(dependency interface{}) *hero.Dependency { func (api *APIContainer) RegisterDependency(dependency interface{}) *hero.Dependency {
return api.Container.Register(dependency) return api.Container.Register(dependency)
} }
// convertHandlerFuncs accepts Iris hero handlers and returns a slice of native Iris handlers. // convertHandlerFuncs accepts Iris hero handlers and returns a slice of native Iris handlers.
func (api *APIBuilderDI) convertHandlerFuncs(relativePath string, handlersFn ...interface{}) context.Handlers { func (api *APIContainer) convertHandlerFuncs(relativePath string, handlersFn ...interface{}) context.Handlers {
fullpath := api.Self.GetRelPath() + relativePath fullpath := api.Self.GetRelPath() + relativePath
paramsCount := macro.CountParams(fullpath, *api.Self.Macros()) paramsCount := macro.CountParams(fullpath, *api.Self.Macros())
@ -84,14 +85,14 @@ func (api *APIBuilderDI) convertHandlerFuncs(relativePath string, handlersFn ...
// Use same as `Self.Use` but it accepts dynamic functions as its "handlersFn" input. // Use same as `Self.Use` but it accepts dynamic functions as its "handlersFn" input.
// //
// See `OnError`, `RegisterDependency`, `Done` and `Handle` for more. // See `OnError`, `RegisterDependency`, `Done` and `Handle` for more.
func (api *APIBuilderDI) Use(handlersFn ...interface{}) { func (api *APIContainer) Use(handlersFn ...interface{}) {
handlers := api.convertHandlerFuncs("/", handlersFn...) handlers := api.convertHandlerFuncs("/", handlersFn...)
api.Self.Use(handlers...) api.Self.Use(handlers...)
} }
// Done same as `Self.Done` but it accepts dynamic functions as its "handlersFn" input. // Done same as `Self.Done` but it accepts dynamic functions as its "handlersFn" input.
// See `OnError`, `RegisterDependency`, `Use` and `Handle` for more. // See `OnError`, `RegisterDependency`, `Use` and `Handle` for more.
func (api *APIBuilderDI) Done(handlersFn ...interface{}) { func (api *APIContainer) Done(handlersFn ...interface{}) {
handlers := api.convertHandlerFuncs("/", handlersFn...) handlers := api.convertHandlerFuncs("/", handlersFn...)
api.Self.Done(handlers...) api.Self.Done(handlers...)
} }
@ -107,7 +108,7 @@ func (api *APIBuilderDI) Done(handlersFn ...interface{}) {
// the end-developer should output an error and return `iris.ErrStopExecution`. // the end-developer should output an error and return `iris.ErrStopExecution`.
// //
// See `OnError`, `RegisterDependency`, `Use`, `Done`, `Get`, `Post`, `Put`, `Patch` and `Delete` too. // See `OnError`, `RegisterDependency`, `Use`, `Done`, `Get`, `Post`, `Put`, `Patch` and `Delete` too.
func (api *APIBuilderDI) Handle(method, relativePath string, handlersFn ...interface{}) *Route { func (api *APIContainer) Handle(method, relativePath string, handlersFn ...interface{}) *Route {
handlers := api.convertHandlerFuncs(relativePath, handlersFn...) handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
return api.Self.Handle(method, relativePath, handlers...) return api.Self.Handle(method, relativePath, handlers...)
} }
@ -115,63 +116,63 @@ func (api *APIBuilderDI) Handle(method, relativePath string, handlersFn ...inter
// 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. // 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 { func (api *APIContainer) Get(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodGet, relativePath, handlersFn...) return api.Handle(http.MethodGet, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Post(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodPost, relativePath, handlersFn...) return api.Handle(http.MethodPost, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Put(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodPut, relativePath, handlersFn...) return api.Handle(http.MethodPut, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Delete(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodDelete, relativePath, handlersFn...) return api.Handle(http.MethodDelete, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Connect(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodConnect, relativePath, handlersFn...) return api.Handle(http.MethodConnect, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Head(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodHead, relativePath, handlersFn...) return api.Handle(http.MethodHead, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Options(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodOptions, relativePath, handlersFn...) return api.Handle(http.MethodOptions, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Patch(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodPatch, relativePath, handlersFn...) return api.Handle(http.MethodPatch, relativePath, handlersFn...)
} }
// 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. // 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 { func (api *APIContainer) Trace(relativePath string, handlersFn ...interface{}) *Route {
return api.Handle(http.MethodTrace, relativePath, handlersFn...) return api.Handle(http.MethodTrace, relativePath, handlersFn...)
} }
@ -185,7 +186,7 @@ func (api *APIBuilderDI) Trace(relativePath string, handlersFn ...interface{}) *
// Options // Options
// Connect // Connect
// Trace // Trace
func (api *APIBuilderDI) Any(relativePath string, handlersFn ...interface{}) (routes []*Route) { func (api *APIContainer) Any(relativePath string, handlersFn ...interface{}) (routes []*Route) {
handlers := api.convertHandlerFuncs(relativePath, handlersFn...) handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
for _, m := range AllMethods { for _, m := range AllMethods {

View File

@ -9,10 +9,16 @@ import (
// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also. // Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
// Party could also be named as 'Join' or 'Node' or 'Group' , Party chosen because it is fun. // Party could also be named as 'Join' or 'Node' or 'Group' , Party chosen because it is fun.
// //
// Look the "APIBuilder" for its implementation. // Look the `APIBuilder` structure for its implementation.
type Party interface { type Party interface {
// DI returns the APIBuilder featured with Dependency Injection. // ConfigureContainer accepts one or more functions that can be used
DI() *APIBuilderDI // to configure dependency injection features of this Party
// such as register dependency and register handlers that will automatically inject any valid dependency.
// However, if the "builder" parameter is nil or not provided then it just returns the *APIContainer,
// which automatically initialized on Party allocation.
//
// It returns the same `APIBuilder` featured with Dependency Injection.
ConfigureContainer(builder ...func(*APIContainer)) *APIContainer
// GetRelPath returns the current party's relative path. // GetRelPath returns the current party's relative path.
// i.e: // i.e:

View File

@ -83,6 +83,11 @@ type (
// //
// A shortcut for the `core/router#Party`, useful when `PartyFunc` is being used. // A shortcut for the `core/router#Party`, useful when `PartyFunc` is being used.
Party = router.Party Party = router.Party
// APIContainer is a wrapper of a common `Party` featured by Dependency Injection.
// See `Party.ConfigureContainer` for more.
//
// A shortcut for the `core/router#APIContainer`.
APIContainer = router.APIContainer
// DirOptions contains the optional settings that // DirOptions contains the optional settings that
// `FileServer` and `Party#HandleDir` can use to serve files and assets. // `FileServer` and `Party#HandleDir` can use to serve files and assets.
// A shortcut for the `router.DirOptions`, useful when `FileServer` or `HandleDir` is being used. // A shortcut for the `router.DirOptions`, useful when `FileServer` or `HandleDir` is being used.

View File

@ -118,8 +118,8 @@ func getBindingsFor(inputs []reflect.Type, deps []*Dependency, paramsCount int)
// That way the above will work as expected: // That way the above will work as expected:
// 1. mvc.New(app.Party("/path/{firstparam}")).Handle(....Controller.GetBy(secondparam string)) // 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)) // 2. mvc.New(app.Party("/path/{firstparam}/{secondparam}")).Handle(...Controller.GetBy(firstparam, secondparam string))
// 3. usersRouter := app.Party("/users/{id:uint64}"); usersRouter.DI().Handle(method, "/", handler(id uint64)) // 3. usersRouter := app.Party("/users/{id:uint64}"); usersRouter.ConfigureContainer().Handle(method, "/", handler(id uint64))
// 4. usersRouter.Party("/friends").DI().Handle(method, "/{friendID:uint64}", handler(friendID uint64)) // 4. usersRouter.Party("/friends").ConfigureContainer().Handle(method, "/{friendID:uint64}", handler(friendID uint64))
// //
// Therefore, count the inputs that can be path parameters first. // Therefore, count the inputs that can be path parameters first.
shouldBindParams := make(map[int]struct{}) shouldBindParams := make(map[int]struct{})

View File

@ -4,6 +4,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/golang/protobuf/proto"
"github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/context"
"github.com/fatih/structs" "github.com/fatih/structs"
@ -323,21 +324,29 @@ func dispatchCommon(ctx context.Context,
return nil return nil
} }
var err error switch context.TrimHeaderValue(contentType) {
case context.ContentXMLHeaderValue:
_, err := ctx.XML(v)
return err
case context.ContentYAMLHeaderValue:
_, err := ctx.YAML(v)
return err
case context.ContentProtobufHeaderValue:
msg, ok := v.(proto.Message)
if !ok {
return context.ErrContentNotSupported
}
if strings.HasPrefix(contentType, context.ContentJavascriptHeaderValue) { _, err := ctx.Protobuf(msg)
_, err = ctx.JSONP(v) return err
} else if strings.HasPrefix(contentType, context.ContentXMLHeaderValue) { case context.ContentMsgPackHeaderValue, context.ContentMsgPack2HeaderValue:
_, err = ctx.XML(v) _, err := ctx.MsgPack(v)
// no need: context.XML{Indent: " "}), after v12.2, return err
// if not iris.WithOptimizations passed and indent is empty then it sets it to two spaces for JSON, JSONP and XML, default:
// otherwise given indentation. // otherwise default to JSON.
} else { _, err := ctx.JSON(v)
// defaults to json if content type is missing or its application/json. return err
_, err = ctx.JSON(v)
} }
return err
} }
ctx.ContentType(contentType) ctx.ContentType(contentType)

View File

@ -220,16 +220,16 @@ func TestHandlerPathParams(t *testing.T) {
return fmt.Sprintf("%d", id) return fmt.Sprintf("%d", id)
} }
app.PartyFunc("/users", func(r iris.Party) { app.Party("/users").ConfigureContainer(func(api *iris.APIContainer) {
r.DI().Get("/{id:uint64}", handler) api.Get("/{id:uint64}", handler)
}) })
app.PartyFunc("/editors/{id:uint64}", func(r iris.Party) { app.Party("/editors/{id:uint64}").ConfigureContainer(func(api *iris.APIContainer) {
r.DI().Get("/", handler) api.Get("/", handler)
}) })
// should receive the last one, as we expected only one useful for MVC (there is a similar test there too). // should receive the last one, as we expected only one useful for MVC (there is a similar test there too).
app.DI().Get("/{ownerID:uint64}/book/{booKID:uint64}", handler) app.ConfigureContainer().Get("/{ownerID:uint64}/book/{booKID:uint64}", handler)
e := httptest.New(t, app) e := httptest.New(t, app)

View File

@ -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("/"))`. // Example: `New(app.Party("/todo"))` or `New(app)` as it's the same as `New(app.Party("/"))`.
func New(party router.Party) *Application { func New(party router.Party) *Application {
return newApp(party, party.DI().Container) return newApp(party, party.ConfigureContainer().Container)
} }
// Configure creates a new controller and configures it, // Configure creates a new controller and configures it,