hime

package module
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2026 License: MIT Imports: 40 Imported by: 6

README

Hime

Test Go Report Card GoDoc

Hime is a Go Web Framework.

See Wiki for guide more information.

Why Framework

I ❤️ 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 is many Go frameworks 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.

That why hime won't ship with any handler include router 🙈

License

MIT

Documentation

Overview

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/moonrhythm/hime"
)

func main() {
	app := hime.New()
	app.Handler(hime.Handler(func(ctx *hime.Context) error {
		return ctx.String("Hello, hime")
	}))

	// drive the app with an httptest recorder instead of ListenAndServe
	w := httptest.NewRecorder()
	r := httptest.NewRequest(http.MethodGet, "/", nil)
	app.ServeHTTP(w, r)

	fmt.Print(w.Body.String())
}
Output:
Hello, hime

Index

Examples

Constants

This section is empty.

Variables

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

Errors

View Source
var ErrInvalidCookie = errors.New("hime: invalid signed cookie")

ErrInvalidCookie is returned by a CookieSigner when a signed cookie value is malformed or fails verification.

Functions

func Compatible added in v0.10.0

func Compatible() *tls.Config

Compatible is the tls config for compatible mode

func Global added in v0.13.0

func Global(ctx context.Context, key any) any

Global returns global value from context

func Modern added in v0.10.0

func Modern() *tls.Config

Modern is the tls config for modern mode

func Restricted added in v0.10.0

func Restricted() *tls.Config

Restricted is the tls config for restricted mode

func Route added in v0.13.0

func Route(ctx context.Context, name string, params ...any) string

Route returns route value from context

func SafeRedirectPath added in v0.0.17

func SafeRedirectPath(p string) string

SafeRedirectPath filters domain out from path

Example
package main

import (
	"fmt"

	"github.com/moonrhythm/hime"
)

func main() {
	// SafeRedirectPath strips the host, defeating open-redirect attempts.
	fmt.Println(hime.SafeRedirectPath("https://evil.example.com/account"))
}
Output:
/account

func StartHTTPSRedirectServer added in v0.10.0

func StartHTTPSRedirectServer(addr string) error

StartHTTPSRedirectServer starts http to https redirect server

Types

type App

