martini

package
v1.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2015 License: MIT, Apache-2.0 Imports: 18 Imported by: 0

README

Martini wercker statusGoDoc

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 and 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"})
r.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.

  • auth - Handlers for authentication.
  • binding - Handler for mapping/validating a raw request into a structure.
  • gzip - Handler for adding gzip compress to requests
  • render - Handler that provides a service for easily rendering JSON and HTML templates.
  • acceptlang - Handler for parsing the Accept-Language HTTP header.
  • sessions - Handler that provides a Session service.
  • strip - URL Prefix stripping.
  • method - HTTP method overriding via Header or form fields.
  • secure - Implements a few quick security wins.
  • encoder - Encoder service for rendering data in several formats and content negotiation.
  • cors - Handler that enables CORS support.
  • oauth2 - Handler that provides OAuth 2.0 login for Martini apps. Google Sign-in, Facebook Connect and Github login is supported.
  • vauth - Handlers for vender webhook authentication (currently GitHub and TravisCI)
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 http.ListenAndServe function instead.

  m := martini.Classic()
  // ...
  log.Fatal(http.ListenAndServe(":8080", m))
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.

About

Inspired by express and sinatra

Martini is obsessively designed by none other than the Code Gangsta

Documentation

Overview

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()
}

Index

Constants

View Source
const (
	Dev  string = "development"
	Prod string = "production"
	Test string = "test"
)

Envs

Variables

View Source
var Env = Dev

Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable.

View Source
var Root string

Functions

This section is empty.

Types

type BeforeFunc

type BeforeFunc func(ResponseWriter)

BeforeFunc is a function that is called before the ResponseWriter has been written to.

type ClassicMartini

type ClassicMartini struct {
	*Martini
	Router
}

ClassicMartini represents a Martini with some reasonable defaults. Embeds the router functions for convenience.

func Classic

func Classic() *ClassicMartini

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.

type Context

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
}

Context represents a request context. Services can be mapped on the request level from this interface.

type Handler

type Handler interface{}

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.

func Logger

func Logger() Handler

Logger returns a middleware handler that logs the request as it goes in and the response as it goes out.

func Recovery

func Recovery() Handler

Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. While Martini is in development mode, Recovery will also output the panic as HTML.

func Static

func Static(directory string, staticOpt ...StaticOptions) Handler

Static returns a middleware handler that serves static files in the given directory.

type Martini

type Martini struct {
	inject.Injector
	// contains filtered or unexported fields
}

Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level.

func New

func New() *Martini

New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used.

func (*Martini) Action

func (m *Martini) Action(handler 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 (*Martini) Handlers

func (m *Martini) Handlers(handlers ...Handler)

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 (*Martini) Run

func (m *Martini) Run()

Run the http server. Listening on os.GetEnv("PORT") or 3000 by default.

func (*Martini) RunOnAddr

func (m *Martini) RunOnAddr(addr string)

Run the http server on a given host and port.

func (*Martini) ServeHTTP

func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request)

ServeHTTP is the HTTP Entry point for a Martini instance. Useful if you want to control your own HTTP server.

func (*Martini) Use

func (m *Martini) Use(handler Handler)

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.

type Params

type Params map[string]string

Params is a map of name/value pairs for named routes. An instance of martini.Params is available to be injected into any route handler.

type ResponseWriter

type ResponseWriter interface {
	http.ResponseWriter
	http.Flusher
	http.Hijacker
	// Status returns the status code of the response or 0 if the response has not been written.
	Status() int
	// Written returns whether or not the ResponseWriter has been written.
	Written() bool
	// Size returns the size of the response body.
	Size() int
	// Before allows for a function to be called before the ResponseWriter has been written to. This is
	// useful for setting headers or any other operations that must happen before a response has been written.
	Before(BeforeFunc)
}

ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about the response. It is recommended that middleware handlers use this construct to wrap a responsewriter if the functionality calls for it.

func NewResponseWriter

func NewResponseWriter(rw http.ResponseWriter) ResponseWriter

NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter

type ReturnHandler

type ReturnHandler func(Context, []reflect.Value)

ReturnHandler is a service that Martini provides that is called when a route handler returns something. The ReturnHandler is responsible for writing to the ResponseWriter based on the values that are passed into this function.

type Route

type Route interface {
	// URLWith returns a rendering of the Route's url with the given string params.
	URLWith([]string) string
	// Name sets a name for the route.
	Name(string)
	// GetName returns the name of the route.
	GetName() string
	// Pattern returns the pattern of the route.
	Pattern() string
	// Method returns the method of the route.
	Method() string
}

Route is an interface representing a Route in Martini's routing layer.

type Router

type Router interface {
	Routes

	// Group adds a group where related routes can be added.
	Group(string, func(Router), ...Handler)
	// Get adds a route for a HTTP GET request to the specified matching pattern.
	Get(string, ...Handler) Route
	// Patch adds a route for a HTTP PATCH request to the specified matching pattern.
	Patch(string, ...Handler) Route
	// Post adds a route for a HTTP POST request to the specified matching pattern.
	Post(string, ...Handler) Route
	// Put adds a route for a HTTP PUT request to the specified matching pattern.
	Put(string, ...Handler) Route
	// Delete adds a route for a HTTP DELETE request to the specified matching pattern.
	Delete(string, ...Handler) Route
	// Options adds a route for a HTTP OPTIONS request to the specified matching pattern.
	Options(string, ...Handler) Route
	// Head adds a route for a HTTP HEAD request to the specified matching pattern.
	Head(string, ...Handler) Route
	// Any adds a route for any HTTP method request to the specified matching pattern.
	Any(string, ...Handler) Route

	// NotFound sets the handlers that are called when a no route matches a request. Throws a basic 404 by default.
	NotFound(...Handler)

	// Handle is the entry point for routing. This is used as a martini.Handler
	Handle(http.ResponseWriter, *http.Request, Context)
}

Router is Martini's de-facto routing interface. Supports HTTP verbs, stacked handlers, and dependency injection.

func NewRouter

func NewRouter() Router

NewRouter creates a new Router instance. If you aren't using ClassicMartini, then you can add Routes as a service with:

m := martini.New()
r := martini.NewRouter()
m.MapTo(r, (*martini.Routes)(nil))

If you are using ClassicMartini, then this is done for you.

type Routes

type Routes interface {
	// URLFor returns a rendered URL for the given route. Optional params can be passed to fulfill named parameters in the route.
	URLFor(name string, params ...interface{}) string
	// MethodsFor returns an array of methods available for the path
	MethodsFor(path string) []string
	// All returns an array with all the routes in the router.
	All() []Route
}

Routes is a helper service for Martini's routing layer.

type StaticOptions

type StaticOptions struct {
	// Prefix is the optional prefix used to serve the static directory content
	Prefix string
	// SkipLogging will disable [Static] log messages when a static file is served.
	SkipLogging bool
	// IndexFile defines which file to serve as index if it exists.
	IndexFile string
	// Expires defines which user-defined function to use for producing a HTTP Expires Header
	// https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
	Expires func() string
	// Fallback defines a default URL to serve when the requested resource was
	// not found.
	Fallback string
	// Exclude defines a pattern for URLs this handler should never process.
	Exclude string
}

StaticOptions is a struct for specifying configuration options for the martini.Static middleware.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL