ship

package module
v4.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 28, 2021 License: Apache-2.0 Imports: 32 Imported by: 1

README

ship Build Status GoDoc License

ship is a flexible, powerful, high performance and minimalist Go Web HTTP router framework. It is inspired by echo and httprouter. Thanks for those contributors.

ship has been stable, and the current version is v4 and support Go 1.11+.

Features

  • Support the url parameter.
  • Support the session manager.
  • Support the customized router manager.
  • Support the pre-route and route middlewares.
  • Support the route group builder to build the route.
  • Support the mulit-virtual hosts and the default host.
  • Support the exact, prefix, suffix and regexp hostname.
  • Support the binding of the request data, such as body and query.
  • Support the renderer, such as the HTML template.
  • ......

Install

go get -u github.com/xgfone/ship/v4

Quick Start

// example.go
package main

import "github.com/xgfone/ship/v4"

func main() {
	router := ship.New()
	router.Route("/ping").GET(func(ctx *ship.Context) error {
		return ctx.JSON(200, map[string]interface{}{"message": "pong"})
	})

	// Start the HTTP server.
	router.Start(":8080").Wait()
	// or
	// http.ListenAndServe(":8080", router)
}
$ go run example.go
$ curl http://127.0.0.1:8080/ping
{"message":"pong"}
Route Path