type App struct {
	ETag bool

	// CookieSigner signs and verifies cookies for AddSignedCookie and
	// SignedCookieValue. It is nil by default; set it to enable signed cookies.
	CookieSigner CookieSigner
	// 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)

Address sets server address

func (*App) Clone added in v0.10.0

func (app *App) Clone() *App

Clone clones app

func (*App) Config added in v0.4.0

func (app *App) Config(config AppConfig)

Config merges config into app's config

Example:

globals:

data1: test

routes:

index: /
about: /about

templates:

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

func (*App) Global added in v0.0.11

func (app *App) Global(key any) any

Global gets value from global storage

func (*App) Globals added in v0.0.11

func (app *App) Globals(globals Globals)

Globals registers global constants

Example
package main

import (
	"fmt"

	"github.com/moonrhythm/hime"
)

func main() {
	app := hime.New()
	app.Globals(hime.Globals{"AppName": "hime"})

	fmt.Println(app.Global("AppName"))
}
Output:
hime

func (*App) Handler

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

Handler sets the handler

func (*App) ListenAndServe

func (app *App) ListenAndServe() error

ListenAndServe starts web server

func (*App) ParseConfig added in v0.4.0

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

ParseConfig parses config data

func (*App) ParseConfigFile added in v0.4.0

func (app *App) ParseConfigFile(filename string)

ParseConfigFile parses config from file

func (*App) Route

func (app *App) Route(name string, params ...any) string

Route gets route path from given name

Example
package main

import (
	"fmt"

	"github.com/moonrhythm/hime"
)

func main() {
	app := hime.New()
	app.Routes(hime.Routes{"user": "/users"})

	fmt.Println(app.Route("user"))
	fmt.Println(app.Route("user", 42))
	fmt.Println(app.Route("user", 42, &hime.Param{Name: "tab", Value: "posts"}))
}
Output:
/users
/users/42
/users/42?tab=posts

func (*App) Routes added in v0.0.4

func (app *App) Routes(routes Routes)

Routes registers route name and path

func (*App) SelfSign added in v0.10.0

func (app *App) SelfSign(s SelfSign)

SelfSign generates self sign cert

func (*App) Serve added in v0.10.0

func (app *App) Serve(l net.Listener) error

Serve serves listener

func (*App) ServeHTTP added in v0.2.0

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

func (*App) ServeHandler added in v1.2.0

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

func (*App) Server added in v0.0.21

func (app *App) Server() *parapet.Server

Server returns server inside app

func (*App) SetServer added in v1.2.0

func (app *App) SetServer(srv *parapet.Server)

func (*App) Shutdown added in v0.10.0

func (app *App) Shutdown() error

Shutdown shutdowns server

func (*App) TLS added in v0.10.0

func (app *App) TLS(certFile, keyFile string)

TLS sets cert and key file

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

TemplateFunc registers an app's level template func

func (*App) TemplateFuncs

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

TemplateFuncs registers app's level template funcs

type AppConfig added in v0.4.2

type AppConfig struct {
	Globals   Globals          `yaml:"globals" json:"globals"`
	Routes    Routes           `yaml:"routes" json:"routes"`
	Templates []TemplateConfig `yaml:"templates" json:"templates"`
}

AppConfig is hime app's config

type Context

type Context struct {
	*http.Request
	// contains filtered or unexported fields
}

Context is hime context

func NewAppContext added in v0.10.0

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

NewAppContext creates new hime's context with given app

func NewContext added in v0.0.15

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

NewContext creates new hime's context

func (*Context) AddCookie added in v1.3.0

func (ctx *Context) AddCookie(name string, value string, opts *CookieOptions)

func (*Context) AddFlash added in v1.5.0

func (ctx *Context) AddFlash(category, value string)

AddFlash queues a flash message under category, to be read exactly once on a later request via Flashes. Messages are stored in a cookie, so they survive the redirect of the post/redirect/get pattern. Calls accumulate.

Flash messages are not encrypted or signed; do not put secrets in them.

func (*Context) AddHeader added in v0.10.0

func (ctx *Context) AddHeader(key, value string)

AddHeader adds a header to response

func (*Context) AddHeaderIfNotExists added in v0.10.0

func (ctx *Context) AddHeaderIfNotExists(key, value string)

AddHeaderIfNotExists adds a header to response if not exists

func (*Context) AddSignedCookie added in v1.5.0

func (ctx *Context) AddSignedCookie(name, value string, opts *CookieOptions) error

AddSignedCookie signs value with the app's CookieSigner and writes it as a cookie. It is the signed counterpart of AddCookie; opts is applied the same way. It panics if the app has no CookieSigner configured.

func (*Context) BindJSON added in v1.1.2

func (ctx *Context) BindJSON(v any) error

BindJSON binds request body using json decoder

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

// newExampleContext builds a Context wired to an httptest recorder so the
// examples below can show output without starting a real server.
func newExampleContext(method, target string, body string) (*hime.Context, *httptest.ResponseRecorder) {
	var r *http.Request
	if body == "" {
		r = httptest.NewRequest(method, target, nil)
	} else {
		r = httptest.NewRequest(method, target, strings.NewReader(body))
	}
	w := httptest.NewRecorder()
	return hime.NewAppContext(hime.New(), w, r), w
}

func main() {
	ctx, _ := newExampleContext(http.MethodPost, "/", `{"name":"hime"}`)

	var body struct {
		Name string `json:"name"`
	}
	ctx.BindJSON(&body)

	fmt.Println(body.Name)
}
Output:
hime

func (*Context) BindXML added in v1.4.0

func (ctx *Context) BindXML(v any) error

BindXML binds request body using xml decoder

func (*Context) Bytes

func (ctx *Context) Bytes(b []byte) error

Bytes writes bytes into response writer

func (*Context) Component added in v1.2.0

func (ctx *Context) Component(name string, data any) error

Component renders component

func (*Context) CookieValue added in v1.3.0

func (ctx *Context) CookieValue(name string) string

func (*Context) CopyFrom

func (ctx *Context) CopyFrom(src io.Reader) error

CopyFrom copies src reader into response writer

func (*Context) Deadline added in v0.10.0

func (ctx *Context) Deadline() (deadline time.Time, ok bool)

Deadline implements context.Context

func (*Context) DelCookie added in v1.3.0

func (ctx *Context) DelCookie(name string, opts *CookieOptions)

func (*Context) DelHeader added in v0.10.0

func (ctx *Context) DelHeader(key string)

DelHeader deletes a header from response

func (*Context) Done added in v0.10.0

func (ctx *Context) Done() <-chan struct{}

Done implements context.Context

func (*Context) ETag added in v1.0.1

func (ctx *Context) ETag(enable bool) *Context

ETag overrides etag setting

func (*Context) Err added in v0.10.0

func (ctx *Context) Err() error

Err implements context.Context

func (*Context) Error

func (ctx *Context) Error(error string) error

Error calls http.Error

func (*Context) File added in v0.0.7

func (ctx *Context) File(name string) error

File serves file using http.ServeFile

func (*Context) Flashes added in v1.5.0

func (ctx *Context) Flashes() map[string][]string

Flashes returns the flash messages queued on a previous request, keyed by category, and clears them so the next request will not see them again. It returns nil when there are none.

Call Flashes before writing the response: the clear is sent as a Set-Cookie header, which has no effect once the response headers have been written.

func (*Context) FormFileHeader added in v0.10.0

func (ctx *Context) FormFileHeader(key string) (*multipart.FileHeader, error)

FormFileHeader returns file header for given key without open file

func (*Context) FormFileHeaderNotEmpty added in v0.10.0

func (ctx *Context) FormFileHeaderNotEmpty(key string) (*multipart.FileHeader, error)

FormFileHeaderNotEmpty returns file header if not empty, or http.ErrMissingFile if file is empty

This function will be deprecated after drop go1.10 support, since go1.11 bring back old behavior

func (*Context) FormFileNotEmpty added in v0.0.18

func (ctx *Context) FormFileNotEmpty(key string) (multipart.File, *multipart.FileHeader, error)

FormFileNotEmpty returns file from r.FormFile only when file size is not empty, or return http.ErrMissingFile if file is empty

func (*Context) FormState added in v1.5.0

func (ctx *Context) FormState() *FormState

FormState returns a FormState seeded with the request's form values (query and body). Add validation errors with AddError, then pass it to a view to re-render the form.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

func main() {
	r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("email=bad"))
	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	ctx := hime.NewAppContext(hime.New(), httptest.NewRecorder(), r)

	form := ctx.FormState()
	if !strings.Contains(form.Value("email"), "@") {
		form.AddError("email", "invalid email")
	}
	// on error, pass form to the view to re-render with the value + message
	fmt.Println(form.Value("email"), form.HasErrors(), form.Error("email"))
}
Output:
bad true invalid email

