Hey, dude, why not just use those popular approaches, like file-based config? We know you'll be asking & we have the answer as well, [here](http://12factor.net/config). | Hey, dude, why not just use those popular approaches, like file-based config? We know you'll be asking & we have the answer as well, [here](http://12factor.net/config). | ||||
## Modules | |||||
## Middleware | |||||
Modules (aka. middleware) work between http requests and the router, they are no different than the standard http.Handler. Existing modules from other frameworks like logging, authorization, session, gzipping are very easy to integrate into Rex. As long as it complies the standard `func(http.Handler) http.Handler` signature, you can simply add one like this: | |||||
Middlware modules work between http requests and the router, they are no different than the standard http.Handler. Existing middleware modules from other frameworks like logging, authorization, session, gzipping are very easy to integrate into Rex. As long as it complies the standard `func(http.Handler) http.Handler` signature, you can simply add one like this: | |||||
``` go | ``` go | ||||
app.Use(modules.XSRF) | |||||
app.Use(middleware.XSRF) | |||||
``` | ``` | ||||
Since a module is just the standard http.Handler, writing a custom module is also pretty straightforward: | |||||
Since a middleware module is just the standard http.Handler, writing custom middleware is also pretty straightforward: | |||||
``` go | ``` go | ||||
app.Use(func(next http.Handler) http.Handler { | app.Use(func(next http.Handler) http.Handler { | ||||
- [X] Hot-Compile Runner | - [X] Hot-Compile Runner | ||||
- [X] Live Reload Integration | - [X] Live Reload Integration | ||||
- [X] Common Modules | - [X] Common Modules | ||||
- [X] Continuous Integration | |||||
- [ ] Full Test Converage | - [ ] Full Test Converage | ||||
- [ ] Improved Template Rendering | - [ ] Improved Template Rendering | ||||
- [ ] Project Wiki | - [ ] Project Wiki | ||||
- [ ] Continuous Integration | |||||
- [ ] Stable API | - [ ] Stable API |
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
* ----------------------------------------------------------------------*/ | * ----------------------------------------------------------------------*/ | ||||
package modules | |||||
package middleware | |||||
import "net/http" | import "net/http" | ||||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
* ----------------------------------------------------------------------*/ | * ----------------------------------------------------------------------*/ | ||||
package modules | |||||
package middleware | |||||
import ( | import ( | ||||
"bytes" | "bytes" |
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
* ----------------------------------------------------------------------*/ | * ----------------------------------------------------------------------*/ | ||||
package modules | |||||
package middleware | |||||
import "net/http" | import "net/http" | ||||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
* ----------------------------------------------------------------------*/ | * ----------------------------------------------------------------------*/ | ||||
package modules | |||||
package middleware | |||||
import ( | import ( | ||||
"net/http" | "net/http" |
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
* ----------------------------------------------------------------------*/ | * ----------------------------------------------------------------------*/ | ||||
package modules | |||||
package middleware | |||||
import ( | import ( | ||||
"net/http" | "net/http" |
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
* ----------------------------------------------------------------------*/ | * ----------------------------------------------------------------------*/ | ||||
package modules | |||||
package middleware | |||||
import ( | import ( | ||||
"bytes" | "bytes" |
/* ---------------------------------------------------------------------- | |||||
* ______ ___ __ | |||||
* / ____/___ / | ____ __ ___ __/ /_ ___ ________ | |||||
* / / __/ __ \/ /| | / __ \/ / / / | /| / / __ \/ _ \/ ___/ _ \ | |||||
* / /_/ / /_/ / ___ |/ / / / /_/ /| |/ |/ / / / / __/ / / __/ | |||||
* \____/\____/_/ |_/_/ /_/\__. / |__/|__/_/ /_/\___/_/ \___/ | |||||
* /____/ | |||||
* | |||||
* (C) Copyright 2015 GoAnywhere (http://goanywhere.io). | |||||
* ---------------------------------------------------------------------- | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
* ----------------------------------------------------------------------*/ | |||||
package rex | |||||
import "net/http" | |||||
type module struct { | |||||
cache http.Handler | |||||
stack []func(http.Handler) http.Handler | |||||
} | |||||
// build sets up the whole middleware modules in a FIFO chain. | |||||
func (self *module) build() http.Handler { | |||||
if self.cache == nil { | |||||
var next http.Handler = http.DefaultServeMux | |||||
// Activate modules in FIFO order. | |||||
for index := len(self.stack) - 1; index >= 0; index-- { | |||||
next = self.stack[index](next) | |||||
} | |||||
self.cache = next | |||||
} | |||||
return self.cache | |||||
} | |||||
// Use add the middleware module into the stack chain. | |||||
func (self *module) Use(modules ...func(http.Handler) http.Handler) { | |||||
self.stack = append(self.stack, modules...) | |||||
} | |||||
// Implements the net/http Handler interface and calls the middleware stack. | |||||
func (self *module) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||
self.build().ServeHTTP(w, r) | |||||
} |
/* ---------------------------------------------------------------------- | |||||
* ______ ___ __ | |||||
* / ____/___ / | ____ __ ___ __/ /_ ___ ________ | |||||
* / / __/ __ \/ /| | / __ \/ / / / | /| / / __ \/ _ \/ ___/ _ \ | |||||
* / /_/ / /_/ / ___ |/ / / / /_/ /| |/ |/ / / / / __/ / / __/ | |||||
* \____/\____/_/ |_/_/ /_/\__. / |__/|__/_/ /_/\___/_/ \___/ | |||||
* /____/ | |||||
* | |||||
* (C) Copyright 2015 GoAnywhere (http://goanywhere.io). | |||||
* ---------------------------------------------------------------------- | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
* ----------------------------------------------------------------------*/ | |||||
package modules |
"runtime" | "runtime" | ||||
"github.com/goanywhere/rex/internal" | "github.com/goanywhere/rex/internal" | ||||
"github.com/goanywhere/rex/modules" | |||||
mw "github.com/goanywhere/rex/middleware" | |||||
"github.com/goanywhere/x/env" | "github.com/goanywhere/x/env" | ||||
"github.com/goanywhere/x/fs" | "github.com/goanywhere/x/fs" | ||||
) | ) | ||||
return DefaultMux.Group(path) | return DefaultMux.Group(path) | ||||
} | } | ||||
// FileServer registers a handler to serve HTTP requests | |||||
// with the contents of the file system rooted at root. | |||||
/* | |||||
func FileServer(prefix, dir string) { | |||||
DefaultMux.FileServer(prefix, dir) | |||||
} | |||||
*/ | |||||
// Use appends middleware module into the serving list, modules will be served in FIFO order. | // Use appends middleware module into the serving list, modules will be served in FIFO order. | ||||
func Use(module func(http.Handler) http.Handler) { | func Use(module func(http.Handler) http.Handler) { | ||||
DefaultMux.Use(module) | DefaultMux.Use(module) | ||||
} | } | ||||
func Run() { | func Run() { | ||||
DefaultMux.Use(modules.Logger) | |||||
DefaultMux.Use(mw.Logger) | |||||
DefaultMux.Run() | DefaultMux.Run() | ||||
} | } | ||||
"github.com/gorilla/mux" | "github.com/gorilla/mux" | ||||
) | ) | ||||
type middleware struct { | |||||
cache http.Handler | |||||
stack []func(http.Handler) http.Handler | |||||
} | |||||
// build sets up the whole middleware modules in a FIFO chain. | |||||
func (self *middleware) build() http.Handler { | |||||
if self.cache == nil { | |||||
var next http.Handler = http.DefaultServeMux | |||||
// Activate modules in FIFO order. | |||||
for index := len(self.stack) - 1; index >= 0; index-- { | |||||
next = self.stack[index](next) | |||||
} | |||||
self.cache = next | |||||
} | |||||
return self.cache | |||||
} | |||||
// Use add the middleware module into the stack chain. | |||||
func (self *middleware) Use(modules ...func(http.Handler) http.Handler) { | |||||
self.stack = append(self.stack, modules...) | |||||
} | |||||
// Implements the net/http Handler interface and calls the middleware stack. | |||||
func (self *middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||
self.build().ServeHTTP(w, r) | |||||
} | |||||
type Router struct { | type Router struct { | ||||
module *module | |||||
middleware *middleware | |||||
mux *mux.Router | mux *mux.Router | ||||
ready bool | ready bool | ||||
subrouters []*Router | subrouters []*Router | ||||
func New() *Router { | func New() *Router { | ||||
return &Router{ | return &Router{ | ||||
module: new(module), | |||||
mux: mux.NewRouter().StrictSlash(true), | |||||
middleware: new(middleware), | |||||
mux: mux.NewRouter().StrictSlash(true), | |||||
} | } | ||||
} | } | ||||
if !self.ready { | if !self.ready { | ||||
self.ready = true | self.ready = true | ||||
// * activate router's middleware modules. | // * activate router's middleware modules. | ||||
self.module.Use(func(http.Handler) http.Handler { | |||||
self.middleware.Use(func(http.Handler) http.Handler { | |||||
return self.mux | return self.mux | ||||
}) | }) | ||||
// * activate subrouters's middleware modules. | // * activate subrouters's middleware modules. | ||||
for index := 0; index < len(self.subrouters); index++ { | for index := 0; index < len(self.subrouters); index++ { | ||||
sr := self.subrouters[index] | sr := self.subrouters[index] | ||||
sr.module.Use(func(http.Handler) http.Handler { | |||||
sr.middleware.Use(func(http.Handler) http.Handler { | |||||
return sr.mux | return sr.mux | ||||
}) | }) | ||||
} | } | ||||
} | } | ||||
return self.module | |||||
return self.middleware | |||||
} | } | ||||
// register adds the http.Handler/http.HandleFunc into Gorilla mux. | // register adds the http.Handler/http.HandleFunc into Gorilla mux. | ||||
// Group creates a new application group under the given path prefix. | // Group creates a new application group under the given path prefix. | ||||
func (self *Router) Group(prefix string) *Router { | func (self *Router) Group(prefix string) *Router { | ||||
var module = new(module) | |||||
self.mux.PathPrefix(prefix).Handler(module) | |||||
var middleware = new(middleware) | |||||
self.mux.PathPrefix(prefix).Handler(middleware) | |||||
var mux = self.mux.PathPrefix(prefix).Subrouter() | var mux = self.mux.PathPrefix(prefix).Subrouter() | ||||
router := &Router{module: module, mux: mux} | |||||
router := &Router{middleware: middleware, mux: mux} | |||||
self.subrouters = append(self.subrouters, router) | self.subrouters = append(self.subrouters, router) | ||||
return router | return router | ||||
} | } | ||||
// Use add the middleware module into the stack chain. | // Use add the middleware module into the stack chain. | ||||
func (self *Router) Use(module func(http.Handler) http.Handler) { | func (self *Router) Use(module func(http.Handler) http.Handler) { | ||||
self.module.Use(module) | |||||
self.middleware.Use(module) | |||||
} | } | ||||
// ServeHTTP dispatches the request to the handler whose | // ServeHTTP dispatches the request to the handler whose |