hime

package module
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: May 18, 2018 License: MIT Imports: 31 Imported by: 6

README

Hime

Build Status Coverage Status Go Report Card GoDoc

Hime is a Go Web Framework.

Why Framework

I like net/http but... there are many duplicated code when working on multiple projects, plus no standard. Framework creates a standard for developers.

Why Another Framework

There're many Go framework out there. But I want a framework that works with any net/http compatible libraries seamlessly.

For example, you can choose any router, any middlewares, or handlers that work with standard library.

Other framework don't allow this. They have built-in router, framework-specific middlewares.

Core focus

  • Add standard to code
  • Compatible with any net/http compatible router
  • Compatible with http.Handler without code change
  • Compatible with net/http middlewares without code change
  • Use standard html/template for view
  • Built-in core functions for build web server
  • Reduce developer bugs

What is this framework DO NOT focus

  • Speed
  • One framework do everything

Example

func main() {
    app := hime.New()

    app.Template().
        Parse("index", "index.tmpl", "_layout.tmpl").
        Minify()

    app.
        Routes(hime.Routes{
            "index": "/",
        }).
        BeforeRender(addHeaderRender).
        Handler(router(app)).
        GracefulShutdown().
        Address(":8080").
        ListenAndServe()
}

func router(app *hime.App) http.Handler {
    mux := http.NewServeMux()
    mux.Handle(app.Route("index"), hime.H(indexHandler))
    return middleware.Chain(
        logRequestMethod,
        logRequestURI,
    )(mux)
}

func logRequestURI(h http.Handler) http.Handler {
    return hime.H(func(ctx hime.Context) hime.Result {
        log.Println(ctx.Request().RequestURI)
        return h
    })
}

func logRequestMethod(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Method)
        h.ServeHTTP(w, r)
    })
}

func addHeaderRender(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
        h.ServeHTTP(w, r)
    })
}

func indexHandler(ctx hime.Context) hime.Result {
    if ctx.Request().URL.Path != "/" {
        return ctx.RedirectTo("index")
    }
    return ctx.View("index", map[string]interface{}{
        "Name": "Acoshift",
    })
}
More Examples

Compatibility with net/http

Handler

Hime doesn't have built-in router, you can use any http.Handler.

hime.Wrap (or hime.H for short-hand) wraps hime.Handler into http.Handler, so you can use hime's handler anywhere in your router that support http.Handler.

Middleware

Hime use native func(http.Handler) http.Handler for middleware. You can use any middleware that compatible with this type.

func logRequestMethod(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Method)
        h.ServeHTTP(w, r)
    })
}

You can also use hime's handler with middleware

func logRequestURI(h http.Handler) http.Handler {
    return hime.H(func(ctx hime.Context) hime.Result {
        log.Println(ctx.Request().RequestURI)
        return h // hime.Result is http.Handler alias
    })
}

Inject data to context

func injectData(h http.Handler) http.Handler {
    return hime.H(func(ctx hime.Context) hime.Result {
        ctx.WithValue(ctxKeyData{}, "injected data!")
        return h
    })
}

Retrieve data from context like context.Context

ctx.Value(ctxKeyData{}).(string)
Use hime.App as Handler

If you don't want to use hime's built-in graceful shutdown, you can use hime.App as normal handler.

func main() {
    app := hime.New()

    app.Template().
        Parse("index", "index.tmpl", "_layout.tmpl").
        Minify()

    app.
        Routes(hime.Routes{
            "index": "/",
        }).
        BeforeRender(addHeaderRender).
        Handler(router(app))

    http.ListenAndServe(":8080", app)
}

Why return Result

Bacause many developers forgot to return to end handler

func signInHandler(w http.ResponseWriter, r *http.Request) {
    username := r.FormValue("username")
    if username == "" {
        http.Error(w, "username required", http.StatusBadRequest)
        return // many return like this, sometime developers forgot about it
    }
    ...
}

with Result

