Services are objects that are available to be injected into a handler's argument list. You can map a service on a Global or Request level.
A Macaron instance implements the inject.Injector
interface, so mapping a service is easy:
db := &MyDatabase{}m := macaron.Classic()m.Map(db) // Service will be available to all handlers as *MyDatabasem.Get("/", func(db *MyDatabase) {// Operations with db.})m.Run()
Mapping on the request level can be done in a handler via *macaron.Context
:
func MyCustomLoggerHandler(ctx *macaron.Context) {logger := &MyCustomLogger{ctx.Req}ctx.Map(logger) // mapped as *MyCustomLogger}func main() {//...m.Get("/", MyCustomLoggerHandler, func(logger *MyCustomLogger) {// Operations with logger.})m.Get("/panic", func(logger *MyCustomLogger) {// This will panic because no logger service maps to this request.})//...}
One of the most powerful parts about services is the ability to map a service to an interface. For instance, if you wanted to override the http.ResponseWriter
with an object that wrapped it and performed extra operations, you can write the following handler:
func WrapResponseWriter(ctx *macaron.Context) {rw := NewSpecialResponseWriter(ctx.Resp)// override ResponseWriter with our wrapper ResponseWriterctx.MapTo(rw, (*http.ResponseWriter)(nil))}
In this way, your code can enjoy new custom service feature without any change. Plus, allow more custom implementations of same type of services.