Classy web framework for Go

Overview

Martini wercker statusGoDoc

NOTE: The martini framework is no longer maintained.

Martini is a powerful package for quickly writing modular web applications/services in Golang.

Language Translations:

Getting Started

After installing Go and setting up your GOPATH, create your first .go file. We'll call it server.go.

package main

import "github.com/go-martini/martini"

func main() {
  m := martini.Classic()
  m.Get("/", func() string {
    return "Hello world!"
  })
  m.Run()
}

Then install the Martini package (go 1.1 or greater is required):

go get github.com/go-martini/martini

Then run your server:

go run server.go

You will now have a Martini webserver running on localhost:3000.

Getting Help

Join the Mailing list

Watch the Demo Video

Ask questions on Stackoverflow using the martini tag

GoDoc documentation

Features

  • Extremely simple to use.
  • Non-intrusive design.
  • Plays nice with other Golang packages.
  • Awesome path matching and routing.
  • Modular design - Easy to add functionality, easy to rip stuff out.
  • Lots of good handlers/middlewares to use.
  • Great 'out of the box' feature set.
  • Fully compatible with the http.HandlerFunc interface.
  • Default document serving (e.g., for serving AngularJS apps in HTML5 mode).

More Middleware

For more middleware and functionality, check out the repositories in the martini-contrib organization.

Table of Contents

Classic Martini

To get up and running quickly, martini.Classic() provides some reasonable defaults that work well for most web applications:

  m := martini.Classic()
  // ... middleware and routing goes here
  m.Run()

Below is some of the functionality martini.Classic() pulls in automatically:

Handlers

Handlers are the heart and soul of Martini. A handler is basically any kind of callable function:

m.Get("/", func() {
  println("hello world")
})

Return Values

If a handler returns something, Martini will write the result to the current http.ResponseWriter as a string:

m.Get("/", func() string {
  return "hello world" // HTTP 200 : "hello world"
})

You can also optionally return a status code:

m.Get("/", func() (int, string) {
  return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot"
})

Service Injection

Handlers are invoked via reflection. Martini makes use of Dependency Injection to resolve dependencies in a Handlers argument list. This makes Martini completely compatible with golang's http.HandlerFunc interface.

If you add an argument to your Handler, Martini will search its list of services and attempt to resolve the dependency via type assertion:

m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini
  res.WriteHeader(200) // HTTP 200
})

The following services are included with martini.Classic():

Routing

In Martini, a route is an HTTP method paired with a URL-matching pattern. Each route can take one or more handler methods:

m.Get("/", func() {
  // show something
})

m.Patch("/", func() {
  // update something
})

m.Post("/", func() {
  // create something
})

m.Put("/", func() {
  // replace something
})

m.Delete("/", func() {
  // destroy something
})

m.Options("/", func() {
  // http options
})

m.NotFound(func() {
  // handle 404
})

Routes are matched in the order they are defined. The first route that matches the request is invoked.

Route patterns may include named parameters, accessible via the martini.Params service:

m.Get("/hello/:name", func(params martini.Params) string {
  return "Hello " + params["name"]
})

Routes can be matched with globs:

m.Get("/hello/**", func(params martini.Params) string {
  return "Hello " + params["_1"]
})

Regular expressions can be used as well:

m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string {
  return fmt.Sprintf ("Hello %s", params["name"])
})

Take a look at the Go documentation for more info about regular expressions syntax .

Route handlers can be stacked on top of each other, which is useful for things like authentication and authorization:

m.Get("/secret", authorize, func() {
  // this will execute as long as authorize doesn't write a response
})

Route groups can be added too using the Group method.

m.Group("/books", func(r martini.Router) {
    r.Get("/:id", GetBooks)
    r.Post("/new", NewBook)
    r.Put("/update/:id", UpdateBook)
    r.Delete("/delete/:id", DeleteBook)
})

Just like you can pass middlewares to a handler you can pass middlewares to groups.

m.Group("/books", func(r martini.Router) {
    r.Get("/:id", GetBooks)
    r.Post("/new", NewBook)
    r.Put("/update/:id", UpdateBook)
    r.Delete("/delete/:id", DeleteBook)
}, MyMiddleware1, MyMiddleware2)