func signInHandler(ctx hime.Context) hime.Result {
    username := r.FormValue("username")
    if username == "" {
        return ctx.Status(http.StatusBadRequest).Error("username required")
    }
    ...
}

Why not return error, like this...

func signInHandler(ctx hime.Context) error {
    username := r.FormValue("username")
    if username == "" {
        return ctx.Status(http.StatusBadRequest).Error("username required")
    }
    ...
}

Then, what if you return an error ?

return err

Hime won't handle error for you :D

You can see that hime won't response anything, you must handle on your own.

Why some functions use panic

Hime try to reduce developer errors, some error can detect while development. Hime will panic for that type of errors.

Useful handlers and middlewares

FAQ

  • Will hime support automated let's encrypt ?

    No, you can use hime as normal handler and use other lib to do this.

  • Do you use hime in production ?

    Yes, why not ? :D

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAppNotFound = errors.New("hime: app not found")
)

Errors

Functions

func H added in v0.0.12

func H(h Handler) http.Handler

H is the short hand for Wrap

func SafeRedirectPath added in v0.0.17

func SafeRedirectPath(p string) string

SafeRedirectPath filters domain out from path

func Wrap

func Wrap(h Handler) http.Handler

Wrap wraps hime handler with http.Handler

Types

type App

type App struct {
	// Addr is server address
	Addr string

	// TLSConfig overrides http.Server TLSConfig
	TLSConfig *tls.Config

	// ReadTimeout overrides http.Server ReadTimeout
	ReadTimeout time.Duration

	// ReadHeaderTimeout overrides http.Server ReadHeaderTimeout
	ReadHeaderTimeout time.Duration

	// WriteTimeout overrides http.Server WriteTimeout
	WriteTimeout time.Duration

	// IdleTimeout overrides http.Server IdleTimeout
	IdleTimeout time.Duration

	// MaxHeaderBytes overrides http.Server MaxHeaderBytes
	MaxHeaderBytes int

	// TLSNextProto overrides http.Server TLSNextProto
	TLSNextProto map[string]func(*http.Server, *tls.Conn, http.Handler)

	// ConnState overrides http.Server ConnState
	ConnState func(net.Conn, http.ConnState)

	// ErrorLog overrides http.Server ErrorLog
	ErrorLog *log.Logger
	// contains filtered or unexported fields
}

App is the hime app

func New

func New() *App

New creates new app

func (*App) Address added in v0.5.0

func (app *App) Address(addr string) *App

Address sets server address

func (*App) BeforeRender

func (app *App) BeforeRender(m middleware.Middleware) *App

BeforeRender runs given middleware for before render, ex. View, JSON, String, Bytes, CopyForm, etc

func (*App) Config added in v0.4.0

func (app *App) Config(config AppConfig) *App

Config merges config into app's config

Example:

globals:

data1: test

routes:

index: /
about: /about

templates:

  • dir: view root: layout delims: ["{{", "}}"] minify: true components:
  • comp/comp1.tmpl
  • comp/comp2.tmpl list: main.tmpl:
  • main.tmpl
  • _layout.tmpl about.tmpl: [about.tmpl, _layout.tmpl]

server:

readTimeout: 10s
readHeaderTimeout: 5s
writeTimeout: 5s
idleTimeout: 30s
gracefulShutdown:
  timeout: 1m
  wait: 5s

func (*App) Global added in v0.0.11

func (app *App) Global(key interface{}) interface{}

Global gets value from global storage

func (*App) Globals added in v0.0.11

func (app *App) Globals(globals Globals) *App

Globals registers global constants

func (*App) GracefulShutdown

func (app *App) GracefulShutdown() *GracefulShutdownApp

GracefulShutdown returns graceful shutdown server

func (*App) Handler

func (app *App) Handler(h http.Handler) *App

Handler sets the handler

func (*App) ListenAndServe

func (app *App) ListenAndServe() error

ListenAndServe starts web server

