Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
github.com/go-martini/martini
Martini is a powerful package for quickly writing modular web applications/services in Golang.
Language Translations:
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
.
Join the Mailing list
Watch the Demo Video
Ask questions on Stackoverflow using the martini tag
GoDoc documentation
For more middleware and functionality, check out the repositories in the martini-contrib organization.
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 are the heart and soul of Martini. A handler is basically any kind of callable function:
m.Get("/", func() {
println("hello world")
})
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"
})
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():
map[string]string
of named params found by route matching.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 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 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()
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
}
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
}
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
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 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)
}
})
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")
})
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.
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.
Accept-Language
HTTP header.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)
}
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")
gin and fresh both live reload martini apps.
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.
Martini is distributed by The MIT License, see LICENSE
Inspired by express and sinatra
Martini is obsessively designed by none other than the Code Gangsta
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.