func (*Context) FormValueFloat32 added in v0.0.17

func (ctx *Context) FormValueFloat32(key string) float32

FormValueFloat32 converts form value to float32

func (*Context) FormValueFloat64 added in v0.0.17

func (ctx *Context) FormValueFloat64(key string) float64

FormValueFloat64 converts form value to float64

func (*Context) FormValueInt added in v0.0.17

func (ctx *Context) FormValueInt(key string) int

FormValueInt converts form value to int

func (*Context) FormValueInt64 added in v0.0.17

func (ctx *Context) FormValueInt64(key string) int64

FormValueInt64 converts form value to int64

func (*Context) FormValueTrimSpace added in v0.0.17

func (ctx *Context) FormValueTrimSpace(key string) string

FormValueTrimSpace trims space from form value

func (*Context) FormValueTrimSpaceComma added in v0.0.17

func (ctx *Context) FormValueTrimSpaceComma(key string) string

FormValueTrimSpaceComma trims space and remove comma from form value

func (*Context) FormValues added in v1.4.0

func (ctx *Context) FormValues(key string) []string

FormValues returns all form values associated with the given key, parsing the form first if necessary (query and body values)

func (*Context) Global added in v0.0.11

func (ctx *Context) Global(key any) any

Global returns global value

func (*Context) HTML added in v0.10.0

func (ctx *Context) HTML(data string) error

HTML writes html to response writer

func (*Context) HTMXRedirect added in v1.5.0

func (ctx *Context) HTMXRedirect(url string, params ...any) error

HTMXRedirect instructs htmx to perform a client-side redirect using the HX-Redirect response header. Prefer this over Redirect when responding to an htmx request, since htmx does not follow normal 3xx redirects. params are applied to url the same way as Redirect.

func (*Context) HTMXRefresh added in v1.5.0

func (ctx *Context) HTMXRefresh() error

HTMXRefresh instructs htmx to do a full page reload via the HX-Refresh header.

func (*Context) HTMXReswap added in v1.5.0

func (ctx *Context) HTMXReswap(strategy string) *Context

HTMXReswap overrides how htmx swaps the response (e.g. "outerHTML", "beforeend") via the HX-Reswap header. It returns ctx for chaining.

func (*Context) HTMXRetarget added in v1.5.0

func (ctx *Context) HTMXRetarget(selector string) *Context