func (*App) ListenAndServeTLS added in v0.2.0

func (app *App) ListenAndServeTLS(certFile, keyFile string) error

ListenAndServeTLS starts web server in tls mode

func (*App) ParseConfig added in v0.4.0

func (app *App) ParseConfig(data []byte) *App

ParseConfig parses config data

func (*App) ParseConfigFile added in v0.4.0

func (app *App) ParseConfigFile(filename string) *App

ParseConfigFile parses config from file

func (*App) Route

func (app *App) Route(name string, params ...interface{}) string

Route gets route path from given name

func (*App) Routes added in v0.0.4

func (app *App) Routes(routes Routes) *App

Routes registers route name and path

func (*App) ServeHTTP added in v0.2.0

func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*App) Template

func (app *App) Template() *Template

Template creates new template loader

func (*App) TemplateFunc added in v0.4.2

func (app *App) TemplateFunc(name string, f interface{}) *App

TemplateFunc registers an app's level template func

func (*App) TemplateFuncs

func (app *App) TemplateFuncs(funcs ...template.FuncMap) *App

TemplateFuncs registers app's level template funcs

type AppConfig added in v0.4.2

type AppConfig struct {
	Globals   map[interface{}]interface{} `yaml:"globals" json:"globals"`
	Routes    map[string]string           `yaml:"routes" json:"routes"`
	Templates []TemplateConfig            `yaml:"templates" json:"templates"`
	Server    struct {
		Addr              string `yaml:"addr" json:"addr"`
		ReadTimeout       string `yaml:"readTimeout" json:"readTimeout"`
		ReadHeaderTimeout string `yaml:"readHeaderTimeout" json:"readHeaderTimeout"`
		WriteTimeout      string `yaml:"writeTimeout" json:"writeTimeout"`
		IdleTimeout       string `yaml:"idleTimeout" json:"idleTimeout"`
		GracefulShutdown  *struct {
			Timeout string `yaml:"timeout" json:"timeout"`
			Wait    string `yaml:"wait" json:"wait"`
		} `yaml:"gracefulShutdown" json:"gracefulShutdown"`
	} `yaml:"server" json:"server"`
}

AppConfig is hime app's config

type Apps added in v0.5.0

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

Apps is the collection of App to start together

func Merge added in v0.5.0

func Merge(apps ...*App) *Apps

Merge merges multiple *App into *Apps

func (*Apps) GracefulShutdown added in v0.5.0

func (apps *Apps) GracefulShutdown() *GracefulShutdownApps

GracefulShutdown changes apps to graceful shutdown mode

func (*Apps) ListenAndServe added in v0.5.0

func (apps *Apps) ListenAndServe() error

ListenAndServe starts web servers

type Context

type Context interface {
	context.Context

	WithContext(ctx context.Context)
	WithRequest(r *http.Request)
	WithResponseWriter(w http.ResponseWriter)
	WithValue(key interface{}, val interface{})

	// Route gets route path from given name
	Route(name string, params ...interface{}) string

	// Global gets value from global storage
	Global(key interface{}) interface{}

	// Request returns http.Request from context
	Request() *http.Request

	// ResponseWrite returns http.ResponseWriter from context
	ResponseWriter() http.ResponseWriter

	// Status sets response status
	Status(code int) Context

	// Request functions
	ParseForm() error
	ParseMultipartForm(maxMemory int64) error
	Form() url.Values
	PostForm() url.Values

	// FromValue functions
	FormValue(key string) string
	FormValueTrimSpace(key string) string
	FormValueTrimSpaceComma(key string) string
	FormValueInt(key string) int
	FormValueInt64(key string) int64
	FormValueFloat32(key string) float32
	FormValueFloat64(key string) float64

	PostFormValue(key string) string
	PostFormValueTrimSpace(key string) string
	PostFormValueTrimSpaceComma(key string) string
	PostFormValueInt(key string) int
	PostFormValueInt64(key string) int64
	PostFormValueFloat32(key string) float32
	PostFormValueFloat64(key string) float64

	FormFile(key string) (multipart.File, *multipart.FileHeader, error)

	// FormFileNotEmpty calls r.FormFile but return http.ErrMissingFile if file empty
	FormFileNotEmpty(key string) (multipart.File, *multipart.FileHeader, error)

	MultipartForm() *multipart.Form
	MultipartReader() (*multipart.Reader, error)
	Method() string

	// Query returns ctx.Request().URL.Query()
	Query() url.Values

	Param(name string, value interface{}) *Param

	// Nothing does nothing
	Nothing() Result

	// Redirect redirects to given url
	Redirect(url string, params ...interface{}) Result

	// SafeRedirect extracts only path from url then redirect
	SafeRedirect(url string, params ...interface{}) Result

	// RedirectTo redirects to named route
	RedirectTo(name string, params ...interface{}) Result

	// RedirectToGet redirects to GET method with See Other status code on the current path
	RedirectToGet() Result

	// RedirectBack redirects back to previous URL
	RedirectBack(fallback string) Result

	// RedirectBackToGet redirects back to GET method with See Other status code to previous URL
	// or fallback to same URL like RedirectToGet
	RedirectBackToGet() Result

	// SafeRedirectBack redirects back to previous URL using SafeRedirect
	SafeRedirectBack(fallback string) Result

	// Error wraps http.Error
	Error(error string) Result

	// NotFound wraps http.NotFound
	NotFound() Result

	// NoContent renders empty body with http.StatusNoContent
	NoContent() Result

	// View renders template
	View(name string, data interface{}) Result

	// JSON renders json
	JSON(data interface{}) Result

	// String renders string with format
	String(format string, a ...interface{}) Result

	// StatusText renders String when http.StatusText
	StatusText() Result

	// CopyFrom copies source into response writer
	CopyFrom(src io.Reader) Result

	// Bytes renders bytes
	Bytes(b []byte) Result

	// File renders file
	File(name string) Result
}

Context is the hime context

func NewContext added in v0.0.15

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

NewContext creates new hime's context

type ErrRouteNotFound added in v0.0.15

type ErrRouteNotFound struct {
	Route string
}

ErrRouteNotFound is the error for route not found

func (*ErrRouteNotFound) Error added in v0.0.15

func (err *ErrRouteNotFound) Error() string

type ErrTemplateDuplicate added in v0.0.15

type ErrTemplateDuplicate struct {
	Name string
}

ErrTemplateDuplicate is the error for template duplicate

func (*ErrTemplateDuplicate) Error added in v0.0.15

func (err *ErrTemplateDuplicate) Error() string

type ErrTemplateNotFound added in v0.0.15

type ErrTemplateNotFound struct {
	Name string
}

ErrTemplateNotFound is the error for template not found

func (*ErrTemplateNotFound) Error added in v0.0.15

func (err *ErrTemplateNotFound) Error() string

type Globals added in v0.0.11

type Globals map[interface{}]interface{}

Globals is the global const map

type GracefulShutdownApp added in v0.0.19

type GracefulShutdownApp struct {
	App *App
	// contains filtered or unexported fields
}

GracefulShutdownApp is the app in graceful shutdown mode

func (*GracefulShutdownApp) Address added in v0.5.0

func (gs *GracefulShutdownApp) Address(addr string) *GracefulShutdownApp

Address sets server address

func (*GracefulShutdownApp) ListenAndServe added in v0.0.19

func (gs *GracefulShutdownApp) ListenAndServe() error

ListenAndServe starts web server in graceful shutdown mode

func (*GracefulShutdownApp) ListenAndServeTLS added in v0.5.0

func (gs *GracefulShutdownApp) ListenAndServeTLS(certFile, keyFile string) error

ListenAndServeTLS starts web server in graceful shutdown and tls mode

func (*GracefulShutdownApp) Notify added in v0.0.20