The route path supports the parameters like :paramName, * or *restParamName.

  • /path/to/route only matches the path /path/to/route.
  • /path/:param1/to matches the path /path/abc/to, /path/xyz/to, etc. And :param1 is equal to abc or xyz.
  • /path/:param1/to/:param2 matches the path /path/p11/to/p21, /path/p12/to/p22, etc. And :parma1 is equal to p11 or p12, and :param2 is equal to p12 or p22.
  • /path/to/* or /path/to/*all matches the path /path/to/abc, /path/to/abc/efg, /path/to/xyz, /path/to/xyz/123, etc. And * or *all is equal to abc, abc/efg, xyz, or xzy/123. Notice: * or *restParamName must be the last one of the route path.
  • /path/:param/to/* matches the path /path/abc/to/efg, /path/abc/to/efg/123, etc. And :param is equal to abc, and * is equal to efg or efg/123

For the parameter, it can be accessed by Context.URLParam(paramName).

  • For *, the parameter name is *, like Context.URLParam("*").
  • For *restParamName, the parameter name is restParamName, like Context.URLParam(restParamName).

API Example

Router
Using CONNECT, GET, POST, PUT, PATCH, DELETE and OPTION
func main() {
    router := ship.New()
    router.Route("/path/get").GET(getHandler)
    router.Route("/path/put").PUT(putHandler)
    router.Route("/path/post").POST(postHandler)
    router.Route("/path/patch").PATCH(patchHandler)
    router.Route("/path/delete").DELETE(deleteHandler)
    router.Route("/path/option").OPTIONS(optionHandler)
    router.Route("/path/connect").CONNECT(connectHandler)
    router.Start(":8080").Wait()
}

Notice: you can register the same handler with more than one method by Route(path string).Method(handler Handler, method ...string).

Cascade the registered routes
func main() {
    router := ship.New()
    router.Route("/path/to").GET(getHandler).POST(postHandler).DELETE(deleteHandler)
    router.Start(":8080").Wait()
}

or use the mapping from method to handler:

func main() {
    router := ship.New()
    router.Route("/path/to").Map(map[string]ship.Handler{
        "GET": getHandler,
        "POST": postHandler,
        "DELETE": deleteHandler,
    })
    router.Start(":8080").Wait()
}
Naming route and building URL

When registering the route, it can be named with a name, then build a url path by the name.

func main() {
    router := ship.New()
    router.Route("/path/:id").Name("get_url").GET(func(ctx *ship.Context) error {
        fmt.Println(ctx.URLPath("get_url", ctx.URLParam("id")))
        return nil
    })
    router.Start(":8080").Wait()
}
Add the Header filter
func main() {
    router := ship.New()
    handler := func(ctx *ship.Context) error { return nil }

    // The Content-Type header of the request to /path2 must be application/json,
    // Or it will return 404.
    router.Route("/path2").HasHeader("Content-Type", "application/json").POST(handler)
    router.Start(":8080").Wait()
}
Using SubRouter
func main() {
    router := ship.New().Use(middleware.Logger(nil), middleware.Recover())

    // v1 SubRouter, which will inherit the middlewares of the parent router.
    v1 := router.Group("/v1")
    v1.Route("/get/path").GET(getHandler)

    // v2 SubRouter, which won't inherit the middlewares of the parent router.
    v2 := router.Group("/v2").NoMiddlewares().Use(MyAuthMiddleware())
    v2.Route("/post/path").POST(postHandler)

    router.Start(":8080").Wait()
}
Filter the unacceptable route
func filter(ri ship.RouteInfo) bool {
    if ri.Name == "" {
        return true
    } else if !strings.HasPrefix(ri.Path, "/prefix/") {
        return true
    }
    return false
}

func main() {
    // Don't register the router without name.
    app := ship.New()
    app.RouteFilter = filter

    app.Group("/prefix").Route("/name").Name("test").GET(handler) // Register the route
    app.Group("/prefix").Route("/noname").GET(handler)            // Don't register the route
    app.Route("/no_group").GET(handler)                           // Don't register the route
}
Modify the registered route
func modifier(ri ship.RouteInfo) ship.RouteInfo {
    ri.Path = "/prefix" + ri.Path
    return ri
}

func main() {
    app := ship.New()
    app.RouteModifier = modifier

    // Register the path as "/prefix/path".
    app.Route("/path").Name("test").GET(handler)
}
Using Middleware
package main

import (
    "net/http"

    "github.com/xgfone/ship/v4"
    "github.com/xgfone/ship/v4/middleware"
)

func main() {
    // We disable the default error log because we have used the Logger middleware.
    app := ship.New().Use(middleware.Logger(nil), middleware.Recover())
    app.Use(MyAuthMiddleware())
    app.Route("/url/path").GET(handler)
    app.Start(":8080").Wait()
}

You can register a Before middleware to be run before finding the router to affect the route match. For example,

package main

import (
    "net/http"

    "github.com/xgfone/ship/v4"
    "github.com/xgfone/ship/v4/middleware"
)

func RemovePathPrefix(prefix string) ship.Middleware {
    if len(prefix) < 2 || prefix[len(prefix)-1] == "/" {
        panic(fmt.Errorf("invalid prefix: '%s'", prefix))
    }

    return func(next ship.Handler) Handler {
        return func(ctx *ship.Context) error {
            req := ctx.Request()
            req.URL.Path = strings.TrimPrefix(req.URL.Path, prefix)
        }
    }
}

func main() {
    router := ship.New()

    // Use and Before have no interference each other.
    router.Use(middleware.Logger(nil))
    router.Pre(RemovePathPrefix("/static"))
    router.Use(middleware.Recover())

    router.Route("/url/path").GET(handler)
    router.Start(":8080").Wait()
}
Add the Virtual Host
package main

import "github.com/xgfone/ship/v4"

func main() {
	router := ship.New()
	router.Route("/").GET(func(c *ship.Context) error { return c.Text(200, "default") })

	// Exact Match Host
	vhost1 := router.Host("www.host1.example.com")
	vhost1.Route("/").GET(func(c *ship.Context) error { return c.Text(200, "vhost1") })

	// Suffix Match Host
	vhost2 := router.Host("*.host2.example.com")
	vhost2.Route("/").GET(func(c *ship.Context) error { return c.Text(200, "vhost2") })

	// Prefix Match Host
	vhost3 := router.Host("www.host3.*")
	vhost3.Route("/").GET(func(c *ship.Context) error { return c.Text(200, "vhost3") })

	// Regexp Match Host by using Go regexp package
	vhost4 := router.Host(`www\.[a-zA-z0-9]+\.example\.com`)
	vhost4.Route("/").GET(func(c *ship.Context) error { return c.Text(200, "vhost4") })

	router.Start(":8080").Wait()
}
$ curl http://127.0.0.1:8080/
default

$ curl http://127.0.0.1:8080/ -H 'Host: www.host1.example.com' # Exact
vhost1

$ curl http://127.0.0.1:8080/ -H 'Host: www.host2.example.com' # Suffix
vhost2

$ curl http://127.0.0.1:8080/ -H 'Host: www.host3.example.com' # Prefix
vhost3

$ curl http://127.0.0.1:8080/ -H 'Host: www.host4.example.com' # Regexp
vhost4
Handle the complex response
package main

import (
	"net/http"

	"github.com/xgfone/ship/v4"
)

func responder(ctx *ship.Context, args ...interface{}) error {
	switch len(args) {
	case 0:
		return ctx.NoContent(http.StatusOK)
	case 1:
		switch v := args[0].(type) {
		case int:
			return ctx.NoContent(v)
		case string:
			return ctx.Text(http.StatusOK, v)
		}
	case 2:
		switch v0 := args[0].(type) {
		case int:
			return ctx.Text(v0, "%v", args[1])
		}
	}
	return ctx.NoContent(http.StatusInternalServerError)
}

func main() {
	app := ship.New()
	app.Responder = responder
	app.Route("/path1").GET(func(c *ship.Context) error { return c.Respond() })
	app.Route("/path2").GET(func(c *ship.Context) error { return c.Respond(200) })
	app.Route("/path3").GET(func(c *ship.Context) error { return c.Respond("Hello, World") })
	app.Route("/path4").GET(func(c *ship.Context) error { return c.Respond(200, "Hello, World") })
	app.Start(":8080").Wait()
}
Bind JSON, XML or Form data form payload

ship supply a default data binding to bind the JSON, XML or Form data from payload.

type Login struct {
    Username string `json:"username" xml:"username"`
    Password string `json:"password" xml:"password"`
}

func main() {
    router := ship.Default()

    router.Route("/login").POST(func(ctx *ship.Context) error {
        var login Login
        if err := ctx.Bind(&login); err != nil {
            return err
        }
        ...
    })

    router.Start(":8080").Wait()
}
Render JSON, XML, HTML or other format data

In the directory /path/to/templates, there is a template file named index.tmpl as follow:

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        This is the body content: </pre>{{ . }}</pre>
    </body>
</html>

So we load it as the template by the stdlib html/template, and render it as the HTML content.

package main

import (
	"fmt"

	"github.com/xgfone/ship/v4"
	"github.com/xgfone/ship/v4/render"
	"github.com/xgfone/ship/v4/render/template"
)

func main() {
	// It will recursively load all the files in the directory as the templates.
	loader := template.NewDirLoader("/path/to/templates")
	tmplRender := template.NewHTMLTemplateRender(loader)

	router := ship.Default()
	router.Renderer.(*render.MuxRenderer).Add(".tmpl", tmplRender)

	// For JSON
	router.Route("/json").GET(func(ctx *ship.Context) error {
		if ctx.QueryParam("pretty") == "1" {
			return ctx.JSONPretty(200, map[string]interface{}{"msg": "json"}, "    ")
		}
		return ctx.JSON(200, map[string]interface{}{"msg": "json"})
	})

	// For XML
	router.Route("/xml").GET(func(ctx *ship.Context) error {
		if ctx.QueryParam("pretty") == "1" {
			return ctx.XMLPretty(200, []string{"msg", "xml"}, "    ")
		}
		return ctx.XML(200, []string{"msg", "xml"})
	})

	// For HTML
	router.Route("/html").GET(func(ctx *ship.Context) error {
		return ctx.RenderOk("index.tmpl", "Hello World")
	})

	// Start the HTTP server.
	router.Start(":8080").Wait()
}

When accessing http://127.0.0.1:8080/html, it returns

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        This is the body content: </pre>Hello World</pre>
    </body>
</html>
Prometheus Metric
package main

import (
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/xgfone/ship/v4"
)

func main() {
	app := ship.New()
	app.Route("/metrics").GET(ship.FromHTTPHandler(promhttp.Handler()))
	app.Start(":8080").Wait()
}

The default collectors can be disabled or removed like this.

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/xgfone/ship/v4"
)

// DisableBuiltinCollector removes the collectors that the default prometheus
// register registered.
func DisableBuiltinCollector() {
	prometheus.Unregister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
	prometheus.Unregister(prometheus.NewGoCollector())
}

func main() {
	DisableBuiltinCollector()
	app := ship.New()
	app.Route("/metrics").GET(ship.FromHTTPHandler(promhttp.Handler()))
	app.Start(":8080").Wait()
}

The default prometheus HTTP handler, promhttp.Handler(), will collect two metrics: promhttp_metric_handler_requests_in_flight and promhttp_metric_handler_requests_total{code="200/500/503"}. However, it can be rewrote like this.

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/expfmt"
	"github.com/xgfone/ship/v4"
)

// DisableBuiltinCollector removes the collectors that the default prometheus
// register registered.
func DisableBuiltinCollector() {
	prometheus.Unregister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
	prometheus.Unregister(prometheus.NewGoCollector())
}

// Prometheus returns a prometheus handler.
//
// if missing gatherer, it is prometheus.DefaultGatherer by default.
func Prometheus(gatherer ...prometheus.Gatherer) ship.Handler {
	gather := prometheus.DefaultGatherer
	if len(gatherer) > 0 && gatherer[0] != nil {
		gather = gatherer[0]
	}

	return func(ctx *ship.Context) error {
		mfs, err := gather.Gather()
		if err != nil {
			return err
		}

		ct := expfmt.Negotiate(ctx.Request().Header)
		ctx.SetContentType(string(ct))
		enc := expfmt.NewEncoder(ctx, ct)

		for _, mf := range mfs {
			if err = enc.Encode(mf); err != nil {
				ctx.Logger().Errorf("failed to encode prometheus metric: %s", err)
			}
		}

		return nil
	}
}

func main() {
	DisableBuiltinCollector()
	ship.New().Route("/metrics").GET(Prometheus()).Ship().Start(":8080").Wait()
}
OpenTracing
import (
	"fmt"
	"net/http"
	"net/url"

	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/xgfone/ship/v4"
)

// OpenTracingOption is used to configure the OpenTracingServer.
type OpenTracingOption struct {
	Tracer        opentracing.Tracer // Default: opentracing.GlobalTracer()
	ComponentName string             // Default: "net/http"

	// URLTagFunc is used to get the value of the tag "http.url".
	// Default: url.String()
	URLTagFunc func(*url.URL) string

	// SpanFilter is used to filter the span if returning true.
	// Default: return false
	SpanFilter func(*http.Request) bool

	// OperationNameFunc is used to the operation name.
	// Default: fmt.Sprintf("HTTP %s %s", r.Method, r.URL.Path)
	OperationNameFunc func(*http.Request) string

	// SpanObserver is used to do extra things of the span for the request.
	//
	// For example,
	//    OpenTracingOption {
	//        SpanObserver: func(*http.Request, opentracing.Span) {
	//            ext.PeerHostname.Set(span, req.Host)
	//        },
	//    }
	//
	// Default: Do nothing.
	SpanObserver func(*http.Request, opentracing.Span)
}

// Init initializes the OpenTracingOption.
func (o *OpenTracingOption) Init() {
	if o.ComponentName == "" {
		o.ComponentName = "net/http"
	}
	if o.URLTagFunc == nil {
		o.URLTagFunc = func(u *url.URL) string { return u.String() }
	}
	if o.SpanFilter == nil {
		o.SpanFilter = func(r *http.Request) bool { return false }
	}
	if o.SpanObserver == nil {
		o.SpanObserver = func(*http.Request, opentracing.Span) {}
	}
	if o.OperationNameFunc == nil {
		o.OperationNameFunc = func(r *http.Request) string {
			return fmt.Sprintf("HTTP %s %s", r.Method, r.URL.Path)
		}
	}
}

// GetTracer returns the OpenTracing tracker.
func (o *OpenTracingOption) GetTracer() opentracing.Tracer {
	if o.Tracer == nil {
		return opentracing.GlobalTracer()
	}
	return o.Tracer
}

// NewOpenTracingRoundTripper returns a new OpenTracingRoundTripper.
func NewOpenTracingRoundTripper(rt http.RoundTripper, opt *OpenTracingOption) *OpenTracingRoundTripper {
	var o OpenTracingOption
	if opt != nil {
		o = *opt
	}
	o.Init()
	return &OpenTracingRoundTripper{RoundTripper: rt, OpenTracingOption: o}
}

// WrappedRoundTripper returns the wrapped http.RoundTripper.
func (rt *OpenTracingRoundTripper) WrappedRoundTripper() http.RoundTripper {
	return rt.RoundTripper
}

func (rt *OpenTracingRoundTripper) roundTrip(req *http.Request) (*http.Response, error) {
	if rt.RoundTripper == nil {
		return http.DefaultTransport.RoundTrip(req)
	}
	return rt.RoundTripper.RoundTrip(req)
}

// RoundTrip implements the interface http.RounderTripper.
func (rt *OpenTracingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	if rt.SpanFilter(req) {
		return rt.roundTrip(req)
	}

	operationName := rt.OperationNameFunc(req)
	sp, ctx := opentracing.StartSpanFromContext(req.Context(), operationName)
	ext.HTTPMethod.Set(sp, req.Method)
	ext.Component.Set(sp, rt.ComponentName)
	ext.HTTPUrl.Set(sp, rt.URLTagFunc(req.URL))
	rt.SpanObserver(req, sp)
	defer sp.Finish()

	carrier := opentracing.HTTPHeadersCarrier(req.Header)
	rt.GetTracer().Inject(sp.Context(), opentracing.HTTPHeaders, carrier)

	return rt.roundTrip(req.WithContext(ctx))
}

// OpenTracing is a middleware to support the OpenTracing.
func OpenTracing(opt *OpenTracingOption) Middleware {
	var o OpenTracingOption
	if opt != nil {
		o = *opt
	}
	o.Init()

	const format = opentracing.HTTPHeaders
	return func(next ship.Handler) ship.Handler {
		return func(ctx *ship.Context) (err error) {
			req := ctx.Request()
			if o.SpanFilter(req) {
				return next(ctx)
			}

			tracer := o.GetTracer()
			sc, _ := tracer.Extract(format, opentracing.HTTPHeadersCarrier(req.Header))
			sp := tracer.StartSpan(o.OperationNameFunc(req), ext.RPCServerOption(sc))

			ext.HTTPMethod.Set(sp, req.Method)
			ext.Component.Set(sp, o.ComponentName)
			ext.HTTPUrl.Set(sp, o.URLTagFunc(req.URL))
			o.SpanObserver(req, sp)

			req = req.WithContext(opentracing.ContextWithSpan(req.Context(), sp))
			ctx.SetRequest(req)

			defer func() {
				if e := recover(); e != nil {
					ext.Error.Set(sp, true)
					sp.Finish()
					panic(e)
				}

				statusCode := ctx.StatusCode()
				if !ctx.IsResponded() {
					switch e := err.(type) {
					case nil:
					case ship.HTTPError:
						statusCode = e.Code
					default:
						statusCode = 500
					}
				}

				ext.HTTPStatusCode.Set(sp, uint16(statusCode))
				if statusCode >= 500 {
					ext.Error.Set(sp, true)
				}
				sp.Finish()
			}()

			err = next(ctx)
			return err
		}
	}
}

func init() {
	// TODO: Initialize the global OpenTracing tracer.

	// Replace the default global RoundTripper.
	http.DefaultTransport = NewOpenTracingRoundTripper(http.DefaultTransport, nil)
}

func main() {
	app := ship.Default()
	app.Use(OpenTracing(nil))
	app.Route("/").GET(func(c *ship.Context) error {
		ctx := c.Request().Context() // ctx contains the parent span context
		req, err := http.NewRequestWithContext(ctx, METHOD, URL, BODY)
		if err != nil {
			return
		}
		// TODO with req ...
	})
	app.Start(":8080").Wait()
}

Route Management

ship supply a default implementation based on Radix tree to manage the route with Zero Garbage (See Benchmark), which refers to echo, that's, NewRouter().

You can appoint your own implementation by implementing the interface Router.

type Router interface {
	// Routes uses the filter to filter and return the routes if it returns true.
	//
	// Return all the routes if filter is nil.
	Routes(filter func(name, path, method string) bool) []Route

	// Path generates a url path by the path name and parameters.
	//
	// Return "" if there is not the route path named name.
	Path(name string, params ...interface{}) string

	// Add adds the route and returns the number of the parameters
	// if there are the parameters in the route path.
	//
	// name is the name of the path, which is optional and must be unique
	// if not empty.
	//
	// If method is empty, handler is the handler of all the methods supported
	// by the implementation. Or, it is only that of the given method.
	//
	// For the parameter in the path, the format is determined by the implementation.
	Add(name, path, method string, handler interface{}) (paramNum int, err error)

	// Del deletes the given route.
	//
	// If method is empty, deletes all the routes associated with the path.
	// Or, only delete the given method for the path.
	Del(path, method string) (err error)

	// Match matches the route by path and method, puts the path parameters
	// into pnames and pvalues, then returns the handler and the number
	// of the path paramethers.
	//
	// If pnames or pvalues is empty, it will ignore the path paramethers
	// when finding the route handler.
	//
	// Return (nil, 0) if not found the route handler.
	Match(path, method string, pnames, pvalues []string) (handler interface{}, pn int)
}
func main() {
    NewMyRouter := func() ship.Router { return ... }
    router := ship.New().SetNewRouter(NewMyRouter)
    // ...
}

Benchmark

Test 1
Dell Vostro 3470
Intel Core i5-7400 3.0GHz
8GB DDR4 2666MHz
Windows 10
Go 1.13.4
Function ops ns/op bytes/opt allocs/op
BenchmarkGinStatic-4 23368 49788 8278 157
BenchmarkGinGitHubAPI-4 15684 75104 10849 203
BenchmarkGinGplusAPI-4 276224 4184 686 13
BenchmarkGinParseAPI-4 157810 7537 1357 26
BenchmarkEchoStatic-4 29432 39989 2432 157
BenchmarkEchoGitHubAPI-4 20527 56857 2468 203
BenchmarkEchoGplusAPI-4 387421 3179 193 13
BenchmarkEchoParseAPI-4 220273 5575 365 26
BenchmarkShipEchoStatic-4 34054 35548 1016 0
BenchmarkShipEchoGitHubAPI-4 21842 54962 1585 0
BenchmarkShipEchoGplusAPI-4 402898 2996 85 0
BenchmarkShipEchoParseAPI-4 223581 5478 154 0
Test 2
MacBook Pro(Retina, 13-inch, Mid 2014)
Intel Core i5 2.6GHz
8GB DDR3 1600MHz
macOS Mojave
Go 1.13.4
Function ops ns/op bytes/opt allocs/op
BenchmarkGinStatic-4 18085 62380 8494 157
BenchmarkGinGitHubAPI-4 12646 93052 11115 203
BenchmarkGinGplusAPI-4 224404 5222 701 13
BenchmarkGinParseAPI-4 124138 9442 1387 26
BenchmarkEchoStatic-4 22624 47401 2021 157
BenchmarkEchoGitHubAPI-4 16822 69059 2654 203
BenchmarkEchoGplusAPI-4 326142 3759 157 13
BenchmarkEchoParseAPI-4 178182 6713 402 26
BenchmarkShipEchoStatic-4 27048 43713 640 0
BenchmarkShipEchoGitHubAPI-4 17545 66953 987 0
BenchmarkShipEchoGplusAPI-4 318595 3698 54 0
BenchmarkShipEchoParseAPI-4 175984 6807 196 0

Documentation

Overview

Package ship has implemented a flexible, powerful, high performance and minimalist Go Web HTTP router framework, which is inspired by echo and httprouter.

Index

Examples

Constants

View Source
const (
	CharsetUTF8 = "charset=UTF-8"
	PROPFIND    = "PROPFIND"
)

Predefine some variables

View Source
const (
	MIMEApplicationJSON                  = "application/json"
	MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + CharsetUTF8
	MIMEApplicationJavaScript            = "application/javascript"
	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + CharsetUTF8
	MIMEApplicationXML                   = "application/xml"
	MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + CharsetUTF8
	MIMETextXML                          = "text/xml"
	MIMETextXMLCharsetUTF8               = MIMETextXML + "; " + CharsetUTF8
	MIMEApplicationForm                  = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf              = "application/protobuf"
	MIMEApplicationMsgpack               = "application/msgpack"
	MIMETextHTML                         = "text/html"
	MIMETextHTMLCharsetUTF8              = MIMETextHTML + "; " + CharsetUTF8
	MIMETextPlain                        = "text/plain"
	MIMETextPlainCharsetUTF8             = MIMETextPlain + "; " + CharsetUTF8
	MIMEMultipartForm                    = "multipart/form-data"
	MIMEOctetStream                      = "application/octet-stream"
)

MIME types

View Source
const (
	HeaderAccept              = "Accept"
	HeaderAcceptedLanguage    = "Accept-Language"
	HeaderAcceptEncoding      = "Accept-Encoding"
	HeaderAllow               = "Allow"
	HeaderAuthorization       = "Authorization"
	HeaderConnection          = "Connection"
	HeaderContentDisposition  = "Content-Disposition"
	HeaderContentEncoding     = "Content-Encoding"
	HeaderContentLength       = "Content-Length"
	HeaderContentType         = "Content-Type"
	HeaderCookie              = "Cookie"
	HeaderSetCookie           = "Set-Cookie"
	HeaderIfModifiedSince     = "If-Modified-Since"
	HeaderLastModified        = "Last-Modified"
	HeaderEtag                = "Etag"
	HeaderLocation            = "Location"
	HeaderUpgrade             = "Upgrade"
	HeaderVary                = "Vary"
	HeaderWWWAuthenticate     = "WWW-Authenticate"
	HeaderXForwardedFor       = "X-Forwarded-For"
	HeaderXForwardedProto     = "X-Forwarded-Proto"
	HeaderXForwardedProtocol  = "X-Forwarded-Protocol"
	HeaderXForwardedSsl       = "X-Forwarded-Ssl"
	HeaderXUrlScheme          = "X-Url-Scheme"
	HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
	HeaderXRealIP             = "X-Real-Ip"
	HeaderXServerID           = "X-Server-Id"
	HeaderXRequestID          = "X-Request-Id"
	HeaderXRequestedWith      = "X-Requested-With"
	HeaderServer              = "Server"
	HeaderOrigin              = "Origin"
	HeaderReferer             = "Referer"
	HeaderUserAgent           = "User-Agent"

	// Access control
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"

	// Security
	HeaderStrictTransportSecurity = "Strict-Transport-Security"
	HeaderXContentTypeOptions     = "X-Content-Type-Options"
	HeaderXXSSProtection          = "X-Xss-Protection"
	HeaderXFrameOptions           = "X-Frame-Options"
	HeaderContentSecurityPolicy   = "Content-Security-Policy"
	HeaderXCSRFToken              = "X-Csrf-Token"
)

Headers

Variables

View Source
var (
	MIMEApplicationJSONs                  = []string{MIMEApplicationJSON}
	MIMEApplicationJSONCharsetUTF8s       = []string{MIMEApplicationJSONCharsetUTF8}
	MIMEApplicationJavaScripts            = []string{MIMEApplicationJavaScript}
	MIMEApplicationJavaScriptCharsetUTF8s = []string{MIMEApplicationJavaScriptCharsetUTF8}
	MIMEApplicationXMLs                   = []string{MIMEApplicationXML}
	MIMEApplicationXMLCharsetUTF8s        = []string{MIMEApplicationXMLCharsetUTF8}
	MIMETextXMLs                          = []string{MIMETextXML}
	MIMETextXMLCharsetUTF8s               = []string{MIMETextXMLCharsetUTF8}
	MIMEApplicationForms                  = []string{MIMEApplicationForm}
	MIMEApplicationProtobufs              = []string{MIMEApplicationProtobuf}
	MIMEApplicationMsgpacks               = []string{MIMEApplicationMsgpack}
	MIMETextHTMLs                         = []string{MIMETextHTML}
	MIMETextHTMLCharsetUTF8s              = []string{MIMETextHTMLCharsetUTF8}
	MIMETextPlains                        = []string{MIMETextPlain}
	MIMETextPlainCharsetUTF8s             = []string{MIMETextPlainCharsetUTF8}
	MIMEMultipartForms                    = []string{MIMEMultipartForm}
	MIMEOctetStreams                      = []string{MIMEOctetStream}
)

MIME slice types

View Source
var (
	ErrMissingContentType    = errors.New("missing the header 'Content-Type'")
	ErrRendererNotRegistered = errors.New("renderer not registered")
	ErrInvalidRedirectCode   = errors.New("invalid redirect status code")
	ErrInvalidSession        = errors.New("invalid session")
	ErrSessionNotExist       = errors.New("session does not exist")
	ErrNoSessionSupport      = errors.New("no session support")
	ErrNoResponder           = errors.New("no responder")
)

Some non-HTTP Errors

Some HTTP error.

View Source
var DefaultShip = Default()

DefaultShip is the default global ship.

DefaultSignals is a set of default signals.

View Source
var ErrSkip = errors.New("skip")

ErrSkip is not an error, which is used to suggest that the middeware should skip and return it back to the outer middleware to handle.

Notice: it is only a suggestion.

View Source
var MaxMemoryLimit int64 = 32 << 20 // 32MB

MaxMemoryLimit is the maximum memory.

Functions

func AddContentTypeMapping

func AddContentTypeMapping(contentType string, contentTypeSlice []string)

AddContentTypeMapping add a content type mapping to convert contentType to contentTypeSlice, then call SetContentType to set the Content-Type to contentTypeSlice by contentType to avoid to allocate the memory.

func CopyNBuffer

func CopyNBuffer(dst io.Writer, src io.Reader, n int64, buf []byte) (written int64, err error)

CopyNBuffer is the same as io.CopyN, but uses the given buf as the buffer.

If buf is nil or empty, it will make a new one with 2048.

func DeleteJSON

func DeleteJSON(url string, req interface{}, resp interface{}) (err error)

DeleteJSON is the same as RequestJSON, but use the method DELETE instead, which may has the request body and the response body.

func DisalbeRedirect

func DisalbeRedirect(req *http.Request, via []*http.Request) error

DisalbeRedirect is used to disalbe the default redirect behavior of http.Client, that's, http.Client won't handle the redirect response and just return it to the caller.

func GetJSON

func GetJSON(url string, resp interface{}) (err error)

GetJSON is the same as RequestJSON, but use the method GET instead, which has no request body but has the response body if successfully.

func GetText

func GetText(url string) (body string, err error)

GetText is the same as GetJSON, but get the response body as the string, which has no request body but has the response body if successfully.

func HeadJSON

func HeadJSON(url string) (respHeader http.Header, err error)

HeadJSON is the same as RequestJSON, but use the method HEADE instead, which has no request or response body.

func InStrings

func InStrings(s string, ss []string) bool

InStrings reports whether s is in the string slice ss or not.

func IsInteger added in v4.1.0

func IsInteger(s string) bool

IsInteger reports whether s is the integer or not.

func NewRequestWithContext

func NewRequestWithContext(ctx context.Context, method, url string,
	body io.Reader) (*http.Request, error)

NewRequestWithContext is the compatibility of http.NewRequestWithContext.

func OptionsJSON

func OptionsJSON(url string, resp interface{}) (err error)

OptionsJSON is the same as RequestJSON, but use the method OPTIONS instead, which has no request body but has the response body if successfully.

func PatchJSON

func PatchJSON(url string, req interface{}, resp interface{}) (err error)

PatchJSON is the same as RequestJSON, but use the method PATCH instead, which has the request body and the response body if successfully.

func PostJSON

func PostJSON(url string, req interface{}, resp interface{}) (err error)

PostJSON is the same as RequestJSON, but use the method POST instead, which has the request body and the response body if successfully.

func PutJSON

func PutJSON(url string, req interface{}) (err error)

PutJSON is the same as RequestJSON, but use the method PUT instead, which has the request body but no response body.

func PutResponseIntoPool

func PutResponseIntoPool(r *Response)

PutResponseIntoPool puts a Response into the pool.

func Request

func Request(ctx context.Context, method, url string, reqHeader http.Header,
	reqBody, respBody interface{}) (err error)

Request sends the http request and parses the response body into respBody.

reqBody must be one of types:

  • nil
  • []byte
  • string
  • io.Reader
  • func() (io.Reader, error)

respBody must be one of types:

  • nil: ignore the response body.
  • *[]byte: read the response body and puts it into respBody as []byte.
  • *string: read the response body and puts it into respBody as string.
  • io.Writer: copy the response body into the given writer.
  • xml.Unmarshaler: read and parse the response body as the XML.
  • json.Unmarshaler: read and parse the response body as the JSON.
  • func(io.Reader) error: call the function with the response body.
  • func(*bytes.Buffer) error: read the response body into the buffer and call the function.
  • func(*http.Response) error: call the function with the response.

Notice: if the encoding of the response body is gzip, it will decode it firstly.

func RequestJSON

func RequestJSON(ctx context.Context, method, url string, reqHeader http.Header,
	reqBody, respBody interface{}) error

RequestJSON is the same as Request, but encodes the request and decodes response body as JSON.

func SetContentType

func SetContentType(res http.ResponseWriter, ct string)

SetContentType is equal to SetHeaderContentType(res.Header(), ct).

func SetHeaderContentType

func SetHeaderContentType(header http.Header, ct string)

SetHeaderContentType sets the Content-Type header to ct.

func SetStructFieldToDefault

func SetStructFieldToDefault(v interface{}) (err error)

SetStructFieldToDefault sets the default value of the fields of the pointer to struct v to the value of the tag "default" of the fields when the field value is ZERO.

For the type of the field, it only supports some base types as follow:

string
float32
float64
int
int8
int16
int32
int64
uint
uint8
uint16
uint32
uint64
struct
struct slice
interface{ SetDefault(_default interface{}) error }
time.Time      // Format: A. Integer(UTC); B. String(RFC3339)
time.Duration  // Format: A. Integer(ms);  B. String(time.ParseDuration)
pointer to the types above

Notice: If the tag value starts with ".", it represents a field name and the default value of current field is set to the value of that field. But their types must be consistent, or panic.

Example
type Struct struct {
	InnerInt int `default:"123"`
	_        int `default:"-"`
}

type S struct {
	Ignore  bool    `default:"true"`
	Int     int     `default:"123"`
	Int8    int8    `default:"123"`
	Int16   int16   `default:"123"`
	Int32   int32   `default:"123"`
	Int64   int64   `default:"123"`
	Uint    uint    `default:"123"`
	Uint8   uint8   `default:"123"`
	Uint16  uint16  `default:"123"`
	Uint32  uint32  `default:"123"`
	Uint64  uint64  `default:"123"`
	Uintptr uintptr `default:"123"`
	Float32 float32 `default:"1.2"`
	Float64 float64 `default:"1.2"`
	FloatN  float64 `default:".Float64"` // Set the default value to other field
	String  string  `default:"abc"`
	Struct  Struct
	Structs []Struct
	_       int `default:"-"`

	DurationInt time.Duration `default:"1000"`
	DurationStr time.Duration `default:"2s"`
	TimeInt     time.Time     `default:"1618059388"`
	TimeStr     time.Time     `default:"2021-04-10T12:56:28Z"`

	NoneP       *int
	IntPtr      *int           `default:"456"`
	TimePtr     *time.Time     `default:"2021-04-10T12:56:28Z"`
	DurationPtr *time.Duration `default:"3s"`
}

s := S{Structs: make([]Struct, 2)}
err := SetStructFieldToDefault(&s)
fmt.Println(err)

fmt.Println(s.Ignore)
fmt.Println(s.Int)
fmt.Println(s.Int8)
fmt.Println(s.Int16)
fmt.Println(s.Int32)
fmt.Println(s.Int64)
fmt.Println(s.Uint)
fmt.Println(s.Uint8)
fmt.Println(s.Uint16)
fmt.Println(s.Uint32)
fmt.Println(s.Uint64)
fmt.Println(s.Uintptr)
fmt.Println(s.Float32)
fmt.Println(s.Float64)
fmt.Println(s.FloatN)
fmt.Println(s.String)
fmt.Println(s.Struct.InnerInt)
fmt.Println(s.Structs[0].InnerInt)
fmt.Println(s.Structs[1].InnerInt)
fmt.Println(s.DurationInt)
fmt.Println(s.DurationStr)
fmt.Println(s.TimeInt.UTC().Format(time.RFC3339))
fmt.Println(s.TimeStr.UTC().Format(time.RFC3339))
fmt.Println(s.NoneP == nil)
fmt.Println(*s.IntPtr)
fmt.Println(s.TimePtr.UTC().Format(time.RFC3339))
fmt.Println(*s.DurationPtr)
Output:

<nil>
false
123
123
123
123
123
123
123
123
123
123
123
1.2
1.2
1.2
abc
123
123
123
1s
2s
2021-04-10T12:56:28Z
2021-04-10T12:56:28Z
true
456
2021-04-10T12:56:28Z
3s

func SplitHostPort

func SplitHostPort(hostport string) (host, port string)

SplitHostPort separates host and port. If the port is not valid, it returns the entire input as host, and it doesn't check the validity of the host. Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.

Example
var host, port string

host, port = SplitHostPort("www.example.com")
fmt.Printf("Host: %s, Port: %s#\n", host, port)

host, port = SplitHostPort("www.example.com:80")
fmt.Printf("Host: %s, Port: %s#\n", host, port)

host, port = SplitHostPort(":80")
fmt.Printf("Host: %s, Port: %s#\n", host, port)

host, port = SplitHostPort("1.2.3.4:80")
fmt.Printf("Host: %s, Port: %s#\n", host, port)

host, port = SplitHostPort("[fe80::1122:3344:5566:7788]")
fmt.Printf("Host: %s, Port: %s#\n", host, port)

host, port = SplitHostPort("[fe80::1122:3344:5566:7788]:80")
fmt.Printf("Host: %s, Port: %s#\n", host, port)
Output:

Host: www.example.com, Port: #
Host: www.example.com, Port: 80#
Host: , Port: 80#
Host: 1.2.3.4, Port: 80#
Host: fe80::1122:3344:5566:7788, Port: #
Host: fe80::1122:3344:5566:7788, Port: 80#

func ToHTTPHandler

func ToHTTPHandler(s *Ship, h Handler) http.Handler

ToHTTPHandler converts the Handler to http.Handler

Types

type Binder

type Binder interface {
	// Bind parses the data from http.Request to v.
	//
	// Notice: v must be a non-nil pointer.
	Bind(req *http.Request, v interface{}) error
}

Binder is the interface to bind the value to v from ctx.

func BinderFunc

func BinderFunc(f func(*http.Request, interface{}) error) Binder

BinderFunc converts a function to Binder.

func FormBinder

func FormBinder(maxMemory int64, tag ...string) Binder

FormBinder returns a Form binder to bind the Form request.

Notice: The bound value must be a pointer to a struct with the tag named tag, which is "form" by default.

func JSONBinder

func JSONBinder() Binder

JSONBinder returns a JSON binder to bind the JSON request.

func QueryBinder

func QueryBinder(tag ...string) Binder

QueryBinder returns a query binder to bind the query parameters..

Notice: The bound value must be a pointer to a struct with the tag named tag, which is "query" by default.

func XMLBinder

func XMLBinder() Binder

XMLBinder returns a XML binder to bind the XML request.

type BufferAllocator

type BufferAllocator interface {
	AcquireBuffer() *bytes.Buffer
	ReleaseBuffer(*bytes.Buffer)
}

BufferAllocator is used to acquire and release a buffer.

type Context

type Context struct {
	// RouteInfo is the route information associated with the route.
	RouteInfo RouteInfo

	// Data is used to store many key-value pairs about the context.
	//
	// Data maybe asks the system to allocate many memories. In order
	// to avoid it and if the interim context values is too few,
	// the context also defines three variables to resolve it.
	//
	// Notice: when the new request is coming, they will be reset to nil.
	Key1 interface{}
	Key2 interface{}
	Key3 interface{}
	Data map[string]interface{}
	// contains filtered or unexported fields
}

Context represetns a request and response context.

func NewContext

func NewContext(urlParamMaxNum, dataInitCap int) *Context

NewContext returns a new Context.

func (*Context) Accept

func (c *Context) Accept() []string

Accept returns the content of the header Accept.

If there is no the header Accept , it return nil.

Notice:

  1. It will sort the content by the q-factor weighting.
  2. If the value is "<MIME_type>/*", it will be amended as "<MIME_type>/". So it can be used to match the prefix.
  3. If the value is "*/*", it will be amended as "".

