Documentation
¶
Overview ¶
Package glue provides a simple interface to writing HTTP services in Go
It aims to be small and as simple as possible while exposing a pleasant API.
Glue uses reflection and dependency injection to provide a flexible API for your HTTP endpoints. There is an obvious tradeoff here. The cost of this flexibility is some static safety and some performance overhead (though this appears negligible in benchmarking).
godoc: http://godoc.org/github.com/tmc/glue
Features:
- small (~250LOC)
- compatible with the net/http Handler and HandleFunc interfaces.
- provides mechanism for before and after request middleware
Basic Example:
package main import "github.com/tmc/glue" func main() { g := glue.New() g.Get("/", func() string { return "hello world" }) g.Listen() // listens on :5000 by default (uses PORT environtment variable) }
Example showing middleware, logging, routing, and static file serving:
g := glue.New() // Register a new type with the underlying DI container g.Register(log.New(os.Stderr, "[glue example] ", log.LstdFlags)) // Add a new glue.Handler that will be invoked for each request g.AddHandler(loggers.NewApacheLogger()) // Add a handler using routing and parameter capture g.Get("/{type}_teapot", func(r *http.Request) (int, string) { return http.StatusTeapot, "that is " + r.URL.Query().Get(":type") + "!" }) // Serve static files g.Get("/", http.FileServer(http.Dir("./static/"))) go g.Listen() // listens on 5000 by default (uses PORT environtment variable) resp, err := http.Get("http://127.0.0.1:5000/purple_teapot") if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Println(resp.Status, string(body)) // Output: // 418 I'm a teapot that is purple!
glue is influenced by martini and basically co-opts gorilla's pat muxing for routing.
Index ¶
- type AfterHandler
- type Context
- type Glue
- func (r Glue) Add(meth, pat string, h Handler) *mux.Route
- func (g *Glue) AddHandler(handler Handler)
- func (r Glue) Delete(pat string, h Handler) *mux.Route
- func (r Glue) Get(pat string, h Handler) *mux.Route
- func (r Glue) Handle(w http.ResponseWriter, req *http.Request, c Context)
- func (g *Glue) Listen() error
- func (r Glue) Post(pat string, h Handler) *mux.Route
- func (r Glue) Put(pat string, h Handler) *mux.Route
- func (g *Glue) ServeHTTP(w http.ResponseWriter, r *http.Request)
- type Handler
- type ResponseHandler
- type ResponseWriter
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AfterHandler ¶
type AfterHandler func(Context)
AfterHandler is a type that a glue Handler can return and have it invoked after the default handler. This allows middleware to execute logic after a response has started. See github.com/tmc/glue/loggers for an example.
type Context ¶
Context represents the execution context for a request in Glue It is a DI (Dependency Injection) container and contains an augmented ResponseWriter
type Glue ¶
Glue is the primary struct that exposes routing and Handler registration
func New ¶
func New() *Glue
New prepares a new Glue instance and registers the default ResponseHandler
Example ¶
Example showing hello world in Glue
package main import ( "fmt" "io/ioutil" "net/http" "github.com/tmc/glue" ) func main() { g := glue.New() g.Get("/", func() string { return "hello world" }) go http.ListenAndServe(":5001", g) resp, _ := http.Get("http://127.0.0.1:5001/") body, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) }
Output: hello world
Example (MultiReturnAndByteSlice) ¶
Example showing returning a status code and a byte slice
package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "github.com/tmc/glue" ) func main() { g := glue.New() g.Get("/teapot", func(r *http.Request) (int, []byte) { teapot, _ := json.Marshal(struct { Teapot struct { IsReady bool } }{}) return http.StatusTeapot, teapot }) go http.ListenAndServe(":5002", g) resp, _ := http.Get("http://127.0.0.1:5002/teapot") body, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) }
Output: {"Teapot":{"IsReady":false}}
Example (RegisterExampleWithDB) ¶
Example showing the creation of a Glue instance and the registration of a sql.DB
package main import ( "database/sql" "fmt" "io/ioutil" "net/http" "os" "github.com/lib/pq" "github.com/tmc/glue" ) func main() { g := glue.New() url := os.Getenv("DATABASE_URL") connection, _ := pq.ParseURL(url) db, _ := sql.Open("postgres", connection) g.Register(db) g.Get("/", func(db *sql.DB) string { return fmt.Sprintf("db: %T\n", db) }) go http.ListenAndServe(":5003", g) resp, _ := http.Get("http://127.0.0.1:5003/") body, _ := ioutil.ReadAll(resp.Body) fmt.Println(resp.Status, string(body)) }
Output: 200 OK db: *sql.DB
func (*Glue) AddHandler ¶
Add adds a handler to the default set of handlers for a Glue instance
func (Glue) Handle ¶
func (r Glue) Handle(w http.ResponseWriter, req *http.Request, c Context)
Handle is a glue.Handler that does route matching and invokes the registered glue.Handler for a route.
If a route is not found the NotFoundHandler is invoked.
func (*Glue) Listen ¶
Listen attempts to ListenAndServe based on the environment variables HOST and PORT
Example ¶
Example showing the use of Listen, routing, logging and static file serving
package main import ( "fmt" "io/ioutil" "log" "net/http" "os" "github.com/tmc/glue" "github.com/tmc/glue/loggers" ) func main() { g := glue.New() // Register a new type with the underlying DI container g.Register(log.New(os.Stderr, "[glue example] ", log.LstdFlags)) // Add a new glue.Handler that will be invoked for each request g.AddHandler(loggers.NewApacheLogger()) // Add a handler using routing and parameter capture g.Get("/{type}_teapot", func(r *http.Request) (int, string) { return http.StatusTeapot, "that is " + r.URL.Query().Get(":type") + "!" }) // Serve static files g.Get("/", http.FileServer(http.Dir("./static/"))) go g.Listen() // listens on 5000 by default (uses PORT environtment variable) resp, err := http.Get("http://127.0.0.1:5000/purple_teapot") if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Println(resp.Status, string(body)) }
Output: 418 I'm a teapot that is purple!
type Handler ¶
type Handler interface{}
Handler is a generic type that must be a callable function.
It is invoked with the Call method of inj.Injector (http://godoc.org/github.com/tmc/inj#Injector.Call) which provides DI (Dependency Injection) based on the types of arguments it accepts.
Accepting a glue.Context allows you to inspect the DI container and examine the currently registered types.
The default registered ResponseHandler expects Handlers to return either one or two values.
If one value, it should return a string or a byte slice. If two values, the first should be an int which will be used as the return code.
type ResponseHandler ¶
type ResponseHandler func(http.ResponseWriter, []reflect.Value)
ResponseHandler is a type that writes an HTTP response given a slice of reflect.Value
type ResponseWriter ¶
type ResponseWriter struct { http.ResponseWriter Size int // the number of bytes that have been written as a response body Status int // the status code that has been written to the response (or zero if unwritten) }
ResponseWriter is an augmented http.ResponseWriter that exposes some additional fields
func (*ResponseWriter) Write ¶
func (rw *ResponseWriter) Write(b []byte) (int, error)
Write writes the data to the connection as part of an HTTP reply. If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) before writing the data. If the Header does not contain a Content-Type line, Write adds a Content-Type set to the result of passing the initial 512 bytes of written data to DetectContentType.
func (*ResponseWriter) WriteHeader ¶
func (rw *ResponseWriter) WriteHeader(status int)
WriteHeader sends an HTTP response header with status code. If WriteHeader is not called explicitly, the first call to Write will trigger an implicit WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly used to send error codes.
func (*ResponseWriter) WroteHeader ¶
func (rw *ResponseWriter) WroteHeader() bool
WroteHeader indicates if a header has been written (and a response has been started)
Directories
¶
Path | Synopsis |
---|---|
examples
|
|
panic_and_txn_example
Small usage example with panic recovery and database transaction management
|
Small usage example with panic recovery and database transaction management |