HTMXRetarget overrides the element htmx swaps the response into via the HX-Retarget header (a CSS selector). It returns ctx for chaining.

func (*Context) HTMXTrigger added in v1.5.0

func (ctx *Context) HTMXTrigger(event string, detail ...any) *Context

HTMXTrigger triggers client-side events after the swap via the HX-Trigger header. With no detail it sends the bare event name; with one detail value it sends {event: detail} as JSON. It returns ctx for chaining, and panics if detail can not be marshalled or if more than one detail is given.

func (*Context) Handle

func (ctx *Context) Handle(h http.Handler) error

Handle calls h.ServeHTTP

func (*Context) IsHTMX added in v1.5.0

func (ctx *Context) IsHTMX() bool

IsHTMX reports whether the request was made by htmx, via the HX-Request header. Use it to render a partial/component for htmx and a full page otherwise.

func (*Context) IsRoute added in v1.5.0

func (ctx *Context) IsRoute(name string) bool

IsRoute reports whether the named route is the most specific registered route matching the current request path: the path equals the route's path or is under it, and no other registered route matches more deeply. It is handy for highlighting the active navigation link — on /admin/users/42 the "/admin/users" route is active but its "/admin" parent is not. Pass ctx into the view data to use it from a template as {{.IsRoute "home"}}.

Matching is path-segment aware ("/admin" matches "/admin/x" but not "/administrators"), so "/" is active only on exactly "/"; any query string or trailing slash in the route path is ignored. It panics if name is not a registered route, like Route.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/moonrhythm/hime"
)

func main() {
	app := hime.New()
	app.Routes(hime.Routes{"home": "/", "about": "/about"})

	r := httptest.NewRequest(http.MethodGet, "/about", nil)
	ctx := hime.NewAppContext(app, httptest.NewRecorder(), r)

	// in a template, pass ctx as the data: {{if .IsRoute "about"}}active{{end}}
	fmt.Println(ctx.IsRoute("about"), ctx.IsRoute("home"))
}
Output:
true false

func (*Context) JSON

func (ctx *Context) JSON(data any) error

JSON encodes given data into json then writes to response writer

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

// newExampleContext builds a Context wired to an httptest recorder so the
// examples below can show output without starting a real server.
func newExampleContext(method, target string, body string) (*hime.Context, *httptest.ResponseRecorder) {
	var r *http.Request
	if body == "" {
		r = httptest.NewRequest(method, target, nil)
	} else {
		r = httptest.NewRequest(method, target, strings.NewReader(body))
	}
	w := httptest.NewRecorder()
	return hime.NewAppContext(hime.New(), w, r), w
}

func main() {
	ctx, w := newExampleContext(http.MethodGet, "/", "")

	ctx.JSON(struct {
		Message string `json:"message"`
	}{Message: "hello"})

	fmt.Print(w.Body.String())
}
Output:
{"message":"hello"}

func (*Context) NoContent added in v0.0.8

func (ctx *Context) NoContent() error

NoContent writes http.StatusNoContent into response writer

func (*Context) NotFound added in v0.0.7

func (ctx *Context) NotFound() error

NotFound calls http.NotFound

func (*Context) Param added in v0.0.16

func (ctx *Context) Param(name string, value any) *Param

Param is the short-hand for hime.Param

func (*Context) PostFormValueFloat32 added in v0.0.17

func (ctx *Context) PostFormValueFloat32(key string) float32

PostFormValueFloat32 converts post form value to flost32

func (*Context) PostFormValueFloat64 added in v0.0.17

func (ctx *Context) PostFormValueFloat64(key string) float64

PostFormValueFloat64 converts post form value to flost64

func (*Context) PostFormValueInt added in v0.0.17

func (ctx *Context) PostFormValueInt(key string) int

PostFormValueInt converts post form value to int

func (*Context) PostFormValueInt64 added in v0.0.17

func (ctx *Context) PostFormValueInt64(key string) int64

PostFormValueInt64 converts post form value to int64

func (*Context) PostFormValueTrimSpace added in v0.0.17

func (ctx *Context) PostFormValueTrimSpace(key string) string

PostFormValueTrimSpace trims space from post form value

func (*Context) PostFormValueTrimSpaceComma added in v0.0.17

func (ctx *Context) PostFormValueTrimSpaceComma(key string) string

PostFormValueTrimSpaceComma trims space and remove comma from post form value

func (*Context) PostFormValues added in v1.4.0

func (ctx *Context) PostFormValues(key string) []string

PostFormValues returns all post form values associated with the given key, parsing the form first if necessary (body values only)

func (*Context) QueryValueFloat32 added in v1.4.0

func (ctx *Context) QueryValueFloat32(key string) float32

QueryValueFloat32 converts query value to float32

func (*Context) QueryValueFloat64 added in v1.4.0

func (ctx *Context) QueryValueFloat64(key string) float64

QueryValueFloat64 converts query value to float64

func (*Context) QueryValueInt added in v1.4.0

func (ctx *Context) QueryValueInt(key string) int

QueryValueInt converts query value to int

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

// newExampleContext builds a Context wired to an httptest recorder so the
// examples below can show output without starting a real server.
func newExampleContext(method, target string, body string) (*hime.Context, *httptest.ResponseRecorder) {
	var r *http.Request
	if body == "" {
		r = httptest.NewRequest(method, target, nil)
	} else {
		r = httptest.NewRequest(method, target, strings.NewReader(body))
	}
	w := httptest.NewRecorder()
	return hime.NewAppContext(hime.New(), w, r), w
}

func main() {
	ctx, _ := newExampleContext(http.MethodGet, "/search?page=2", "")

	fmt.Println(ctx.QueryValueInt("page"))
}
Output:
2

func (*Context) QueryValueInt64 added in v1.4.0

func (ctx *Context) QueryValueInt64(key string) int64

QueryValueInt64 converts query value to int64

func (*Context) QueryValueTrimSpace added in v1.4.0

func (ctx *Context) QueryValueTrimSpace(key string) string

QueryValueTrimSpace trims space from query value

func (*Context) QueryValueTrimSpaceComma added in v1.4.0

func (ctx *Context) QueryValueTrimSpaceComma(key string) string

QueryValueTrimSpaceComma trims space and remove comma from query value

func (*Context) QueryValues added in v1.4.0

func (ctx *Context) QueryValues(key string) []string

QueryValues returns all query string values associated with the given key

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

// newExampleContext builds a Context wired to an httptest recorder so the
// examples below can show output without starting a real server.
func newExampleContext(method, target string, body string) (*hime.Context, *httptest.ResponseRecorder) {
	var r *http.Request
	if body == "" {
		r = httptest.NewRequest(method, target, nil)
	} else {
		r = httptest.NewRequest(method, target, strings.NewReader(body))
	}
	w := httptest.NewRecorder()
	return hime.NewAppContext(hime.New(), w, r), w
}

func main() {
	ctx, _ := newExampleContext(http.MethodGet, "/?tag=go&tag=web", "")

	fmt.Println(ctx.QueryValues("tag"))
}
Output:
[go web]

func (*Context) Redirect

func (ctx *Context) Redirect(url string, params ...any) error

Redirect redirects to given url

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

// newExampleContext builds a Context wired to an httptest recorder so the
// examples below can show output without starting a real server.
func newExampleContext(method, target string, body string) (*hime.Context, *httptest.ResponseRecorder) {
	var r *http.Request
	if body == "" {
		r = httptest.NewRequest(method, target, nil)
	} else {
		r = httptest.NewRequest(method, target, strings.NewReader(body))
	}
	w := httptest.NewRecorder()
	return hime.NewAppContext(hime.New(), w, r), w
}

func main() {
	ctx, w := newExampleContext(http.MethodGet, "/", "")

	ctx.Redirect("/login")

	fmt.Println(w.Code)
	fmt.Println(w.Header().Get("Location"))
}
Output:
302
/login

func (*Context) RedirectBack added in v0.0.25

func (ctx *Context) RedirectBack(fallback string) error

RedirectBack redirects to referer or fallback if referer not exists

func (*Context) RedirectBackToGet added in v0.0.27

func (ctx *Context) RedirectBackToGet() error

RedirectBackToGet redirects to referer or fallback with same url

func (*Context) RedirectTo

func (ctx *Context) RedirectTo(name string, params ...any) error

RedirectTo redirects to route name

func (*Context) RedirectToGet added in v0.0.14

func (ctx *Context) RedirectToGet() error

RedirectToGet redirects to same url back to Get

func (*Context) Render added in v1.2.0

func (ctx *Context) Render(tmpl string, data any) error

Render renders html template

func (*Context) RenderComponentToString added in v1.5.0

func (ctx *Context) RenderComponentToString(name string, data any) (string, error)

RenderComponentToString renders the named component to a string instead of writing it to the response, for composing responses (such as htmx out-of-band swaps) from several components. It panics if the component is not found, matching Component.

func (*Context) ResponseWriter

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

ResponseWriter returns response writer

func (*Context) Route added in v0.0.11

func (ctx *Context) Route(name string, params ...any) string

Route gets route path from name

func (*Context) SafeRedirect

func (ctx *Context) SafeRedirect(url string, params ...any) error

SafeRedirect extracts only path from url then redirect

func (*Context) SafeRedirectBack added in v0.0.25

func (ctx *Context) SafeRedirectBack(fallback string) error

SafeRedirectBack safe redirects to referer

func (*Context) SetHeader added in v0.10.0

func (ctx *Context) SetHeader(key, value string)

SetHeader sets a header to response

func (*Context) SignedCookieValue added in v1.5.0

func (ctx *Context) SignedCookieValue(name string) string

SignedCookieValue verifies the named cookie with the app's CookieSigner and returns its value, or an empty string if the cookie is absent OR fails verification (tampered, wrong key, or wrong name). The two cases are intentionally indistinguishable — the safe default is to not trust the value either way. If you need to tell them apart (for example to log tampering), read the raw cookie with CookieValue and call the signer's Verify yourself. It panics if the app has no CookieSigner configured.

func (*Context) Status

func (ctx *Context) Status(code int) *Context

Status sets response status code

func (*Context) StatusCode added in v1.4.0

func (ctx *Context) StatusCode() int

StatusCode returns the status code set via Status, defaulting to http.StatusOK when none was set

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

// newExampleContext builds a Context wired to an httptest recorder so the
// examples below can show output without starting a real server.
func newExampleContext(method, target string, body string) (*hime.Context, *httptest.ResponseRecorder) {
	var r *http.Request
	if body == "" {
		r = httptest.NewRequest(method, target, nil)
	} else {
		r = httptest.NewRequest(method, target, strings.NewReader(body))
	}
	w := httptest.NewRecorder()
	return hime.NewAppContext(hime.New(), w, r), w
}

func main() {
	ctx, _ := newExampleContext(http.MethodGet, "/", "")

	fmt.Println(ctx.StatusCode()) // defaults to 200 when unset
	ctx.Status(http.StatusTeapot)
	fmt.Println(ctx.StatusCode())
}
Output:
200
418

func (*Context) StatusText added in v0.0.8

func (ctx *Context) StatusText() error

StatusText writes status text from seted status code into response writer

func (*Context) String

func (ctx *Context) String(format string, a ...any) error

String writes string into response writer

func (*Context) Value added in v0.10.0

func (ctx *Context) Value(key any) any

Value implements context.Context

func (*Context) View

func (ctx *Context) View(name string, data any) error

View renders view

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/moonrhythm/hime"
)

func main() {
	app := hime.New()
	app.Template().Parse("index", "Hello, {{.}}")

	w := httptest.NewRecorder()
	r := httptest.NewRequest(http.MethodGet, "/", nil)
	ctx := hime.NewAppContext(app, w, r)
	ctx.View("index", "hime")

	fmt.Print(w.Body.String())
}
Output:
Hello, hime

func (*Context) WithContext added in v0.0.24

func (ctx *Context) WithContext(nctx context.Context) *Context

WithContext returns new context with new request with given context

func (*Context) WithRequest added in v0.0.26

func (ctx *Context) WithRequest(r *http.Request) *Context

WithRequest returns new context with given request

func (*Context) WithResponseWriter added in v0.0.26

func (ctx *Context) WithResponseWriter(w http.ResponseWriter) *Context

WithResponseWriter returns new context with given response writer

func (*Context) WithValue added in v0.0.26

func (ctx *Context) WithValue(key any, val any) *Context

WithValue calls WithContext with value context

func (*Context) XML added in v1.4.0

func (ctx *Context) XML(data any) error

XML encodes given data into xml then writes to response writer

Example
package main

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/moonrhythm/hime"
)

// newExampleContext builds a Context wired to an httptest recorder so the
// examples below can show output without starting a real server.
func newExampleContext(method, target string, body string) (*hime.Context, *httptest.ResponseRecorder) {
	var r *http.Request
	if body == "" {
		r = httptest.NewRequest(method, target, nil)
	} else {
		r = httptest.NewRequest(method, target, strings.NewReader(body))
	}
	w := httptest.NewRecorder()
	return hime.NewAppContext(hime.New(), w, r), w
}