func (*Context) AcquireBuffer

func (c *Context) AcquireBuffer() *bytes.Buffer

AcquireBuffer acquires a buffer.

Notice: you should call ReleaseBuffer() to release it.

func (*Context) AddHeader

func (c *Context) AddHeader(name, value string)

AddHeader appends the value for the response header name.

func (*Context) Attachment

func (c *Context) Attachment(file string, name string) error

Attachment sends a response as attachment, prompting client to save the file.

If the file does not exist, it returns ErrNotFound.

func (*Context) BasicAuth

func (c *Context) BasicAuth() (username, password string, ok bool)

BasicAuth returns the username and password from the request.

func (*Context) Bind

func (c *Context) Bind(v interface{}) (err error)

Bind binds the request information into the provided value v.

The default binder does it based on Content-Type header.

Notice: it will call the interfaces or functions in turn as follow:

  1. Binder
  2. SetDefault
  3. Validator

func (*Context) BindQuery

func (c *Context) BindQuery(v interface{}) (err error)

BindQuery binds the request URL query into the provided value v.

Notice: it will call the interfaces or functions in turn as follow:

  1. QueryBinder
  2. SetDefault
  3. Validator

func (*Context) Blob

func (c *Context) Blob(code int, contentType string, b []byte) (err error)

Blob sends a blob response with status code and content type.

