glue

package module
v0.0.0-...-3756f3c Latest Latest
Warning

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

Go to latest
Published: Feb 3, 2014 License: ISC Imports: 9 Imported by: 0

README

glue

import "github.com/tmc/glue"

Build Status

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).

Contributions welcome!

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!

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

type Context struct {
    inj.Injector
    // contains filtered or unexported fields
}

Context represents the execution context for a request in Glue It is a DI (Dependency Injection) container and contains an augmented ResponseWriter

type Glue

type Glue struct {
    inj.Injector
    // contains filtered or unexported fields
}

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

func (*Glue) Add
func (g *Glue) Add(handler Handler)

Add adds a handler to the default set of handlers for a Glue instance

func (Glue) Delete
func (r Glue) Delete(pat string, h Handler) *mux.Route

Delete registers a pattern with a handler for DELETE requests.

func (Glue) Get
func (r Glue) Get(pat string, h Handler) *mux.Route

Get registers a pattern with a handler for GET requests.

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
func (g *Glue) Listen()

Listen attempts to ListenAndServe based on the environment variables HOST and PORT

func (Glue) Post
func (r Glue) Post(pat string, h Handler) *mux.Route

Post registers a pattern with a handler for POST requests.

func (Glue) Put
func (r Glue) Put(pat string, h Handler) *mux.Route

Put registers a pattern with a handler for PUT requests.

func (*Glue) ServeHTTP
func (g *Glue) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP satisfies the http.Handler interface

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)

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

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

type Context struct {
	inj.Injector
	// contains filtered or unexported fields
}

Context represents the execution context for a request in Glue It is a DI (Dependency Injection) container and contains an augmented ResponseWriter

type Glue

type Glue struct {
	inj.Injector
	// contains filtered or unexported fields
}

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) Add

func (r Glue) Add(meth, pat string, h Handler) *mux.Route

Add registers a pattern with a handler for the given request method.

func (*Glue) AddHandler

func (g *Glue) AddHandler(handler Handler)

Add adds a handler to the default set of handlers for a Glue instance

func (Glue) Delete

func (r Glue) Delete(pat string, h Handler) *mux.Route

Delete registers a pattern with a handler for DELETE requests.

func (Glue) Get

func (r Glue) Get(pat string, h Handler) *mux.Route

Get registers a pattern with a handler for GET requests.

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

func (g *Glue) Listen() error

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!

func (Glue) Post

func (r Glue) Post(pat string, h Handler) *mux.Route

Post registers a pattern with a handler for POST requests.

func (Glue) Put

func (r Glue) Put(pat string, h Handler) *mux.Route

Put registers a pattern with a handler for PUT requests.

func (*Glue) ServeHTTP

func (g *Glue) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP satisfies the http.Handler interface

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

Jump to

Keyboard shortcuts

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