hime

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: May 15, 2018 License: MIT Imports: 29 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().
        ListenAndServe(":8080")
}

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 {
	// 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) 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) 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() *GracefulShutdown

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(addr string) error

ListenAndServe starts web server

func (*App) ListenAndServeTLS added in v0.2.0

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

ListenAndServeTLS starts web server in tls mode

func (*App) Load added in v0.3.0

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

Load loads 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

graceful:

timeout: 1m
wait: 5s

func (*App) LoadFromFile added in v0.3.0

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

LoadFromFile loads 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) TemplateFuncs

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

TemplateFuncs registers app's level template funcs

type Config added in v0.3.0

type Config struct {
	Globals   map[interface{}]interface{} `yaml:"globals" json:"globals"`
	Routes    map[string]string           `yaml:"routes" json:"routes"`
	Templates []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"`
	} `yaml:"templates" json:"templates"`
	Server struct {
		ReadTimeout       string `yaml:"readTimeout" json:"readTimeout"`
		ReadHeaderTimeout string `yaml:"readHeaderTimeout" json:"readHeaderTimeout"`
		WriteTimeout      string `yaml:"writeTimeout" json:"writeTimeout"`
		IdleTimeout       string `yaml:"idleTimeout" json:"idleTimeout"`
	} `yaml:"server" json:"server"`
	Graceful struct {
		Timeout string `yaml:"timeout" json:"timeout"`
		Wait    string `yaml:"wait" json:"wait"`
	} `yaml:"graceful" json:"graceful"`
}

Config is app's config

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 GracefulShutdown added in v0.2.0

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

GracefulShutdown is the app in graceful shutdown mode

func (*GracefulShutdown) Before added in v0.2.0

func (gs *GracefulShutdown) Before(fn func()) *GracefulShutdown

Before runs fn before start waiting to SIGTERM

func (*GracefulShutdown) ListenAndServe added in v0.2.0

func (gs *GracefulShutdown) ListenAndServe(addr string) error

ListenAndServe starts web server in graceful shutdown mode

func (*GracefulShutdown) ListenAndServeTLS added in v0.2.0

func (gs *GracefulShutdown) ListenAndServeTLS(addr, certFile, keyFile string) error

ListenAndServeTLS starts web server in graceful shutdown and tls mode

func (*GracefulShutdown) Notify added in v0.2.0

func (gs *GracefulShutdown) Notify(fn func()) *GracefulShutdown

Notify calls fn when receive terminate signal from os

func (*GracefulShutdown) Timeout added in v0.2.0

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

default is 0

func (*GracefulShutdown) Wait added in v0.2.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) 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) 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) 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 ""

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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