func (*Context) BlobText

func (c *Context) BlobText(code int, contentType string, format string,
	args ...interface{}) (err error)

BlobText sends a string blob response with status code and content type.

func (*Context) Body

func (c *Context) Body() io.ReadCloser

Body returns the reader of the request body.

func (*Context) Charset

func (c *Context) Charset() string

Charset returns the charset of the request content.

Return "" if there is no charset.

func (*Context) ClearData

func (c *Context) ClearData()

ClearData clears the data.

func (*Context) ClientIP

func (c *Context) ClientIP() string

ClientIP returns the real client's network address based on `X-Forwarded-For` or `X-Real-IP` request header. Or returns the remote address.

func (*Context) ContentLength

func (c *Context) ContentLength() int64

ContentLength return the length of the request body.

func (*Context) ContentType

func (c *Context) ContentType() (ct string)

ContentType returns the Content-Type of the request without the charset.

func (*Context) Cookie

func (c *Context) Cookie(name string) *http.Cookie

Cookie returns the named cookie provided in the request.

Return nil if no the cookie named name.

func (*Context) Cookies

func (c *Context) Cookies() []*http.Cookie

Cookies returns the HTTP cookies sent with the request.

func (*Context) DelHeader

func (c *Context) DelHeader(name string)

DelHeader deletes the header named name from the response.