Services

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.

Global Mapping

A Martini instance implements the inject.Injector interface, so mapping a service is easy:

db := &MyDatabase{}
m := martini.Classic()
m.Map(db) // the service will be available to all handlers as *MyDatabase
// ...
m.Run()

Request-Level Mapping

Mapping on the request level can be done in a handler via martini.Context:

func MyCustomLoggerHandler(c martini.Context, req *http.Request) {
  logger := &MyCustomLogger{req}
  c.Map(logger) // mapped as *MyCustomLogger
}

Mapping values to Interfaces

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(res http.ResponseWriter, c martini.Context) {
  rw := NewSpecialResponseWriter(res)
  c.MapTo(rw, (*http.ResponseWriter)(nil)) // override ResponseWriter with our wrapper ResponseWriter
}

Serving Static Files

A martini.Classic() instance automatically serves static files from the "public" directory in the root of your server. You can serve from more directories by adding more martini.Static handlers.

m.Use(martini.Static("assets")) // serve from the "assets" directory as well

Serving a Default Document

You can specify the URL of a local file to serve when the requested URL is not found. You can also specify an exclusion prefix so that certain URLs are ignored. This is useful for servers that serve both static files and have additional handlers defined (e.g., REST API). When doing so, it's useful to define the static handler as a part of the NotFound chain.

The following example serves the /index.html file whenever any URL is requested that does not match any local file and does not start with /api/v:

static := martini.Static("assets", martini.StaticOptions{Fallback: "/index.html", Exclude: "/api/v"})
m.NotFound(static, http.NotFound)

Middleware Handlers

Middleware Handlers sit between the incoming http request and the router. In essence they are no different than any other Handler in Martini. You can add a middleware handler to the stack like so:

m.Use(func() {
  // do some middleware stuff
})

You can have full control over the middleware stack with the Handlers function. This will replace any handlers that have been previously set:

m.Handlers(
  Middleware1,
  Middleware2,
  Middleware3,
)

Middleware Handlers work really well for things like logging, authorization, authentication, sessions, gzipping, error pages and any other operations that must happen before or after an http request:

// validate an api key
m.Use(func(res http.ResponseWriter, req *http.Request) {
  if req.Header.Get("X-API-KEY") != "secret123" {
    res.WriteHeader(http.StatusUnauthorized)
  }
})

Next()

Context.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:

// log before and after a request
m.Use(func(c martini.Context, log *log.Logger){
  log.Println("before a request")

  c.Next()

  log.Println("after a request")
})

Martini Env

Some Martini handlers make use of the martini.Env global variable to provide special functionality for development environments vs production environments. It is recommended that the MARTINI_ENV=production environment variable to be set when deploying a Martini server into a production environment.

FAQ

Where do I find middleware X?

Start by looking in the martini-contrib projects. If it is not there feel free to contact a martini-contrib team member about adding a new repo to the organization.

  • acceptlang - Handler for parsing the Accept-Language HTTP header.
  • accessflags - Handler to enable Access Control.
  • auth - Handlers for authentication.
  • binding - Handler for mapping/validating a raw request into a structure.
  • cors - Handler that enables CORS support.
  • csrf - CSRF protection for applications
  • encoder - Encoder service for rendering data in several formats and content negotiation.
  • gzip - Handler for adding gzip compress to requests
  • gorelic - NewRelic middleware
  • logstasher - Middleware that prints logstash-compatible JSON
  • method - HTTP method overriding via Header or form fields.
  • oauth2 - Handler that provides OAuth 2.0 login for Martini apps. Google Sign-in, Facebook Connect and Github login is supported.
  • permissions2 - Handler for keeping track of users, login states and permissions.
  • render - Handler that provides a service for easily rendering JSON and HTML templates.
  • secure - Implements a few quick security wins.
  • sessions - Handler that provides a Session service.
  • sessionauth - Handler that provides a simple way to make routes require a login, and to handle user logins in the session
  • strict - Strict Mode
  • strip - URL Prefix stripping.
  • staticbin - Handler for serving static files from binary data
  • throttle - Request rate throttling middleware.
  • vauth - Handlers for vender webhook authentication (currently GitHub and TravisCI)
  • web - hoisie web.go's Context

