// Package martini is a powerful package for quickly writing modular web applications/services in Golang. // // For a full guide visit http://github.com/go-martini/martini // // package main // // import "github.com/go-martini/martini" // // func main() { // m := martini.Classic() // // m.Get("/", func() string { // return "Hello world!" // }) // // m.Run() // } package martini import ( "log" "net/http" "os" "reflect" "github.com/codegangsta/inject" ) // Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level. type Martini struct { inject.Injector handlers []Handler action Handler logger *log.Logger } // New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used. func New() *Martini { m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(os.Stdout, "[martini] ", 0)} m.Map(m.logger) m.Map(defaultReturnHandler()) return m } // Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers. // Will panic if any of the handlers is not a callable function func (m *Martini) Handlers(handlers ...Handler) { m.handlers = make([]Handler, 0) for _, handler := range handlers { m.Use(handler) } } // Action sets the handler that will be called after all the middleware has been invoked. This is set to martini.Router in a martini.Classic(). func (m *Martini) Action(handler Handler) { validateHandler(handler) m.action = handler } // Logger sets the logger func (m *Martini) Logger(logger *log.Logger) { m.logger = logger m.Map(m.logger) } // Use adds a middleware Handler to the stack. Will panic if the handler is not a callable func. Middleware Handlers are invoked in the order that they are added. func (m *Martini) Use(handler Handler) { validateHandler(handler) m.handlers = append(m.handlers, handler) } // ServeHTTP is the HTTP Entry point for a Martini instance. Useful if you want to control your own HTTP server. func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) { m.createContext(res, req).run() } // Run the http server on a given host and port. func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed. logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) logger.Fatalln(http.ListenAndServe(addr, m)) } // Run the http server. Listening on os.GetEnv("PORT") or 3000 by default. func (m *Martini) Run() { port := os.Getenv("PORT") if len(port) == 0 { port = "3000" } host := os.Getenv("HOST") m.RunOnAddr(host + ":" + port) } func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context { c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0} c.SetParent(m) c.MapTo(c, (*Context)(nil)) c.MapTo(c.rw, (*http.ResponseWriter)(nil)) c.Map(req) return c } // ClassicMartini represents a Martini with some reasonable defaults. Embeds the router functions for convenience. type ClassicMartini struct { *Martini Router } // Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery and martini.Static. // Classic also maps martini.Routes as a service. func Classic() *ClassicMartini { r := NewRouter() m := New() m.Use(Logger()) m.Use(Recovery()) m.Use(Static("public")) m.MapTo(r, (*Routes)(nil)) m.Action(r.Handle) return &ClassicMartini{m, r} } // Handler can be any callable function. Martini attempts to inject services into the handler's argument list. // Martini will panic if an argument could not be fullfilled via dependency injection. type Handler interface{} func validateHandler(handler Handler) { if reflect.TypeOf(handler).Kind() != reflect.Func { panic("martini handler must be a callable func") } } // Context represents a request context. Services can be mapped on the request level from this interface. type Context interface { inject.Injector // Next is an optional function that Middleware Handlers can call to yield the until after // the other Handlers have been executed. This works really well for any operations that must // happen after an http request Next() // Written returns whether or not the response for this context has been written. Written() bool } type context struct { inject.Injector handlers []Handler action Handler rw ResponseWriter index int } func (c *context) handler() Handler { if c.index < len(c.handlers) { return c.handlers[c.index] } if c.index == len(c.handlers) { return c.action } panic("invalid index for context handler") } func (c *context) Next() { c.index += 1 c.run() } func (c *context) Written() bool { return c.rw.Written() } func (c *context) run() { for c.index <= len(c.handlers) { _, err := c.Invoke(c.handler()) if err != nil { panic(err) } c.index += 1 if c.Written() { return } } }