func (*Context) DelSession

func (c *Context) DelSession(id string) (err error)

DelSession deletes the session from the backend store.

func (*Context) Error

func (c *Context) Error(code int, err error) HTTPServerError

Error sends an error response with status code.

func (*Context) Execute

func (c *Context) Execute() error

Execute finds the route and calls the handler.

SetRouter must be called before calling Execute, which be done by the framework.

func (*Context) File

func (c *Context) File(file string) (err error)

File sends a response with the content of the file.

If the file does not exist, it returns ErrNotFound.

If not set the Content-Type, it will deduce it from the extension of the file name.

func (*Context) FindRoute

func (c *Context) FindRoute() (ok bool)

FindRoute finds the route from the router.

func (*Context) FormFile

func (c *Context) FormFile(name string) (multipart.File, *multipart.FileHeader, error)

FormFile returns the multipart form file for the provided name.

func (*Context) FormParams

func (c *Context) FormParams() (url.Values, error)

FormParams returns the form parameters as `url.Values`.

func (*Context) FormValue

func (c *Context) FormValue(name string, defaultValue ...string) string

FormValue returns the form field value for the provided name.

func (*Context) GetBody

func (c *Context) GetBody() (string, error)

GetBody reads all the contents from the body and returns it as string.

func (*Context) GetBodyReader

func (c *Context) GetBodyReader() (buf *bytes.Buffer, err error)

GetBodyReader reads all the contents from the body to buffer and returns it.

Notice: You should call ReleaseBuffer(buf) to release the buffer at last.

func (*Context) GetHeader

func (c *Context) GetHeader(name string, defaultValue ...string) string

GetHeader returns the first value of the request header named name.

Return "" if the header does not exist.

func (*Context) GetSession

func (c *Context) GetSession(id string) (v interface{}, err error)

GetSession returns the session content by id from the backend store.

If the session id does not exist, it returns ErrSessionNotExist.

func (*Context) HTML

func (c *Context) HTML(code int, html string) error

HTML sends an HTTP response with status code.

func (*Context) HTMLBlob

func (c *Context) HTMLBlob(code int, b []byte) error

HTMLBlob sends an HTTP blob response with status code.

func (*Context) HasHeader

func (c *Context) HasHeader(name string) bool

HasHeader reports whether the request header named name exists or not.

func (*Context) HasQuery

func (c *Context) HasQuery(name string) bool

HasQuery reports whether the query argument named name exists or not.

func (*Context) Header

func (c *Context) Header() http.Header

Header is the alias of RespHeader to implement the interface http.ResponseWriter.

func (*Context) Host

func (c *Context) Host() string

Host returns the host of the request.

func (*Context) Hostname

func (c *Context) Hostname() string

Hostname returns the hostname of the request.

func (*Context) Inline

func (c *Context) Inline(file string, name string) error

Inline sends a response as inline, opening the file in the browser.

If the file does not exist, it returns ErrNotFound.

func (*Context) IsAjax

func (c *Context) IsAjax() bool

IsAjax reports whether the request is ajax or not.

func (*Context) IsResponded

func (c *Context) IsResponded() bool

IsResponded reports whether the response is sent.

func (*Context) IsTLS

func (c *Context) IsTLS() bool

IsTLS reports whether HTTP connection is TLS or not.

func (*Context) IsWebSocket

func (c *Context) IsWebSocket() bool

IsWebSocket reports whether HTTP connection is WebSocket or not.

func (*Context) JSON

func (c *Context) JSON(code int, v interface{}) error

JSON sends a JSON response with status code.

func (*Context) JSONBlob

func (c *Context) JSONBlob(code int, b []byte) error

JSONBlob sends a JSON blob response with status code.

func (*Context) JSONP

func (c *Context) JSONP(code int, callback string, i interface{}) error

JSONP sends a JSONP response with status code. It uses `callback` to construct the JSONP payload.

func (*Context) JSONPBlob

func (c *Context) JSONPBlob(code int, callback string, b []byte) (err error)

JSONPBlob sends a JSONP blob response with status code. It uses `callback` to construct the JSONP payload.

func (*Context) JSONPretty

func (c *Context) JSONPretty(code int, v interface{}, indent string) error

JSONPretty sends a pretty-print JSON with status code.

func (*Context) Logger

func (c *Context) Logger() Logger

Logger returns the logger.

func (*Context) Method

func (c *Context) Method() string

Method returns the method of the request.

func (*Context) MultipartForm

func (c *Context) MultipartForm() (*multipart.Form, error)

MultipartForm returns the multipart form.

func (*Context) MultipartReader

func (c *Context) MultipartReader() (*multipart.Reader, error)

MultipartReader returns the multipart reader from the request.

func (*Context) NoContent

func (c *Context) NoContent(code int) error

NoContent sends a response with no body and a status code.

func (*Context) NotFoundHandler

func (c *Context) NotFoundHandler() Handler

NotFoundHandler returns the NotFound Handler, but returns nil instead if not set.

func (*Context) Path

func (c *Context) Path() string

Path returns the path of the request.

func (*Context) QueryParam

func (c *Context) QueryParam(name string, defaultValue ...string) string

QueryParam returns the query param for the provided name.

func (*Context) QueryParams

func (c *Context) QueryParams() url.Values

QueryParams returns the query parameters as `url.Values`.

func (*Context) QueryRawString

func (c *Context) QueryRawString() string

QueryRawString returns the URL query string.

func (*Context) Redirect

func (c *Context) Redirect(code int, toURL string) error

Redirect redirects the request to a provided URL with status code.

func (*Context) Referer

func (c *Context) Referer() string

Referer returns the Referer header of the request.

func (*Context) ReleaseBuffer

func (c *Context) ReleaseBuffer(buf *bytes.Buffer)

ReleaseBuffer releases a buffer into the pool.

func (*Context) RemoteAddr

func (c *Context) RemoteAddr() string

RemoteAddr returns the remote address of the http connection.

func (*Context) Render

func (c *Context) Render(name string, code int, data interface{}) error

Render renders a template named name with data and sends a text/html response with status code.

func (*Context) RenderOk

func (c *Context) RenderOk(name string, data interface{}) error

RenderOk is short for c.Render(name, http.StatusOK, data).

func (*Context) ReqHeader

func (c *Context) ReqHeader() http.Header

ReqHeader returns the header of the request.

func (*Context) Request

func (c *Context) Request() *http.Request

Request returns the inner Request.

func (*Context) RequestURI

func (c *Context) RequestURI() string

RequestURI returns the URI of the request.

func (*Context) Reset

func (c *Context) Reset()

Reset resets the context to the initalizing state.

func (*Context) RespHeader

func (c *Context) RespHeader() http.Header

RespHeader returns the header of the response.

func (*Context) Respond

func (c *Context) Respond(args ...interface{}) error

Respond calls the context handler set by SetHandler.

Return ErrNoResponder if the context handler or the global handler is not set.

func (*Context) Response

func (c *Context) Response() *Response

Response returns the inner Response.

func (*Context) ResponseWriter

func (c *Context) ResponseWriter() http.ResponseWriter

ResponseWriter returns the underlying http.ResponseWriter.

func (*Context) Router

func (c *Context) Router() Router

Router returns the router.

func (*Context) Scheme

func (c *Context) Scheme() (scheme string)

Scheme returns the HTTP protocol scheme, `http` or `https`.

func (*Context) SetBinder

func (c *Context) SetBinder(b Binder)

SetBinder sets the binder to b to bind the request information to an object.

func (*Context) SetBufferAllocator

func (c *Context) SetBufferAllocator(alloc BufferAllocator)

SetBufferAllocator sets the buffer allocator to alloc.

func (*Context) SetConnectionClose

func (c *Context) SetConnectionClose()

SetConnectionClose tell the server to close the connection.

func (*Context) SetContentType

func (c *Context) SetContentType(ct string)

SetContentType sets the Content-Type header of the response body to ct, but does nothing if contentType is "".

func (*Context) SetCookie

func (c *Context) SetCookie(cookie *http.Cookie)

SetCookie adds a `Set-Cookie` header in HTTP response.

func (*Context) SetDefault

func (c *Context) SetDefault(v interface{}) error

SetDefault calls the default setter to set the default value of v.

func (*Context) SetDefaulter

func (c *Context) SetDefaulter(v func(interface{}) error)

SetDefaulter sets the default setter to v set the default value.

func (*Context) SetHeader

func (c *Context) SetHeader(name, value string)

SetHeader sets the response header name to value.

func (*Context) SetLogger

func (c *Context) SetLogger(logger Logger)

SetLogger sets the logger to logger.

func (*Context) SetNotFoundHandler

func (c *Context) SetNotFoundHandler(notFound Handler)

SetNotFoundHandler sets the NotFound handler.

func (*Context) SetQueryBinder

func (c *Context) SetQueryBinder(f func(interface{}, url.Values) error)

SetQueryBinder sets the query binder to f to bind the url query to an object.

func (*Context) SetRenderer

func (c *Context) SetRenderer(r Renderer)

