diff --git a/_examples/routing/basic/main.go b/_examples/routing/basic/main.go index 8a6c29f1..df40290f 100644 --- a/_examples/routing/basic/main.go +++ b/_examples/routing/basic/main.go @@ -4,7 +4,7 @@ import ( "github.com/kataras/iris" ) -func main() { +func newApp() *iris.Application { app := iris.New() app.Logger().SetLevel("debug") @@ -63,8 +63,6 @@ func main() { /u/abcd123 maps to :string */ - app.Get("/donate", donateHandler, donateFinishHandler) - // Pssst, don't forget dynamic-path example for more "magic"! app.Get("/api/users/{userid:uint64 min(1)}", func(ctx iris.Context) { userID, err := ctx.Params().GetUint64("userid") @@ -129,8 +127,9 @@ func main() { { // braces are optional, it's just type of style, to group the routes visually. // http://v1.localhost:8080 + // Note: for versioning-specific features checkout the _examples/versioning instead. v1.Get("/", func(ctx iris.Context) { - ctx.HTML("Version 1 API. go to /api/users") + ctx.HTML(`Version 1 API. go to /api/users`) }) usersAPI := v1.Party("/api/users") @@ -154,9 +153,14 @@ func main() { }) } + return app +} + +func main() { + app := newApp() + // http://localhost:8080 // http://localhost:8080/home - // http://localhost:8080/donate // http://localhost:8080/api/users/42 // http://localhost:8080/admin // http://localhost:8080/admin/login @@ -183,24 +187,6 @@ func adminMiddleware(ctx iris.Context) { ctx.Next() // to move to the next handler, or don't that if you have any auth logic. } -func donateHandler(ctx iris.Context) { - ctx.Writef("Just like an inline handler, but it can be " + - "used by other package, anywhere in your project.") - - // let's pass a value to the next handler - // Values is the way handlers(or middleware) are communicating between each other. - ctx.Values().Set("donate_url", "https://github.com/kataras/iris#-people") - ctx.Next() // in order to execute the next handler in the chain, look donate route. -} - -func donateFinishHandler(ctx iris.Context) { - // values can be any type of object so we could cast the value to a string - // but iris provides an easy to do that, if donate_url is not defined, then it returns an empty string instead. - donateURL := ctx.Values().GetString("donate_url") - ctx.Application().Logger().Infof("donate_url value was: " + donateURL) - ctx.Writef("\n\nDonate sent(?).") -} - func notFoundHandler(ctx iris.Context) { ctx.HTML("Custom route for 404 not found http code, here you can render a view, html, json any valid response.") } diff --git a/_examples/routing/basic/main_test.go b/_examples/routing/basic/main_test.go new file mode 100644 index 00000000..e539dbe3 --- /dev/null +++ b/_examples/routing/basic/main_test.go @@ -0,0 +1,86 @@ +package main + +import ( + "fmt" + "testing" + + "github.com/kataras/iris/httptest" +) + +// Shows a very basic usage of the httptest. +// The tests are written in a way to be easy to understand, +// for a more comprehensive testing examples check out the: +// _examples/routing/main_test.go, +// _examples/subdomains/www/main_test.go +// _examples/file-server and e.t.c. +// Almost every example which covers +// a new feature from you to learn +// contains a test file as well. +func TestRoutingBasic(t *testing.T) { + expectedUResponse := func(paramName, paramType, paramValue string) string { + s := fmt.Sprintf("before %s (%s), current route name: GET/u/{%s:%s}\n", paramName, paramType, paramName, paramType) + s += fmt.Sprintf("%s (%s): %s", paramName, paramType, paramValue) + return s + } + + var ( + expectedNotFoundResponse = "Custom route for 404 not found http code, here you can render a view, html, json any valid response." + + expectedIndexResponse = "Hello from /" + expectedHomeResponse = `Same as app.Handle("GET", "/", [...])` + + expectedUStringResponse = expectedUResponse("username", "string", "abcd123") + expectedUIntResponse = expectedUResponse("id", "int", "-1") + expectedUUintResponse = expectedUResponse("uid", "uint", "42") + expectedUAlphabeticalResponse = expectedUResponse("firstname", "alphabetical", "abcd") + + expectedAPIUsersIndexResponse = map[string]interface{}{"user_id": 42} + + expectedAdminIndexResponse = "

Hello from admin/

" + + expectedSubdomainV1IndexResponse = `Version 1 API. go to /api/users` + expectedSubdomainV1APIUsersIndexResponse = "All users" + expectedSubdomainV1APIUsersIndexWithParamResponse = "user with id: 42" + + expectedSubdomainWildcardIndexResponse = "Subdomain can be anything, now you're here from: any-subdomain-here" + ) + + app := newApp() + e := httptest.New(t, app) + + e.GET("/anotfound").Expect().Status(httptest.StatusNotFound). + Body().Equal(expectedNotFoundResponse) + + e.GET("/").Expect().Status(httptest.StatusOK). + Body().Equal(expectedIndexResponse) + e.GET("/home").Expect().Status(httptest.StatusOK). + Body().Equal(expectedHomeResponse) + + e.GET("/u/abcd123").Expect().Status(httptest.StatusOK). + Body().Equal(expectedUStringResponse) + e.GET("/u/-1").Expect().Status(httptest.StatusOK). + Body().Equal(expectedUIntResponse) + e.GET("/u/42").Expect().Status(httptest.StatusOK). + Body().Equal(expectedUUintResponse) + e.GET("/u/abcd").Expect().Status(httptest.StatusOK). + Body().Equal(expectedUAlphabeticalResponse) + + e.GET("/api/users/42").Expect().Status(httptest.StatusOK). + JSON().Equal(expectedAPIUsersIndexResponse) + + e.GET("/admin").Expect().Status(httptest.StatusOK). + Body().Equal(expectedAdminIndexResponse) + + e.Request("GET", "/").WithURL("http://v1.example.com").Expect().Status(httptest.StatusOK). + Body().Equal(expectedSubdomainV1IndexResponse) + + e.Request("GET", "/api/users").WithURL("http://v1.example.com").Expect().Status(httptest.StatusOK). + Body().Equal(expectedSubdomainV1APIUsersIndexResponse) + + e.Request("GET", "/api/users/42").WithURL("http://v1.example.com").Expect().Status(httptest.StatusOK). + Body().Equal(expectedSubdomainV1APIUsersIndexWithParamResponse) + + e.Request("GET", "/").WithURL("http://any-subdomain-here.example.com").Expect().Status(httptest.StatusOK). + Body().Equal(expectedSubdomainWildcardIndexResponse) + +} diff --git a/_examples/routing/main.go b/_examples/routing/main.go index 9f450327..ccd35c9e 100644 --- a/_examples/routing/main.go +++ b/_examples/routing/main.go @@ -1,8 +1,6 @@ package main import ( - "io/ioutil" - "github.com/kataras/iris" ) @@ -108,7 +106,7 @@ func newApp() *iris.Application { // to protect ourselves from "over heating". app.Post("/", iris.LimitRequestBodySize(maxBodySize), func(ctx iris.Context) { // get request body - b, err := ioutil.ReadAll(ctx.Request().Body) + b, err := ctx.GetBody() // if is larger then send a bad request status if err != nil { ctx.StatusCode(iris.StatusBadRequest) diff --git a/core/router/handler.go b/core/router/handler.go index 894fefd0..b63d0979 100644 --- a/core/router/handler.go +++ b/core/router/handler.go @@ -85,6 +85,13 @@ func (h *routerHandler) Build(provider RoutesProvider) error { rp := errors.NewReporter() registeredRoutes := provider.GetRoutes() + // before sort. + for _, r := range registeredRoutes { + if r.topLink != nil { + bindMultiParamTypesHandler(r.topLink, r) + } + } + // sort, subdomains go first. sort.Slice(registeredRoutes, func(i, j int) bool { first, second := registeredRoutes[i], registeredRoutes[j] @@ -116,12 +123,6 @@ func (h *routerHandler) Build(provider RoutesProvider) error { return lsub1 > lsub2 }) - for _, r := range registeredRoutes { - if r.topLink != nil { - bindMultiParamTypesHandler(r.topLink, r) - } - } - for _, r := range registeredRoutes { if r.Subdomain != "" { h.hosts = true