How do I integrate with existing servers?

A Martini instance implements http.Handler, so it can easily be used to serve subtrees on existing Go servers. For example this is a working Martini app for Google App Engine:

package hello

import (
  "net/http"
  "github.com/go-martini/martini"
)

func init() {
  m := martini.Classic()
  m.Get("/", func() string {
    return "Hello world!"
  })
  http.Handle("/", m)
}

How do I change the port/host?

Martini's Run function looks for the PORT and HOST environment variables and uses those. Otherwise Martini will default to localhost:3000. To have more flexibility over port and host, use the martini.RunOnAddr function instead.

  m := martini.Classic()
  // ...
  m.RunOnAddr(":8080")

Live code reload?

gin and fresh both live reload martini apps.

Contributing

Martini is meant to be kept tiny and clean. Most contributions should end up in a repository in the martini-contrib organization. If you do have a contribution for the core of Martini feel free to put up a Pull Request.

License

Martini is distributed by The MIT License, see LICENSE

About

Inspired by express and sinatra

Martini is obsessively designed by none other than the Code Gangsta

Comments
  • add Routes.NotFound method

    add Routes.NotFound method

    called inside a routing handler for passing current request to NotFound handler

    m.Get("/:uri", func(p martini.Params, r martini.Routes) {
        if p["uri"] == "allok" {
            ...
            return
        }
        r.NotFound() // from here
    })
    
    m.NotFound(func() {
        // to here
    })
    
    opened by sevkin 16
  • net/http/pprof breaks with Martini

    net/http/pprof breaks with Martini

    It appears that Martini prevents net/http/pprof from working. This can be reproduced by creating a non-Martini app and an equivalent Martini app and examining the "/debug/pprof/" endpoints.

    To reproduce:

    If you create the following non-Martini application:

    // Non-Martini version
    package main
    
    import (
        "fmt"
        "net/http"
        _ "net/http/pprof"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
    }
    
    func main() {
        http.HandleFunc("/", handler)
        http.ListenAndServe(":8080", nil)
    }
    

    When running this and then navigating to http://localhost:8080/debug/pprof/ you'll see the following:

    screen shot 2014-04-09 at 2 48 32 pm

    If you create the equivalent Martini based application:

    // Martini Version
    package main
    
    import (
        "fmt"
        "github.com/go-martini/martini"
        "net/http"
        _ "net/http/pprof"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
    }
    
    func main() {
        m := martini.New()
        r := martini.NewRouter()
        r.Get("/", handler)
        m.Action(r.Handle)
        http.ListenAndServe(":8080", m)
    }
    

    And navigate to the same endpoint, you get a 404.

    opened by apiguy 13
  • go_version.go does not compile

    go_version.go does not compile

    It seems the following code in go_version.go does not compile:

    package martini
    
    func MartiniDoesNotSupportGo1Point0() {
            "Martini requires Go 1.1 or greater."
    }
    
    opened by elgs 13
  • Swagger Integration (Feature Request)

    Swagger Integration (Feature Request)

    Hi

    First of all, nice project. I like it a lot.

    Some feature that would make this project even more attractive is support for swagger.

    Swagger is a specification and complete framework implementation for describing, producing, consuming, and visualizing RESTful web services.

    Website: https://developers.helloreverb.com/swagger/ Example: http://petstore.swagger.wordnik.com/

    Swagger is already supported by play-framework, scalatra, django, go-restful.

    BR, Rene

    later 
    opened by ghost 13
  • Added option to disable logging when serving static assets

    Added option to disable logging when serving static assets

    I added an optional parameter to Static(), to disable logging when serving static assets.

    The reason for this is that my current project has a lot of static CSS, JS, etc. files that are served with each GET request. This produces a lot of "spam" that I don't want / need to have in my logfile/stdout.

    The new variadic bool parameter for Static() is called skipLogging. If it is set to true, no logging output will be produced. Since the default for a missing parameter / bool is false, this change is fully backwards compatible.

    Example:

    //m := martini.Classic()
    r := martini.NewRouter()
    m := martini.New()
    m.Use(martini.Recovery())
    m.Use(martini.Static("public", true)) // skip logging on static content
    m.Use(martini.Logger()) // place Logger after Static
    m.Action(r.Handle)
    
    r.Get("/", index)
    m.Run()
    
    // Output:
    // [martini] listening on port 3000
    // [martini] Started GET /
    // [martini] Completed 200 OK in 615.252us
    

    vs. before:

    m := martini.Classic()
    
    m.Get("/", index)
    m.Run()
    
    // Output:
    // [martini] listening on port 3000
    // [martini] Started GET /
    // [martini] Completed 200 OK in 604.306us
    // [martini] Started GET /stylesheets/base.css
    // [martini] [Static] Serving /stylesheets/base.css
    // [martini] Completed 304 Not Modified in 52.72us
    // [martini] Started GET /stylesheets/custom.css
    // [martini] [Static] Serving /stylesheets/custom.css
    // [martini] Completed 304 Not Modified in 36.677us
    // [martini] Started GET /stylesheets/layout.css
    // [martini] [Static] Serving /stylesheets/layout.css
    // [martini] Completed 304 Not Modified in 32.378us
    // [martini] Started GET /stylesheets/skeleton.css
    // [martini] [Static] Serving /stylesheets/skeleton.css
    // [martini] Completed 304 Not Modified in 33.953us
    // [martini] Started GET /images/bg.png
    // [martini] [Static] Serving /images/bg.png
    // [martini] Completed 304 Not Modified in 42.832us
    // [martini] Started GET /images/color.png
    // [martini] [Static] Serving /images/color.png
    // [martini] Completed 304 Not Modified in 37.132us
    
    opened by JamesClonk 12
  • Add Values and Printer to give middleware control over Handler return

    Add Values and Printer to give middleware control over Handler return

    This moves the return handling functionality from Router into a new Printer() middleware by means of a Values type. This allows other middleware to do things with values returned from the previous handler.

    This keeps the functionality of Martini & ClassicMartini functionality identical to the way it is now. Router tests have been updated to reflect the changes, and new tests have been added for Printer().

    Printer() also additionally supports String() from fmt.Stringer and []byte.

    opened by lukescott 12
  • UrlFor implemented

    UrlFor implemented

    Hi! One common pattern I've seen in multiple web frameworks is the ability to assign a name to a route and generate the url for that route through an UrlFor method, which I think it's very useful. I've noticed Martini didn't have it so here's my attempt to implement it.

    All tests are passing.

    Some examples:

    // Naming a route
    m.Get("/foo", func() {
        // Here be code
    }).Name("my_fancy_route")
    
    // Generating the url for your route
    fmt.Println(m.UrlFor("my_fancy_route", nil))
    // Outputs /foo
    
    // Naming a route with params
    m.Get("/foo/:bar/:baz", func() {
        // Here be code
    }).Name("my_fancy_route_with_params")
    
    // Generating the url for your route with params
    fmt.Println(m.UrlFor("my_fancy_route_with_params", "param1", "param2"))
    // Outputs /foo/param1/param2
    
    opened by erizocosmico 12
  • Use a secure comparison in auth middleware

    Use a secure comparison in auth middleware

    Otherwise you might get timing attacks:

    http://verboselogging.com/2012/08/20/a-timing-attack-in-action

    I don't actually know Go. I ran through gofmt at least.

    Also I feel like that SecureCompare would be generally useful in a middleware project (Rack has one in Util ,for example) so I bet it should be extracted from here.

    opened by bemurphy 11
  • Logger RemoteAddr

    Logger RemoteAddr

    For various reasons I am using Nginx as a proxy pass through to my Go servers.

    Nginx config:

    server {
          listen 443 ssl;
          server_name justriot.com;
    
          ssl on;
          ssl_certificate /var/www/go/src/pixelrelay/tls/ssl.crt;
          ssl_certificate_key /var/www/go/src/pixelrelay/tls/key.pem;
    
    
          location / {
            proxy_set_header    X-Real-IP       $remote_addr;
            proxy_set_header    X-Forwarded-For $remote_addr;
            proxy_set_header    Host            $host;
            proxy_pass          https://127.0.0.1:8000;
          }
    }
    

    However, this ends up giving the following in the logs:

    [martini] Started GET /views/albuminfo.html for 127.0.0.1:50889
    

    Obviously, this gives a log entry that means nothing to me if I were to go back and read through the logs.

    So, is there a way to override the header that it is grabbing the req.RemoteAddr value from. So I could instead let it take the value from X-Real-IP?

    opened by jayrox 10
  • Value not found for type martini.Context

    Value not found for type martini.Context

    On localhost with go1.2.1 darwin/amd64 there is no problem but when i try to deploy on debian with go1.2.1 linux/amd64 error occurred.

    [martini] Started POST /register
    [martini] PANIC: Value not found for type martini.Context
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/router.go:320 (0x433768)
        (*routeContext).run: panic(err)
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/router.go:221 (0x432d04)
        (*route).Handle: context.run()
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/router.go:112 (0x431d7c)
        (*router).Handle: route.Handle(context, res)
    /home/pkowalczuk/go/src/github.com/piotrkowalczuk/netwars-backend/server.go:49 (0x401c80)
        Router.Handle.fm: m.Action(router.Handle)
    /usr/local/go/src/pkg/runtime/asm_amd64.s:340 (0x425372)
        call64: CALLFN(call64, 64)
    /usr/local/go/src/pkg/reflect/value.go:474 (0x551a7b)
        Value.call: call(fn, ptr, uint32(size))
    /usr/local/go/src/pkg/reflect/value.go:345 (0x550b6d)
        Value.Call: return v.call("Call", in)
    /home/pkowalczuk/go/src/github.com/codegangsta/inject/inject.go:102 (0x560844)
        (*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/martini.go:163 (0x430382)
        (*context).run: _, err := c.Invoke(c.handler())
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/martini.go:154 (0x4302db)
        (*context).Next: c.run()
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/recovery.go:140 (0x434166)
        func.004: c.Next()
    /usr/local/go/src/pkg/runtime/asm_amd64.s:339 (0x425312)
        call32: CALLFN(call32, 32)
    /usr/local/go/src/pkg/reflect/value.go:474 (0x551a7b)
        Value.call: call(fn, ptr, uint32(size))
    /usr/local/go/src/pkg/reflect/value.go:345 (0x550b6d)
        Value.Call: return v.call("Call", in)
    /home/pkowalczuk/go/src/github.com/codegangsta/inject/inject.go:102 (0x560844)
        (*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/martini.go:163 (0x430382)
        (*context).run: _, err := c.Invoke(c.handler())
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/martini.go:154 (0x4302db)
        (*context).Next: c.run()
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/logger.go:16 (0x433a78)
        func.001: c.Next()
    /usr/local/go/src/pkg/runtime/asm_amd64.s:340 (0x425372)
        call64: CALLFN(call64, 64)
    /usr/local/go/src/pkg/reflect/value.go:474 (0x551a7b)
        Value.call: call(fn, ptr, uint32(size))
    /usr/local/go/src/pkg/reflect/value.go:345 (0x550b6d)
        Value.Call: return v.call("Call", in)
    /home/pkowalczuk/go/src/github.com/codegangsta/inject/inject.go:102 (0x560844)
        (*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/martini.go:163 (0x430382)
        (*context).run: _, err := c.Invoke(c.handler())
    /home/pkowalczuk/go/src/github.com/codegangsta/martini/martini.go:69 (0x42fa93)
        (*Martini).ServeHTTP: m.createContext(res, req).run()
    /usr/local/go/src/pkg/net/http/server.go:1597 (0x4491ee)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
    /usr/local/go/src/pkg/net/http/server.go:1167 (0x4471f7)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
    /usr/local/go/src/pkg/runtime/proc.c:1394 (0x418b00)
        goexit: runtime·goexit(void)
    [martini] Completed 500 Internal Server Error in 12.53285ms
    

    https://github.com/piotrkowalczuk/netwars-backend/blob/develop/server.go#L49

    opened by piotrkowalczuk 10
  • Value not found for type martini.Context

    Value not found for type martini.Context

    The following request logger appears to be causing Martini to panic:

    func requestLogger() martini.Handler {
        return func(res http.ResponseWriter, req *http.Request, c martini.Context) {
            start := time.Now()
    
            rw := res.(martini.ResponseWriter)
            c.Next()
    
            log.Infof("%s %s %v %s", req.Method, req.URL.Path, rw.Status(), time.Since(start))
        }
    }
    

    The trace is here:

    Mar 31 16:55:56 cdr2 rated[23101]: 2014/03/31 16:55:56 http: panic serving 127.0.0.1:59838: Value not found for type martini.Context
    Mar 31 16:55:56 cdr2 rated[23101]: goroutine 19 [running]:
    Mar 31 16:55:56 cdr2 rated[23101]: net/http.func·009()
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/.gvm/gos/go1.2/src/pkg/net/http/server.go:1093 +0xae
    Mar 31 16:55:56 cdr2 rated[23101]: runtime.panic(0x882bc0, 0xc21013ca70)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/.gvm/gos/go1.2/src/pkg/runtime/panic.c:248 +0x106
    Mar 31 16:55:56 cdr2 rated[23101]: github.com/codegangsta/martini.(*context).run(0xc2100e8e10)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/gopath/src/github.com/codegangsta/martini/martini.go:165 +0x98
    Mar 31 16:55:56 cdr2 rated[23101]: github.com/codegangsta/martini.(*context).Next(0xc2100e8e10)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/gopath/src/github.com/codegangsta/martini/martini.go:154 +0x2b
    Mar 31 16:55:56 cdr2 rated[23101]: main.func·001(0x7fa26f7f1340, 0xc2100e5dc0, 0xc21015a000, 0x7fa26f7f12d8, 0xc2100e8e10)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/gopath/src/github.com/QTAB/rating/src/rated.go:62 +0x93
    Mar 31 16:55:56 cdr2 rated[23101]: reflect.Value.call(0x857ce0, 0xa6eb68, 0x130, 0x949d40, 0x4, ...)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/.gvm/gos/go1.2/src/pkg/reflect/value.go:474 +0xe0b
    Mar 31 16:55:56 cdr2 rated[23101]: reflect.Value.Call(0x857ce0, 0xa6eb68, 0x130, 0xc2100e8e60, 0x3, ...)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/.gvm/gos/go1.2/src/pkg/reflect/value.go:345 +0x9d
    Mar 31 16:55:56 cdr2 rated[23101]: github.com/codegangsta/inject.(*injector).Invoke(0xc210150a40, 0x857ce0, 0xa6eb68, 0xf518f0, 0x0, ...)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/gopath/src/github.com/codegangsta/inject/inject.go:102 +0x304
    Mar 31 16:55:56 cdr2 rated[23101]: github.com/codegangsta/martini.(*context).run(0xc2100e8e10)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/gopath/src/github.com/codegangsta/martini/martini.go:163 +0x62
    Mar 31 16:55:56 cdr2 rated[23101]: github.com/codegangsta/martini.(*Martini).ServeHTTP(0xc2100423c0, 0x7fa26f7f11e8, 0xc210152a00, 0xc21015a0
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/gopath/src/github.com/codegangsta/martini/martini.go:69 +0x53
    Mar 31 16:55:56 cdr2 rated[23101]: net/http.serverHandler.ServeHTTP(0xc2100e8550, 0x7fa26f7f11e8, 0xc210152a00, 0xc21015a000)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/.gvm/gos/go1.2/src/pkg/net/http/server.go:1597 +0x16e
    Mar 31 16:55:56 cdr2 rated[23101]: net/http.(*conn).serve(0xc210148080)
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/.gvm/gos/go1.2/src/pkg/net/http/server.go:1167 +0x7b7
    Mar 31 16:55:56 cdr2 rated[23101]: created by net/http.(*Server).Serve
    Mar 31 16:55:56 cdr2 rated[23101]: /home/travis/.gvm/gos/go1.2/src/pkg/net/http/server.go:1644 +0x28b
    

    For some strange reason I am only getting this from Travis binary builds - I'm not getting this issue running the app from source.

    opened by 0x6e6562 10
  • Use an interface for logger

    Use an interface for logger

    What this does:

    Moves from a pointer to a log.logger to a logger interface. I leave in the original code that initializes a default log.logger because this is an older repo and theres no reason to break this.

    Why this is necessary

    • I have an older repo (orchestrator) that uses martini and the logs are poluted with martini logs that are in a non standard format and make searching them hard.
    • Also added support for go modules..
    opened by Highstead 0
  • Problems with # in route matching

    Problems with # in route matching

    LIke: m.Get("/hello/**", func(params martini.Params) string { return "Hello " + params["_1"] })

    Enter when I visit “/hello/test#test”, It's return 404. I want to know # is treated as something else? Thank you ^-^

    opened by DoLolitingyu 0
  • how to break-out of middleware chain using Martini

    how to break-out of middleware chain using Martini

    I put this question on SO and am looking for answers - this question may be based off a false assumption:

    https://stackoverflow.com/questions/60679922/how-to-break-out-of-martini-middleware

    but at the very least I have no idea how martini would know when to keep invoking the middleware chain and when not to? it wouldn't know even if you aleady set the http status code or wrote the response body, you may still want to keep writing in subsequent middleware funcs. someone please explain how to return early out of the chain.

    Perhaps this is the best way to do it?

    m.Use(func(c martini.Context, w http.ResponseWriter){
    
        if reqIsMalformed() {
            http.Error(w, "Bad request because xyz", 422)
            return;
        }
    
        c.Next()  // only invoke remaining middleware if the request is valid?
    
    })
    
    opened by ORESoftware 2
  • How to include auth middleware that handles roles for logged-in users

    How to include auth middleware that handles roles for logged-in users

    We have this right now which works:

    func (ctr *Controller) Routes(m *martini.ClassicMartini) {
       m.Post("/cp/foo", common.AsJson, common.RequestTimer, ctr.Login)
       m.Get("/cp/bar", common.AsJson, common.RequestTimer, ctr.Logout)
    }
    

    we want to do something like this:

    func (ctr *Controller) Routes(m *martini.ClassicMartini) {
       m.Post("/cp/foo", common.AsJson, common.LoadUser("admin"), common.RequestTimer, ctr.Login)
       m.Get("/cp/bar", common.AsJson, common.LoadUser("admin", "super"), common.RequestTimer, ctr.Logout)
    }
    

    basically we want some middleware that can load a user from a JWT and ensure that they have the right role (either admin or super or both etc). The above would work fine, but we want to send a 401 back in the middleware if the user doesn't have the right roles or if the JWT cannot be decrypted.

    Is there a way to define middleware for each route, where that middleware can respond, so we don't have to handle that logic at every endpoint?

    opened by ORESoftware 1
Releases(v1.0)
  • v1.0(May 19, 2014)

  • v1.0-rc1(Apr 25, 2014)

    This is the first release candidate for martini version 1. At this point we are pretty happy with the feature set that martini has. Paired with the recent change in the inject branch https://github.com/codegangsta/inject/pull/18, martini should be in a good spot for cutting a 1.0 version soon

    Source code(tar.gz)
    Source code(zip)
  • v0.1(Dec 5, 2013)

Golanger Web Framework is a lightweight framework for writing web applications in Go.

/* Copyright 2013 Golanger.com. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except

golanger 299 Mar 3, 2022
An ideally refined web framework for Go.

Air An ideally refined web framework for Go. High-performance? Fastest? Almost all web frameworks are using these words to tell people that they are t

Aofei Sheng 418 Sep 14, 2022
Web framework for creating apps using Go in Google AppEngine

Welcome to app.go v3.0 app.go is a simple web framework for use in Google AppEngine. Just copy the app folder to your working folder and import it fro

George Nava 46 Mar 21, 2021
Eudore is the core of a golang lightweight web framework.

Eudore eudore是一个golang轻量级web框架核心,可以轻松扩展成一个技术栈专用框架,具有完整框架设计体系。 反馈和交流请加群组:QQ群373278915。 Features 易扩展:主要设计目标、核心全部解耦,接口即为逻辑。 简单:对象语义明确,框架代码量少复杂度低,无依赖库。 易用

null 72 Jul 30, 2022
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin Web Framework Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks

Gin-Gonic 63.2k Sep 29, 2022
Goal is a toolkit for high productivity web development in Go language in the spirit of Revel Framework that is built around the concept of code generation.

Goal Goal is a set of tools for high productivity web development in Go language. Goal, being mostly inspired by Revel Framework and its discussions,

null 88 Sep 27, 2021
a golang web mvc framework, like asp.net mvc.

goku goku is a Web Mvc Framework for golang, mostly like ASP.NET MVC. doc & api Installation To install goku, simply run go get github.com/QLeelulu/go

QLeelulu 272 Aug 27, 2022
A high level web-framework for Go

go-start is a high level web-framework for Go, like Django for Python or Rails for Ruby. Installation: go get github.com/ungerik/go-start Documentatio

Erik Unger 267 Aug 25, 2022
A lightweight RESTful web framework for Go

Goweb A lightweight RESTful web framework for Go. For examples and usage, please read the Goweb API Documentation Read our Articles Who uses Goweb? "U

Stretchr, Inc. 630 Sep 5, 2022
Fast and Reliable Golang Web Framework

Gramework The Good Framework Gramework long-term testing stand metrics screenshot made with Gramework Stats Dashboard and metrics middleware What is i

null 371 Sep 19, 2022
Mango is a modular web-application framework for Go, inspired by Rack, and PEP333.

Mango Mango is a modular web-application framework for Go, inspired by Rack and PEP333. Note: Not actively maintained. Overview Mango is most of all a

Paul Bellamy 369 Sep 14, 2022
A Go framework for building JSON web services inspired by Dropwizard

Tiger Tonic A Go framework for building JSON web services inspired by Dropwizard. If HTML is your game, this will hurt a little. Like the Go language

Richard Crowley 1000 Sep 2, 2022
The web framework for Golang

uAdmin the Golang Web Framework Easy to use, blazing fast and secure. Originally open source by IntegrityNet Solutions and Services For Documentation:

uADMIN 201 Sep 16, 2022
Simple web framework for go, still quite beta at this point

WFDR Framework - Beta Release New 18/Feb/2012: Updated for go 1.0, new directory layout to take advantage of the go build tool. Background There's a m

null 23 Feb 11, 2021
A simple blog framework built with GO. Uses HTML files and a JSON dict to give you more control over your content.

Go-Blog A simple template based blog framework. Instructions Built for GO version: 1 See the Documentation or Getting Started pages in the wiki. Notes

Matt West 45 Sep 10, 2022
Goldorak GO is a mini framework for the Go programming language. (unfinished dead code)

Goldorak Go =========== > Goldorak GO ! Rétrolaser en action > Goldorak GO !! Va accomplir ta mission > Dans l'infini > Des galaxies > Poursuis ta lu

Bruno Michel 10 Apr 29, 2021
A small and evil REST framework for Go

go-rest A small and evil REST framework for Go Reflection, Go structs, and JSON marshalling FTW! go get github.com/ungerik/go-rest import "github.com/

Erik Unger 124 Sep 7, 2022
🍐 Elegant Golang REST API Framework

An Elegant Golang Web Framework Goyave is a progressive and accessible web application framework focused on REST APIs, aimed at making backend develop

SystemGlitch 1.2k Sep 21, 2022
A lightweight MVC framework for Go(Golang)

utron utron is a lightweight MVC framework in Go (Golang) for building fast, scalable and robust database-driven web applications. Features Postgres,

Geofrey Ernest 2.2k Sep 21, 2022