SetRenderer sets the renderer to r to render the response to the peer.

func (*Context) SetReqRes

func (c *Context) SetReqRes(r *http.Request, w http.ResponseWriter)

SetReqRes is the same as Reset, but only reset the request and response, not all things.

func (*Context) SetRequest

func (c *Context) SetRequest(req *http.Request)

SetRequest resets the request to req.

func (*Context) SetResponder

func (c *Context) SetResponder(h func(*Context, ...interface{}) error)

SetResponder sets the responder to handle the complicated response.

For example,

responder := func(ctx *Context, args ...interface{}) error {
    switch len(args) {
    case 0:
        return ctx.NoContent(http.StatusOK)
    case 1:
        switch v := args[0].(type) {
        case int:
            return ctx.NoContent(v)
        case string:
            return ctx.Text(http.StatusOK, v)
        }
    case 2:
        switch v0 := args[0].(type) {
        case int:
            return ctx.Text(v0, "%v", args[1])
        }
    }
    return ctx.NoContent(http.StatusInternalServerError)
}

router := New()
router.Responder =responder
router.Route("/path1").GET(func(c *Context) error { return c.Handle() })
router.Route("/path2").GET(func(c *Context) error { return c.Handle(200) })
router.Route("/path3").GET(func(c *Context) error { return c.Handle("Hello, World") })
router.Route("/path4").GET(func(c *Context) error { return c.Handle(200, "Hello, World") })

func (*Context) SetResponse

func (c *Context) SetResponse(res http.ResponseWriter)

SetResponse resets the response to resp, which will ignore nil.

func (*Context) SetRouter

func (c *Context) SetRouter(r Router)

SetRouter sets the router to r.

func (*Context) SetSession

func (c *Context) SetSession(id string, value interface{}) (err error)

SetSession sets the session to the backend store.

func (*Context) SetSessionManagement

func (c *Context) SetSessionManagement(s Session)

SetSessionManagement sets the session management to s.

func (*Context) SetValidator

func (c *Context) SetValidator(v func(interface{}) error)

SetValidator sets the validator to v to validate the argument when Binding.

func (*Context) StatusCode

func (c *Context) StatusCode() int

StatusCode returns the status code of the response.

func (*Context) Stream

func (c *Context) Stream(code int, contentType string, r io.Reader) (err error)

Stream sends a streaming response with status code and content type.

func (*Context) Text

func (c *Context) Text(code int, format string, args ...interface{}) error

Text sends a string response with status code.

func (*Context) URLParam

func (c *Context) URLParam(name string) string

URLParam returns the parameter value in the url path by name.

func (*Context) URLParamNames

func (c *Context) URLParamNames() []string

URLParamNames returns the names of all the URL parameters.

func (*Context) URLParamValues

func (c *Context) URLParamValues() []string

URLParamValues returns the values of all the URL parameters.

func (*Context) URLParams

func (c *Context) URLParams() map[string]string

URLParams returns all the parameters as the key-value map in the url path.

func (*Context) URLPath

func (c *Context) URLPath(name string, params ...interface{}) string

URLPath generates a url path by the route path name and provided parameters.

Return "" if there is not the route named name.

func (*Context) UserAgent

func (c *Context) UserAgent() string

UserAgent returns the User-Agent header of the request.

func (*Context) Validate

func (c *Context) Validate(v interface{}) error

Validate validates whether the argument v is valid.

func (*Context) Write

func (c *Context) Write(b []byte) (int, error)

Write writes the content to the peer, which implements the interface http.ResponseWriter.

it will write the header firstly with 200 if the header is not sent.

func (*Context) WriteHeader

func (c *Context) WriteHeader(statusCode int)

WriteHeader sends an HTTP response header with the provided status code, which implements the interface http.ResponseWriter.

func (*Context) XML

func (c *Context) XML(code int, v interface{}) error

XML sends an XML response with status code.

func (*Context) XMLBlob

func (c *Context) XMLBlob(code int, b []byte) (err error)

XMLBlob sends an XML blob response with status code.

func (*Context) XMLPretty

func (c *Context) XMLPretty(code int, v interface{}, indent string) error

XMLPretty sends a pretty-print XML with status code.

type HTTPClientError

type HTTPClientError struct {
	Code   int    `json:"code" xml:"code"`
	Method string `json:"method" xml:"method"`
	URL    string `json:"url" xml:"url"`
	Data   string `json:"data" xml:"data"`
	Err    error  `json:"err" xml:"err"`
}

HTTPClientError represents an error about the http client response.

func NewHTTPClientError

func NewHTTPClientError(method, url string, code int, err error,
	data ...string) HTTPClientError

NewHTTPClientError returns a new HTTPClientError.

func (HTTPClientError) Error

func (e HTTPClientError) Error() string

func (HTTPClientError) String

func (e HTTPClientError) String() string

func (HTTPClientError) Unwrap

func (e HTTPClientError) Unwrap() error

type HTTPServerError

type HTTPServerError struct {
	Code int
	Err  error
	CT   string // Content-Type
}

HTTPServerError represents a server error with HTTP Status Code.

func NewHTTPServerError

func NewHTTPServerError(code int, msg ...string) HTTPServerError

NewHTTPServerError returns a new HTTPServerError.

func (HTTPServerError) Error

func (e HTTPServerError) Error() string

func (HTTPServerError) New

New returns a new HTTPError with the new error.

func (HTTPServerError) NewCT

NewCT returns a new HTTPError with the new ContentType ct.

func (HTTPServerError) Newf

func (e HTTPServerError) Newf(msg string, args ...interface{}) HTTPServerError

Newf is equal to New(fmt.Errorf(msg, args...)).

func (HTTPServerError) Unwrap

func (e HTTPServerError) Unwrap() error

Unwrap unwraps the inner error.

type Handler

type Handler func(*Context) error

Handler is a handler of the HTTP request.

func FromHTTPHandler

func FromHTTPHandler(h http.Handler) Handler

FromHTTPHandler converts http.Handler to Handler.

func FromHTTPHandlerFunc

func FromHTTPHandlerFunc(h http.HandlerFunc) Handler

FromHTTPHandlerFunc converts http.HandlerFunc to Handler.

func MethodNotAllowedHandler

func MethodNotAllowedHandler(allowedMethods []string) Handler

MethodNotAllowedHandler returns a MethodNotAllowed handler.

func NotFoundHandler

func NotFoundHandler() Handler

NotFoundHandler returns a NotFound handler.

func NothingHandler

func NothingHandler() Handler

NothingHandler returns a Handler doing nothing.

func OkHandler

func OkHandler() Handler

OkHandler returns a Handler only sending the response "200 OK"

func (Handler) HTTPHandler

func (h Handler) HTTPHandler(s *Ship) http.Handler

HTTPHandler converts itself to http.Handler.

s may be nil.

type Logger

type Logger interface {
	Tracef(format string, args ...interface{})
	Debugf(format string, args ...interface{})
	Infof(format string, args ...interface{})
	Warnf(format string, args ...interface{})
	Errorf(format string, args ...interface{})
}

Logger is logger interface.

Notice: The implementation maybe also has the method { Writer() io.Writer } to get the underlynig writer.

func NewLoggerFromStdlog

func NewLoggerFromStdlog(logger *log.Logger) Logger

NewLoggerFromStdlog converts stdlib log to Logger.

Notice: the returned logger has also implemented the interface { Writer() io.Writer }.

func NewLoggerFromWriter

func NewLoggerFromWriter(w io.Writer, prefix string, flags ...int) Logger

NewLoggerFromWriter returns a new logger by creating a new stdlib log.

Notice: the returned logger has also implemented the interface { Writer() io.Writer }.

type Middleware

type Middleware func(Handler) Handler

Middleware represents a middleware.

type MuxBinder

type MuxBinder struct {
	// contains filtered or unexported fields
}

MuxBinder is a multiplexer for kinds of Binders based on the Content-Type.

func NewMuxBinder

func NewMuxBinder() *MuxBinder

NewMuxBinder returns a new MuxBinder.

func (*MuxBinder) Add

func (mb *MuxBinder) Add(contentType string, binder Binder)

Add adds a binder to bind the content for the header Content-Type.

func (*MuxBinder) Bind

func (mb *MuxBinder) Bind(req *http.Request, v interface{}) error

Bind implements the interface Binder, which will call the registered binder to bind the request to v by the request header Content-Type.

func (*MuxBinder) Del

func (mb *MuxBinder) Del(contentType string)

Del removes the corresponding binder by the header Content-Type.

func (*MuxBinder) Get

func (mb *MuxBinder) Get(contentType string) Binder

Get returns the corresponding binder by the header Content-Type.

Return nil if not found.

type MuxRenderer

type MuxRenderer struct {
	// contains filtered or unexported fields
}

MuxRenderer is a multiplexer for kinds of Renderers.

func NewMuxRenderer

func NewMuxRenderer() *MuxRenderer

NewMuxRenderer returns a new MuxRenderer.

func (*MuxRenderer) Add

func (mr *MuxRenderer) Add(suffix string, renderer Renderer)

Add adds a renderer with a suffix identifier.

func (*MuxRenderer) Del

func (mr *MuxRenderer) Del(suffix string)

Del removes the corresponding renderer by the suffix.

func (*MuxRenderer) Get

func (mr *MuxRenderer) Get(suffix string) Renderer

Get returns the corresponding renderer by the suffix.

Return nil if not found.

func (*MuxRenderer) Render

func (mr *MuxRenderer) Render(w http.ResponseWriter, name string, code int, data interface{}) error

Render implements the interface Renderer, which will get the renderer the name suffix then render the content.

type OnceRunner

type OnceRunner struct {
	// contains filtered or unexported fields
}

OnceRunner is used to run the task only once, which is different from sync.Once, the second calling does not wait until the first calling finishes.

func NewOnceRunner

func NewOnceRunner(task func()) *OnceRunner

NewOnceRunner returns a new OnceRunner.

func (*OnceRunner) Run

func (r *OnceRunner) Run()

Run runs the task.

type RWLocker

type RWLocker interface {
	RLock()
	RUnlock()
	sync.Locker
}

RWLocker represents an object that can be locked and unlocked with read and write.

func NewNoopRWLocker

func NewNoopRWLocker() RWLocker

NewNoopRWLocker returns a No-Op RLocker, which does nothing.

type RegexpHostRouter