func (gs *GracefulShutdownApp) Notify(fn func()) *GracefulShutdownApp

Notify calls fn when receive terminate signal from os

func (*GracefulShutdownApp) OnShutdown added in v0.5.0

func (gs *GracefulShutdownApp) OnShutdown(fn func()) *GracefulShutdownApp

OnShutdown calls server.RegisterOnShutdown(fn)

func (*GracefulShutdownApp) Timeout added in v0.0.19

Timeout sets shutdown timeout for graceful shutdown, set to 0 to disable timeout

default is 0

func (*GracefulShutdownApp) Wait added in v0.0.19

Wait sets wait time before shutdown

type GracefulShutdownApps added in v0.5.0

type GracefulShutdownApps struct {
	Apps *Apps
	// contains filtered or unexported fields
}

GracefulShutdownApps is the apps in graceful shutdown mode

func (*GracefulShutdownApps) ListenAndServe added in v0.5.0

func (gs *GracefulShutdownApps) ListenAndServe() error

ListenAndServe starts web servers in graceful shutdown mode

func (*GracefulShutdownApps) Notify added in v0.5.0

func (gs *GracefulShutdownApps) Notify(fn func()) *GracefulShutdownApps

Notify calls fn when receive terminate signal from os

func (*GracefulShutdownApps) Timeout added in v0.5.0

Timeout sets shutdown timeout for graceful shutdown, set to 0 to disable timeout

default is 0

func (*GracefulShutdownApps) Wait added in v0.5.0

Wait sets wait time before shutdown

type Handler

type Handler func(Context) Result

Handler is the hime handler

type Param added in v0.0.16

type Param struct {
	Name  string
	Value interface{}
}

Param is the query param when redirect

type Result

type Result http.Handler

Result is the handler result

type Routes added in v0.0.4

type Routes map[string]string

Routes is the map for route name => path

type Template added in v0.3.0

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

Template is template loader

func (*Template) Component added in v0.3.0

func (tp *Template) Component(filename ...string) *Template

Component adds given templates to every templates

func (*Template) Config added in v0.4.2

func (tp *Template) Config(cfg TemplateConfig) *Template

Config loads template config

func (*Template) Delims added in v0.3.0

func (tp *Template) Delims(left, right string) *Template

Delims sets left and right delims

func (*Template) Dir added in v0.3.0

func (tp *Template) Dir(path string) *Template

Dir sets root directory when load template

default is ""

func (*Template) Func added in v0.4.2

func (tp *Template) Func(name string, f interface{}) *Template

Func adds a template func while load template

func (*Template) Funcs added in v0.3.0

func (tp *Template) Funcs(funcs ...template.FuncMap) *Template

Funcs adds template funcs while load template

func (*Template) Minify added in v0.3.0

func (tp *Template) Minify() *Template

Minify enables minify when render html, css, js

func (*Template) Parse added in v0.3.0

func (tp *Template) Parse(name string, filenames ...string) *Template

Parse loads template into memory

func (*Template) ParseConfig added in v0.4.2

func (tp *Template) ParseConfig(data []byte) *Template

ParseConfig parses template config data

func (*Template) ParseConfigFile added in v0.4.2

func (tp *Template) ParseConfigFile(filename string) *Template

ParseConfigFile parses template config from file

func (*Template) Root added in v0.3.0

func (tp *Template) Root(name string) *Template

Root calls t.Lookup(name) after load template, empty string won't trigger t.Lookup

default is ""

type TemplateConfig added in v0.4.2

type TemplateConfig struct {
	Dir        string              `yaml:"dir" json:"dir"`
	Root       string              `yaml:"root" json:"root"`
	Minify     bool                `yaml:"minify" json:"minify"`
	Components []string            `yaml:"components" json:"components"`
	List       map[string][]string `yaml:"list" json:"list"`
	Delims     []string            `yaml:"delims" json:"delims"`
}

TemplateConfig is template config

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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