Martini est une puissante bibliothèque pour développer rapidement des applications et services web en Golang.
Après avoir installé Go et configuré le chemin d'accès pour GOPATH, créez votre premier fichier '.go'. Nous l'appellerons 'server.go'.
package main
import "github.com/go-martini/martini"
func main() {
m := martini.Classic()
m.Get("/", func() string {
return "Hello world!"
})
m.Run()
}
Installez ensuite le paquet Martini (go 1.1 ou supérieur est requis) :
go get github.com/go-martini/martini
La commande suivante vous permettra de lancer votre serveur :
go run server.go
Vous avez à présent un serveur web Martini à l'écoute sur l'adresse et le port suivants : localhost:3000
.
- Souscrivez à la Liste d'emails
- Regardez les vidéos Demo en vidéo
- Posez vos questions sur StackOverflow.com en utilisant le tag martini
- La documentation GoDoc documentation
- Simple d'utilisation
- Design non-intrusif
- Compatible avec les autres paquets Golang
- Gestionnaire d'URL et routeur disponibles
- Modulable, permettant l'ajout et le retrait de fonctionnalités
- Un grand nombre de handlers/middlewares disponibles
- Prêt pour une utilisation immédiate
- Entièrement compatible avec l'interface http.HandlerFunc.
Pour plus de middlewares et de fonctionnalités, consultez le dépôt martini-contrib.
Pour vous faire gagner un temps précieux, martini.Classic() est configuré avec des paramètres qui devraient couvrir les besoins de la plupart des applications web :
m := martini.Classic()
// ... les middlewares and le routage sont insérés ici...
m.Run()
Voici quelques handlers/middlewares que martini.Classic() intègre par défault :
- Logging des requêtes/réponses - martini.Logger
- Récupération sur erreur - martini.Recovery
- Serveur de fichiers statiques - martini.Static
- Routage - martini.Router
Les Handlers sont le coeur et l'âme de Martini. N'importe quelle fonction peut être utilisée comme un handler.
m.Get("/", func() {
println("hello world")
})
Si un handler retourne une valeur, Martini écrira le résultat dans l'instance http.ResponseWriter courante sous forme de string
:
m.Get("/", func() string {
return "hello world" // HTTP 200 : "hello world"
})
Vous pouvez aussi optionnellement renvoyer un code de statut HTTP :
m.Get("/", func() (int, string) {
return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot"
})
Les handlers sont appelés via réflexion. Martini utilise "l'injection par dépendance" pour résoudre les dépendances des handlers dans la liste d'arguments. Cela permet à Martini d'être parfaitement compatible avec l'interface golang http.HandlerFunc
.
Si vous ajoutez un argument à votre Handler, Martini parcourera la liste des services et essayera de déterminer ses dépendances selon son type :
m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini
res.WriteHeader(200) // HTTP 200
})
Les services suivants sont inclus avec martini.Classic():
- log.Logger - Global logger for Martini.
- martini.Context - Contexte d'une requête HTTP.
- martini.Params -
map[string]string
contenant les paramètres retrouvés par correspondance des routes. - martini.Routes - Service d'aide au routage.
- http.ResponseWriter - Interface d'écriture de réponses HTTP.
- *http.Request - Requête HTTP.
Dans Martini, un chemin est une méthode HTTP liée à un modèle d'adresse URL. Chaque chemin peut avoir un seul ou plusieurs méthodes handler :
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
})
Les chemins seront traités dans l'ordre dans lequel ils auront été définis. Le handler du premier chemin trouvé qui correspondra à la requête sera invoqué.
Les chemins peuvent inclure des paramètres nommés, accessibles avec le service martini.Params :
m.Get("/hello/:name", func(params martini.Params) string {
return "Hello " + params["name"]
})
Les chemins peuvent correspondre à des globs :
m.Get("/hello/**", func(params martini.Params) string {
return "Hello " + params["_1"]
})
Les expressions régulières peuvent aussi être utilisées :
m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string {
return fmt.Sprintf ("Hello %s", params["name"])
})
Jetez un oeil à la documentation Go documentation pour plus d'informations sur la syntaxe des expressions régulières.
Les handlers d'un chemins peuvent être superposés, ce qui s'avère particulièrement pratique pour des tâches comme la gestion de l'authentification et des autorisations :
m.Get("/secret", authorize, func() {
// this will execute as long as authorize doesn't write a response
})
Un groupe de chemins peut aussi être ajouté en utilisant la méthode Group
:
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)
})
Comme vous pouvez passer des middlewares à un handler, vous pouvez également passer des middlewares à des groupes :
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)
Les services sont des objets injectés dans la liste d'arguments d'un handler. Un service peut être défini pour une requête, ou de manière globale.
Les instances Martini implémentent l'interace inject.Injector, ce qui facilite grandement le mapping de services :
db := &MyDatabase{}
m := martini.Classic()
m.Map(db) // the service will be available to all handlers as *MyDatabase
// ...
m.Run()
Pour une déclaration au niveau d'une requête, il suffit d'utiliser un handler via martini.Context :
func MyCustomLoggerHandler(c martini.Context, req *http.Request) {
logger := &MyCustomLogger{req}
c.Map(logger) // mapped as *MyCustomLogger
}
L'un des aspects les plus intéressants des services réside dans le fait qu'ils peuvent être liés à des interfaces. Par exemple, pour surcharger http.ResponseWriter avec un objet qui l'enveloppe et étend ses fonctionnalités, vous pouvez utiliser le handler suivant :
func WrapResponseWriter(res http.ResponseWriter, c martini.Context) {
rw := NewSpecialResponseWriter(res)
c.MapTo(rw, (*http.ResponseWriter)(nil)) // override ResponseWriter with our wrapper ResponseWriter
}
Une instance martini.Classic() est déjà capable de servir les fichiers statiques qu'elle trouvera dans le dossier public à la racine de votre serveur. Vous pouvez indiquer d'autres dossiers sources à l'aide du handler martini.Static.
m.Use(martini.Static("assets")) // serve from the "assets" directory as well
Les middleware handlers sont placés entre la requête HTTP entrante et le routeur. Ils ne sont aucunement différents des autres handlers présents dans Martini. Vous pouvez ajouter un middleware handler comme ceci :
m.Use(func() {
// do some middleware stuff
})
Vous avez un contrôle total sur la structure middleware avec la fonction Handlers
. Son exécution écrasera tous les handlers configurés précédemment :
m.Handlers(
Middleware1,
Middleware2,
Middleware3,
)
Middleware Handlers est très pratique pour automatiser des fonctions comme le logging, l'autorisation, l'authentification, sessions, gzipping, pages d'erreur, et toutes les opérations qui se font avant ou après chaque requête HTTP :
// 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() est une fonction optionnelle que les Middleware Handlers peuvent appeler pour patienter jusqu'à ce que tous les autres handlers aient été exécutés. Cela fonctionne très bien pour toutes opérations qui interviennent après une requête HTTP :
// log before and after a request
m.Use(func(c martini.Context, log *log.Logger){
log.Println("avant la requête")
c.Next()
log.Println("après la requête")
})
Plusieurs Martini handlers utilisent 'martini.Env' comme variable globale pour fournir des fonctionnalités particulières qui diffèrent entre l'environnement de développement et l'environnement de production. Il est recommandé que la variable 'MARTINI_ENV=production' soit définie pour déployer un serveur Martini en environnement de production.
Commencer par regarder dans le martini-contrib projet. S'il n'y est pas, n'hésitez pas à contacter un membre de l'équipe martini-contrib pour ajouter un nouveau dépôt à l'organisation.
- 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)
Une instance Martini implémente http.Handler
. Elle peut donc utilisée pour alimenter des sous-arbres sur des serveurs Go existants. Voici l'exemple d'une application Martini pour 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)
}
La fonction Run
de Martini utilise le port et l'adresse spécifiés dans les variables d'environnement. Si elles ne peuvent y être trouvées, Martini utilisera localhost:3000 par default.
Pour avoir plus de flexibilité sur le port et l'adresse, utilisez la fonction martini.RunOnAddr
à la place.
m := martini.Classic()
// ...
log.Fatal(m.RunOnAddr(":8080"))
gin et fresh sont tous les capables de recharger le code des applications martini chaque fois qu'il est modifié.
Martini est destiné à rester restreint et épuré. Toutes les contributions doivent finir dans un dépot dans l'organisation martini-contrib. Si vous avez une contribution pour le noyau de Martini, n'hésitez pas à envoyer une Pull Request.
Inspiré par express et Sinatra, Martini est l'oeuvre de nul d'autre que Code Gangsta, votre serviteur.