type RegexpHostRouter interface {
	// Len returns the number of the regexp host routers.
	Len() int

	// Range is used to traverse all the regexp host routers.
	Range(func(regexpHost string, router Router))

	// Add adds and returns the regexp host router.
	//
	// If the regexp host has been added, do nothing and return the added router.
	Add(regexpHost string, router Router) (Router, error)

	// Del deletes and returns the regexp host router.
	//
	// If the regexp host router does not exist, return nil.
	Del(regexpHost string) Router

	// Router accurately returns the router by the regexp host.
	//
	// If the regexp host router does not exist, return nil.
	Router(regexpHost string) Router

	// Match matches the host and returns the corresponding router information.
	//
	// If there is no regexp host router to match it, return ("", nil).
	Match(host string) (matchedRegexpHost string, matchedRouter Router)
}

RegexpHostRouter is the manager to match the host by the regular expression.

func NewRegexpHostRouter

func NewRegexpHostRouter() RegexpHostRouter

NewRegexpHostRouter returns a new RegexpHostRouter, which uses the stdlib "regexp" to implement the regular expression syntax of Golang.

For the golang regexp syntax, see https://pkg.go.dev/regexp/syntax.

type Renderer

type Renderer interface {
	Render(w http.ResponseWriter, name string, code int, data interface{}) error
}

Renderer is the interface to render the response.

func RendererFunc

func RendererFunc(f func(http.ResponseWriter, string, int, interface{}) error) Renderer

RendererFunc converts a function to Renderer.

type Response

type Response struct {
	http.ResponseWriter

	Size   int64
	Wrote  bool
	Status int
}

Response implements http.ResponseWriter.

func GetResponseFromPool

func GetResponseFromPool(w http.ResponseWriter) *Response

GetResponseFromPool returns a Response from the pool.

func NewResponse

func NewResponse(w http.ResponseWriter) *Response

NewResponse returns a new instance of Response.

func (*Response) Flush

func (r *Response) Flush()

Flush implements the http.Flusher interface to allow an HTTP handler to flush buffered data to the client.