func main() {
	ctx, w := newExampleContext(http.MethodGet, "/", "")

	ctx.XML(struct {
		XMLName xml.Name `xml:"greeting"`
		Message string   `xml:"message"`
	}{Message: "hello"})

	fmt.Print(w.Body.String())
}
Output:
<greeting><message>hello</message></greeting>

type CookieOptions added in v1.3.0

type CookieOptions struct {
	Path     string
	Domain   string
	MaxAge   int
	Secure   bool
	HttpOnly bool
	SameSite http.SameSite
}

type CookieSigner added in v1.5.0

type CookieSigner interface {
	// Sign returns the signed, encoded value to store in the cookie named name.
	Sign(name, value string) (string, error)

	// Verify checks signedValue for the cookie named name and returns the
	// original value, or an error if it is malformed or fails verification.
	Verify(name, signedValue string) (string, error)
}

CookieSigner signs and verifies cookie values so tampering can be detected.

Implementations must bind the cookie name into the signature (so a value signed for one cookie can not be reused under a different name) and must use a constant-time comparison when verifying.

type ErrComponentDuplicate added in v1.2.0

type ErrComponentDuplicate struct {
	Name string
}

ErrComponentDuplicate is the error for component duplicate

func (*ErrComponentDuplicate) Error added in v1.2.0

func (err *ErrComponentDuplicate) Error() string

type ErrComponentNotFound added in v1.2.0

type ErrComponentNotFound struct {
	Name string
}

ErrComponentNotFound is the error for component not found

func (*ErrComponentNotFound) Error added in v1.2.0

func (err *ErrComponentNotFound) Error() string

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 FormState added in v1.5.0

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

FormState holds submitted form values together with per-field validation errors, so a form can be re-rendered with the user's input after a failed submission (instead of making them retype everything).

func (*FormState) AddError added in v1.5.0

func (fs *FormState) AddError(name, message string)

AddError records a validation error message for the field name. Calls accumulate.

func (*FormState) Error added in v1.5.0

func (fs *FormState) Error(name string) string

Error returns the first error message for name, or "".

func (*FormState) Errors added in v1.5.0

func (fs *FormState) Errors(name string) []string

Errors returns all error messages for name.

func (*FormState) HasError added in v1.5.0

func (fs *FormState) HasError(name string) bool

HasError reports whether name has any error.

func (*FormState) HasErrors added in v1.5.0

func (fs *FormState) HasErrors() bool

HasErrors reports whether any field has an error.

func (*FormState) SetValue added in v1.5.0

func (fs *FormState) SetValue(name, value string)

SetValue sets name's value, replacing any submitted value. Useful for pre-filling a form (such as an edit form) before rendering.

func (*FormState) Value added in v1.5.0

func (fs *FormState) Value(name string) string

Value returns the first submitted value for name, or "".

func (*FormState) Values added in v1.5.0

func (fs *FormState) Values(name string) []string

Values returns all submitted values for name (for multi-value fields such as checkboxes or multi-selects).

type Globals added in v0.0.11

type Globals map[any]any

Globals is the global const map

type HMACCookieSigner added in v1.5.0

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

HMACCookieSigner is a CookieSigner backed by HMAC-SHA256. The cookie name is bound into the signature and verification is constant time.

It signs but does not encrypt: the value stays readable by the client. Serve signed cookies as Secure + HttpOnly over HTTPS to protect them in transit, and rely on cookie MaxAge for expiry (the signature itself never expires).

Because the signature never expires on its own, rotating the key invalidates every existing cookie. To rotate without logging users out, keep verifying against the old key (try each signer in turn) until the old cookies' MaxAge has elapsed.

Example
package main

import (
	"fmt"

	"github.com/moonrhythm/hime"
)

func main() {
	signer := hime.NewHMACCookieSigner([]byte("a-32-byte-or-longer-secret-key!!"))

	signed, _ := signer.Sign("session", "user42")
	value, err := signer.Verify("session", signed)
	fmt.Println(value, err == nil)

	// the cookie name is bound into the signature, so reusing the value
	// under a different name fails verification
	_, err = signer.Verify("other", signed)
	fmt.Println(err)
}
Output:
user42 true
hime: invalid signed cookie

func NewHMACCookieSigner added in v1.5.0

func NewHMACCookieSigner(key []byte) *HMACCookieSigner

NewHMACCookieSigner returns an HMACCookieSigner using key (32+ random bytes recommended). The key is copied, so the caller may reuse or zero its slice. It panics if key is empty, since an empty key provides no protection.

func (*HMACCookieSigner) Sign added in v1.5.0