See http.Flusher(https://golang.org/pkg/net/http/#Flusher)

func (*Response) Hijack

func (r *Response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error)

Hijack implements the http.Hijacker interface to allow an HTTP handler to take over the connection.

See http.Hijacker(https://golang.org/pkg/net/http/#Hijacker)

func (*Response) Push

func (r *Response) Push(target string, opts *http.PushOptions) error

Push implements the http.Pusher interface to support HTTP/2 server push.

See http.Pusher(https://golang.org/pkg/net/http/#Pusher)

func (*Response) Reset

func (r *Response) Reset(w http.ResponseWriter)

Reset resets the response to the initialized and returns itself.

func (*Response) SetWriter

func (r *Response) SetWriter(w http.ResponseWriter)

SetWriter resets the writer to w and return itself.

func (*Response) Write

func (r *Response) Write(b []byte) (n int, err error)

Write implements http.ResponseWriter#Writer().

func (*Response) WriteHeader

func (r *Response) WriteHeader(code int)

WriteHeader implements http.ResponseWriter#WriteHeader().

func (*Response) WriteString

func (r *Response) WriteString(s string) (n int, err error)

WriteString implements io.StringWriter.

type Route

type Route struct {
	// contains filtered or unexported fields
}

Route represents a route information.

func (*Route) Any

func (r *Route) Any(handler Handler) *Route

Any registers all the supported methods , which is short for r.Method(handler, "")

func (*Route) CONNECT

func (r *Route) CONNECT(handler Handler) *Route

CONNECT is the short for r.Method(handler, "CONNECT").

func (*Route) Clone

func (r *Route) Clone() *Route

Clone closes itself and returns a new one.

func (*Route) CtxData

func (r *Route) CtxData(data interface{}) *Route

CtxData sets the context data on the route.

func (*Route) DELETE

func (r *Route) DELETE(handler Handler) *Route

DELETE is the short for r.Method(handler, "DELETE").

func (*Route) GET

func (r *Route) GET(handler Handler) *Route

GET is the short for r.Method(handler, "GET").

func (*Route) Group

func (r *Route) Group() *RouteGroup

Group returns the group that the current route belongs to.

Notice: it will return nil if the route is from ship.Route.

func (*Route) HEAD

func (r *Route) HEAD(handler Handler) *Route

HEAD is the short for r.Method(handler, "HEAD").

func (*Route) HasHeader

func (r *Route) HasHeader(headerK string, headerV ...string) *Route

HasHeader checks whether the request contains the request header. If no, the request will be rejected.

If the header value is given, it will be tested to match, for example

s := ship.New()
// The request must contains the header "Content-Type: application/json".
s.R("/path/to").HasHeader("Content-Type", "application/json").POST(handler)

func (*Route) Host

func (r *Route) Host(host string) *Route

Host sets the host of the route to host.

func (*Route) Map

func (r *Route) Map(method2handlers map[string]Handler) *Route

Map registers a group of methods with handlers, which is equal to

for method, handler := range method2handlers {
    r.Method(handler, method)
}

func (*Route) Method

func (r *Route) Method(handler Handler, methods ...string) *Route

Method registers the routes with the handler and methods.

It will panic with it if there is an error when adding the routes.

func (*Route) Name

func (r *Route) Name(name string) *Route

Name sets the route name.

func (*Route) New

func (r *Route) New() *Route

New clones a new Route based on the current route.

func (*Route) NoMiddlewares

func (r *Route) NoMiddlewares() *Route

NoMiddlewares clears all the middlewares and returns itself.

func (*Route) OPTIONS

func (r *Route) OPTIONS(handler Handler) *Route

OPTIONS is the short for r.Method(handler, "OPTIONS").

func (*Route) PATCH

func (r *Route) PATCH(handler Handler) *Route

PATCH is the short for r.Method(handler, "PATCH").

func (*Route) POST

func (r *Route) POST(handler Handler) *Route

POST is the short for r.Method(handler, "POST").

func (*Route) PUT

func (r *Route) PUT(handler Handler) *Route

PUT is the short for r.Method(handler, "PUT").

func (*Route) Redirect

func (r *Route) Redirect(code int, toURL string, method ...string) *Route

Redirect is used to redirect the path to toURL.

method is GET by default.

func (*Route) Remove

func (r *Route) Remove(method string) *Route

Remove removes the route.

If the method is "", it will remove all the routes associated with the path.

func (*Route) RemoveAny

func (r *Route) RemoveAny() *Route

RemoveAny is equal to r.Remove("").

func (*Route) RemoveCONNECT

func (r *Route) RemoveCONNECT() *Route

RemoveCONNECT is equal to r.Remove(http.MethodConnect).

func (*Route) RemoveDELETE

func (r *Route) RemoveDELETE() *Route

RemoveDELETE is equal to r.Remove(http.MethodDelete).

func (*Route) RemoveGET

func (r *Route) RemoveGET() *Route

RemoveGET is equal to r.Remove(http.MethodGet).

func (*Route) RemoveHEAD

func (r *Route) RemoveHEAD() *Route

RemoveHEAD is equal to r.Remove(http.MethodHead).

func (*Route) RemoveOPTIONS

func (r *Route) RemoveOPTIONS() *Route

RemoveOPTIONS is equal to r.Remove(http.MethodOptions).

func (*Route) RemovePATCH

func (r *Route) RemovePATCH() *Route

RemovePATCH is equal to r.Remove(http.MethodPatch).

func (*Route) RemovePOST

func (r *Route) RemovePOST() *Route

RemovePOST is equal to r.Remove(http.MethodPost).

func (*Route) RemovePUT

func (r *Route) RemovePUT() *Route

RemovePUT is equal to r.Remove(http.MethodPut).

func (*Route) RemoveTRACE

func (r *Route) RemoveTRACE() *Route

RemoveTRACE is equal to r.Remove(http.MethodTrace).

func (*Route) RouteInfo

func (r *Route) RouteInfo(handler Handler, methods ...string) []RouteInfo

RouteInfo converts the context routes to []RouteInfo.

func (*Route) Ship

func (r *Route) Ship() *Ship

Ship returns the ship that the current route is associated with.

func (*Route) Static

func (r *Route) Static(dirpath string) *Route

Static is the same as StaticFS, but listing the files for a directory.

func (*Route) StaticFS

func (r *Route) StaticFS(fs http.FileSystem) *Route

StaticFS registers a route to serve a static filesystem.

func (*Route) TRACE

func (r *Route) TRACE(handler Handler) *Route

TRACE is the short for r.Method(handler, "TRACE").

func (*Route) Use

func (r *Route) Use(middlewares ...Middleware) *Route

Use adds some middlwares for the route.

type RouteError

type RouteError struct {
	RouteInfo
	Err error
}

RouteError represents a route error when adding a route.

func (RouteError) Error

func (re RouteError) Error() string

type RouteGroup

type RouteGroup struct {
	// contains filtered or unexported fields
}

RouteGroup is a route group, that's, it manages a set of routes.

func (*RouteGroup) AddRoutes

func (g *RouteGroup) AddRoutes(ris ...RouteInfo) *RouteGroup

AddRoutes registers a set of the routes.

It will panic with it if there is an error when adding the routes.

func (*RouteGroup) Clone

func (g *RouteGroup) Clone() *RouteGroup

Clone clones itself and returns a new one.

func (*RouteGroup) CtxData

func (g *RouteGroup) CtxData(data interface{}) *RouteGroup

CtxData sets the context data on the route group.

func (*RouteGroup) DelRoutes

func (g *RouteGroup) DelRoutes(ris ...RouteInfo) *RouteGroup

DelRoutes deletes a set of the registered routes.

It will panic with it if there is an error when deleting the routes.

func (*RouteGroup) Group

func (g *RouteGroup) Group(prefix string, middlewares ...Middleware) *RouteGroup

Group returns a new route sub-group.

func (*RouteGroup) Host

func (g *RouteGroup) Host(host string) *RouteGroup

Host sets the host of the route group to host.

func (*RouteGroup) NoMiddlewares

func (g *RouteGroup) NoMiddlewares() *RouteGroup

NoMiddlewares clears all the middlewares and returns itself.

func (*RouteGroup) Route

func (g *RouteGroup) Route(path string) *Route

Route returns a new route, which is used to build and register the route.

You should call Route.Method() or its short method to register it.

func (*RouteGroup) Ship

func (g *RouteGroup) Ship() *Ship

Ship returns the ship that the current group belongs to.

func (*RouteGroup) Use

func (g *RouteGroup) Use(middlewares ...Middleware) *RouteGroup

Use adds some middlwares for the group and returns the origin group to write the chained router.

type RouteInfo

type RouteInfo struct {
	// The host is used to isolate the routes. And the different host
	// maybe has the same routes.
	//
	// If Host is empty, it represents the default host.
	Host string `json:"host,omitempty" xml:"host,omitempty"`

	// Path and Method represent the unique route in a certain host.
	//
	// Path maybe contain the parameters, which is determined by the underlying
	// router. And if Method is empty, it stands for all the methods.
	Path   string `json:"path,omitempty" xml:"path,omitempty"`
	Method string `json:"method,omitempty" xml:"method,omitempty"`

	// Name is the name of the path, which may be empty to represent no name.
	Name string `json:"name,omitempty" xml:"name,omitempty"`

	// Handler is the handler of the route to handle the request.
	Handler Handler `json:"-" xml:"-"`

	// CtxData is any additional context data, which is passed to the handler
	// and it can be accessed by Context.RouteInfo.CtxData in the handler.
	CtxData interface{} `json:"ctxdata,omitempty" xml:"ctxdata,omitempty"`
}

RouteInfo is used to represent the information of the registered route.

func (RouteInfo) String

func (ri RouteInfo) String() string

type Router

type Router = router.Router

Router is the alias of router.Router.

type Runner

type Runner struct {
	Name      string
	Logger    Logger
	Server    *http.Server
	Handler   http.Handler
	Signals   []os.Signal
	ConnState func(net.Conn, http.ConnState)
	// contains filtered or unexported fields
}

Runner is a HTTP Server runner.

func NewRunner

func NewRunner(name string, handler http.Handler) *Runner

NewRunner returns a new Runner.

func (r *Runner) Link(other *Runner) *Runner

Link registers the shutdown function between itself and other, then returns itself.

func (*Runner) RegisterOnShutdown

func (r *Runner) RegisterOnShutdown(functions ...func()) *Runner

RegisterOnShutdown registers some functions to run when the http server is shut down.

func (*Runner) Shutdown

func (r *Runner) Shutdown(ctx context.Context) (err error)

Shutdown stops the HTTP server.

func (*Runner) Start

func (r *Runner) Start(addr string, tlsFiles ...string) *Runner

Start starts a HTTP server with addr and ends when the server is closed.

If tlsFiles is not nil, it must be certFile and keyFile. For example,

runner := NewRunner()
runner.Start(":80", certFile, keyFile)

func (*Runner) Stop

func (r *Runner) Stop()

Stop is the same as r.Shutdown(context.Background()).

func (*Runner) Wait

func (r *Runner) Wait()

Wait waits until all the registered shutdown functions have finished.

type Session

type Session interface {
	// If the session id does not exist, it should return (nil, nil).
	GetSession(id string) (value interface{}, err error)
	SetSession(id string, value interface{}) error
	DelSession(id string) error
}

Session represents an interface about the session.

func NewMemorySession

func NewMemorySession() Session

NewMemorySession return a Session implementation based on the memory.

type Ship

type Ship struct {
	*Runner

	// Lock is used to access the host routers concurrently and thread-safely.
	//
	// Notice: It doesn't ensure that it's safe to access the routes
	// in a certain router concurrently and thread-safely.
	// But you maybe use the locked Router, such as router.LockRouter.
	//
	// Default: NewNoopRWLocker()
	Lock RWLocker

	// The initialization capacity of Context.Data.
	//
	// Default: 0
	CtxDataInitCap int

	// The maximum number of the url paramters of the route.
	//
	// Default: 4
	URLParamMaxNum int

	// The maximum number of the middlewares.
	//
	// Default: 256
	MiddlewareMaxNum int

	// The prefix of the paths of all the routes.
	//
	// Default: ""
	Prefix string

	// The default handler when not finding the route.
	//
	// Default: NotFoundHandler()
	NotFound Handler

	// Filter the route when registering and unregistering it.
	//
	// Default: nil
	RouteFilter func(RouteInfo) bool

	// Modify the route before registering and unregistering it.
	// Default: nil
	RouteModifier func(RouteInfo) RouteInfo

	// RouterExecutor is the router executor, which is called after matching
	// the host and before finding the route. By default, it only calls
	// Context.Execute().
	//
	// For the context, the executor can only use the field RouteInfo.Host.
	RouterExecutor Handler

	// HandleError is used to handle the error at last
	// if the handler or middleware returns an error.
	//
	// Default: respond the error to the client if not responding.
	HandleError func(c *Context, err error)

	// Others is used to set the context.
	Session    Session                                     // Default: NewMemorySession()
	Logger     Logger                                      // Default: NewLoggerFromWriter(os.Stderr, "")
	Binder     Binder                                      // Default: nil
	Renderer   Renderer                                    // Default: nil
	Responder  func(c *Context, args ...interface{}) error // Default: nil
	BindQuery  func(interface{}, url.Values) error         // Default: BindURLValues(v, vs, "query")
	SetDefault func(v interface{}) error                   // Default: SetStructFieldToDefault
	Validator  func(v interface{}) error                   // Default: nil
	// contains filtered or unexported fields
}

Ship is an app to be used to manage the router.

func Default

func Default() *Ship

Default returns a new ship with MuxBinder and MuxRenderer as the binder and renderer.

func New

func New() *Ship

New returns a new Ship.

func (*Ship) AcquireBuffer

func (s *Ship) AcquireBuffer() *bytes.Buffer

AcquireBuffer gets a Buffer from the pool.

func (*Ship) AcquireContext

func (s *Ship) AcquireContext(r *http.Request, w http.ResponseWriter) *Context

AcquireContext gets a Context from the pool.

func (*Ship) AddHost

func (s *Ship) AddHost(host string, r Router) (Router, error)

AddHost adds the router with the host and returns it if it does not exist; or, do nothing and return the existed router.

If router is nil, new one firstly.

func (*Ship) AddRoute

func (s *Ship) AddRoute(ri RouteInfo) (err error)

AddRoute registers the route.

func (*Ship) AddRoutes

func (s *Ship) AddRoutes(ris ...RouteInfo)

AddRoutes registers a set of the routes.

It will panic with it if there is an error when adding the routes.

func (*Ship) Clone

func (s *Ship) Clone() *Ship

Clone clones itself to a new one without routes, middlewares and the server. Meanwhile, it will reset the signals of the new Ship to nil.

func (*Ship) DelHost

func (s *Ship) DelHost(host string)

DelHost deletes the host router.

If the host is empty or the host router does not exist, do nothing.

func (*Ship) DelRoute

func (s *Ship) DelRoute(ri RouteInfo) (err error)

DelRoute deletes the registered route, which only uses "Host", "Path" and "Method", and others are ignored.

If Method is empty, deletes all the routes associated with the path.

If the route does not exist, do nothing and return nil.

func (*Ship) DelRoutes

func (s *Ship) DelRoutes(ris ...RouteInfo)

DelRoutes deletes a set of the registered routes.

It will panic with it if there is an error when deleting the routes.

func (*Ship) GetDefaultRouter

func (s *Ship) GetDefaultRouter() (host string, router Router)

GetDefaultRouter returns the default host domain and router.

For the default default router, the host is "".

func (*Ship) Group

func (s *Ship) Group(prefix string) *RouteGroup

Group returns a new route sub-group with the group prefix.

func (*Ship) Host

func (s *Ship) Host(host string) *RouteGroup

Host returns a new route sub-group with the virtual host.

func (*Ship) Hosts

func (s *Ship) Hosts() (hosts []string)

Hosts returns all the hosts except for the default.

func (*Ship) NewContext

func (s *Ship) NewContext() *Context

NewContext news a Context.

func (*Ship) Pre

func (s *Ship) Pre(middlewares ...Middleware) *Ship

Pre registers the Pre-middlewares, which are executed before finding the route. then returns the origin ship router to write the chained router.

func (*Ship) ReleaseBuffer

func (s *Ship) ReleaseBuffer(buf *bytes.Buffer)

ReleaseBuffer puts a Buffer into the pool.

func (*Ship) ReleaseContext

func (s *Ship) ReleaseContext(c *Context)

ReleaseContext puts a Context into the pool.

func (*Ship) ResetMiddlewares

func (s *Ship) ResetMiddlewares(mdws ...Middleware) *Ship

ResetMiddlewares resets the global middlewares to mdws.

func (*Ship) ResetPreMiddlewares

func (s *Ship) ResetPreMiddlewares(mdws ...Middleware) *Ship

ResetPreMiddlewares resets the global pre-middlewares to mdws.

func (*Ship) Route

func (s *Ship) Route(path string) *Route

Route returns a new route, which is used to build and register the route.

You should call Route.Method() or its short method to register it.

func (*Ship) Router

func (s *Ship) Router(host string) (r Router)

Router returns the Router implementation by the host name.

If host is empty, return the default router.

func (*Ship) Routers

func (s *Ship) Routers() (routers map[string]Router)

Routers returns the routers with their host.

func (*Ship) Routes

func (s *Ship) Routes() (routes []RouteInfo)

Routes returns the information of all the routes.

func (*Ship) ServeHTTP

func (s *Ship) ServeHTTP(resp http.ResponseWriter, req *http.Request)

ServeHTTP implements the interface http.Handler.

func (*Ship) SetBufferSize

func (s *Ship) SetBufferSize(size int) *Ship

SetBufferSize resets the size of the buffer.

func (*Ship) SetDefaultRouter

func (s *Ship) SetDefaultRouter(host string, router Router)

SetDefaultRouter resets the default router with the host domain. If the router is nil, it lookups the router by the host, and uses the default host router instead if failing to lookup it.

When matching the route, if no host router matches the request host, the default router will be used to find the route to handle the request.

func (*Ship) SetLogger

func (s *Ship) SetLogger(logger Logger) *Ship

SetLogger sets the logger of Ship and Runner to logger.

func (*Ship) SetNewRegexpHostRouter

func (s *Ship) SetNewRegexpHostRouter(f func() RegexpHostRouter) *Ship

SetNewRegexpHostRouter is used to customize RegexpHostRouter.

func (*Ship) SetNewRouter

func (s *Ship) SetNewRouter(f func() Router) *Ship

SetNewRouter resets the NewRouter to create the new router.

It must be called before adding any route.

func (*Ship) Use

func (s *Ship) Use(middlewares ...Middleware) *Ship

Use registers the global middlewares and returns the origin ship router to write the chained router.

Directories

Path Synopsis
Package middleware is the collection of the middlewares.
Package middleware is the collection of the middlewares.
render
Package router supplies a router interface ane some implementations.
Package router supplies a router interface ane some implementations.
echo
Package echo supplies a customized Router implementation by referring to github.com/labstack/echo.
Package echo supplies a customized Router implementation by referring to github.com/labstack/echo.

Jump to

Keyboard shortcuts

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