func (s *HMACCookieSigner) Sign(name, value string) (string, error)

Sign implements CookieSigner. The wire format is base64url(value) "." base64url(mac).

func (*HMACCookieSigner) Verify added in v1.5.0

func (s *HMACCookieSigner) Verify(name, signedValue string) (string, error)

Verify implements CookieSigner.

type HTTPSRedirect added in v0.10.0

type HTTPSRedirect struct {
	Addr string `json:"addr"`
}

HTTPSRedirect type

func (*HTTPSRedirect) ServeHTTP added in v0.10.0

func (s *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (HTTPSRedirect) Server added in v0.10.0

func (s HTTPSRedirect) Server() *http.Server

Server generates https redirect server

type Handler

type Handler func(*Context) error

Handler is the hime handler

func (Handler) ServeHTTP added in v0.10.0

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Param added in v0.0.16

type Param struct {
	Name  string
	Value any
}

Param is the query param when redirect

type Routes added in v0.0.4

type Routes map[string]string

Routes is the map for route name => path

type SelfSign added in v0.10.0

type SelfSign struct {
	Key struct {
		Algo string `yaml:"algo" json:"algo"`
		Size int    `yaml:"size" json:"size"`
	} `yaml:"key" json:"key"`
	CN    string   `yaml:"cn" json:"cn"`
	Hosts []string `yaml:"host" json:"host"`
}

SelfSign type

type TLS added in v0.10.0

type TLS struct {
	SelfSign   *SelfSign `yaml:"selfSign" json:"selfSign"`
	CertFile   string    `yaml:"certFile" json:"certFile"`
	KeyFile    string    `yaml:"keyFile" json:"keyFile"`
	Profile    string    `yaml:"profile" json:"profile"`
	MinVersion string    `yaml:"minVersion" json:"minVersion"`
	MaxVersion string    `yaml:"maxVersion" json:"maxVersion"`
	Curves     []string  `yaml:"curves" json:"curves"`
}

TLS type

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(ts ...*template.Template)

Component loads html/template into component list

func (*Template) Config added in v0.4.2

func (tp *Template) Config(cfg TemplateConfig)

Config loads template config

func (*Template) Delims added in v0.3.0

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

Delims sets left and right delims

func (*Template) Dir added in v0.3.0

func (tp *Template) Dir(path string)

Dir sets root directory when load template

default is ""

func (*Template) FS added in v1.1.0

func (tp *Template) FS(fs fs.FS)

FS uses fs when load template

func (*Template) Func added in v0.4.2

func (tp *Template) Func(name string, f any)

Func adds a template func while load template

func (*Template) Funcs added in v0.3.0

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

Funcs adds template funcs while load template

func (*Template) Minify added in v0.3.0

func (tp *Template) Minify()

Minify enables minify when render html, css, js, must call before parse

func (*Template) MinifyWith added in v1.0.1

func (tp *Template) MinifyWith(cfg TemplateMinifyConfig)

MinifyWith enables minify with custom options, must call before parse

func (*Template) Parse added in v0.3.0

func (tp *Template) Parse(name string, text string)

Parse parses template from text

func (*Template) ParseComponent added in v1.2.0

func (tp *Template) ParseComponent(name string, text string)

ParseComponent parses component from text

func (*Template) ParseComponentFile added in v1.2.0

func (tp *Template) ParseComponentFile(name string, filename string)

ParseComponentFile loads component from file

func (*Template) ParseConfig added in v0.4.2

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

ParseConfig parses template config data

func (*Template) ParseConfigFile added in v0.4.2

func (tp *Template) ParseConfigFile(filename string)

ParseConfigFile parses template config from file

func (*Template) ParseFiles added in v0.10.0

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

ParseFiles loads template from file

func (*Template) ParseGlob added in v0.10.0

func (tp *Template) ParseGlob(name string, pattern string)

ParseGlob loads template from pattern

func (*Template) Preload added in v0.10.0

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

Preload loads given templates before parse

func (*Template) Root added in v0.3.0

func (tp *Template) Root(name string)

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"`
	Preload []string            `yaml:"preload" json:"preload"`
	List    map[string][]string `yaml:"list" json:"list"`
	Delims  []string            `yaml:"delims" json:"delims"`
}

TemplateConfig is template config

type TemplateMinifyConfig added in v1.0.1

type TemplateMinifyConfig struct {
	HTML minify.Minifier
	CSS  minify.Minifier
	JS   minify.Minifier
}

Jump to

Keyboard shortcuts

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