htmlview

package
v0.1.45 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 7 Imported by: 0

README

htmlview

htmlview is planned as a small helper package for rendering Go values as passable HTML in chiutil backoffice pages.

The goal is to make object and slice endpoints nicer than raw JSON/YAML while keeping handler code very small. RouteFolder stays responsible for routing, navigation, and previews; htmlview is responsible only for turning values into HTML.

Intended API

The core type is Handler, which implements http.Handler. Renderer() returns a new *Handler; the constructor is named for the fluent call site because Go does not allow type Renderer and func Renderer in the same package.

type Handler struct {
	// internal render configuration
}

func Renderer() *Handler
func Render(value any) *Handler
func Loader[T any](loader func(*http.Request) (T, error)) *Handler

func (h *Handler) WithObject(value any) *Handler
func (h *Handler) WithLoader(loader func(*http.Request) (any, error)) *Handler
func (h *Handler) WithTitle(title string) *Handler
func (h *Handler) WithColumns(columns ...string) *Handler
func (h *Handler) WithEmptyText(text string) *Handler
func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request)

Render is for already available values:

folder.GetHandler("/sessions", htmlview.Render(sessions).
	WithTitle("Sessions").
	WithColumns("ID", "Package", "StartedAt"))

Loader is for request-time values:

folder.GetHandler("/sessions", htmlview.Loader(func(r *http.Request) ([]sessionView, error) {
	return store.ListSessions(r.Context())
}).
	WithTitle("Sessions").
	WithColumns("ID", "Package", "StartedAt"))

WithLoader remains available for builder-style configuration, but most typed call sites should prefer Loader because it avoids forcing the loader function to return any.

folder.GetHandler("/sessions", htmlview.Renderer().
	WithTitle("Sessions").
	WithLoader(func(r *http.Request) (any, error) {
		return store.ListSessions(r.Context())
	}).
	WithColumns("ID", "Package", "StartedAt"))

RouteFolder Integration

Because Renderer implements http.Handler, RouteFolder should grow handler registration helpers alongside the existing http.HandlerFunc helpers:

func (f *RouteFolder) GetHandler(path string, handler http.Handler)
func (f *RouteFolder) GetHandlerDesc(path, description string, handler http.Handler)

That keeps route registration direct:

folder.GetHandler("/my", htmlview.Render(account).
	WithTitle("My Account").
	WithColumns("ID", "Email", "Plan"))

ObjectsFolder Integration

ObjectsFolder routes should stay as they are. They are already descriptive:

func (m *sessionMapper) Routes() []chiutil.ObjectRoute[*sessionView] {
	return []chiutil.ObjectRoute[*sessionView]{
		{
			Method:      "GET",
			Path:        "/details",
			Handler:     (*sessionView).serveDetails,
			Description: "Session identity, package, timing",
		},
		{
			Method:      "GET",
			Path:        "/subsets",
			Handler:     (*sessionView).serveSubsets,
			Description: "API subsets snapshot taken at initialize",
		},
	}
}

The renderer should make those handler bodies simple:

func (s *sessionView) serveDetails(w http.ResponseWriter, r *http.Request) {
	htmlview.Render(s).
		WithTitle("Session details").
		WithColumns("ID", "Package", "StartedAt", "FinishedAt").
		ServeHTTP(w, r)
}

func (s *sessionView) serveSubsets(w http.ResponseWriter, r *http.Request) {
	htmlview.Render(s.Subsets).
		WithTitle("API subsets").
		WithColumns("Name", "Operations", "CapturedAt").
		ServeHTTP(w, r)
}

This keeps ObjectsFolder focused on lookup and route dispatch. htmlview only handles presentation.

Rendering Rules

Initial behavior should stay intentionally small:

  • Structs render as a compact key/value table.
  • Slices and arrays of structs render as a table.
  • Maps render as a key/value table.
  • Scalars render as escaped text.
  • Pointers are dereferenced; nil pointers render as empty text.
  • time.Time renders as a readable timestamp.
  • fmt.Stringer values render through String().
  • Output is escaped by default.
  • htmlview:"Label" changes a field label.
  • htmlview:"-" hides a field from default and column-selected rendering.

WithColumns selects and orders fields for struct and slice rendering:

htmlview.Render(accounts).
	WithTitle("Accounts").
	WithColumns("ID", "Name", "Status")

The result should be a regular HTML table with only those fields, in that order.

Non-Goals

  • Do not make a component framework.
  • Do not replace RouteFolder or ObjectsFolder.
  • Do not use JSON/YAML as an intermediate rendering format.
  • Do not render raw HTML by default.
  • Do not add broad styling/configuration APIs until real handlers need them.

Documentation

Overview

Package htmlview renders Go values as simple HTML pages for chiutil routes.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

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

Handler renders either a fixed object or a value loaded from a request.

func Loader

func Loader[T any](loader func(*http.Request) (T, error)) *Handler

Loader returns a renderer configured with a typed request-time loader.

func Render

func Render(value any) *Handler

Render returns a renderer configured with a fixed object or slice.

func Renderer

func Renderer() *Handler

Renderer returns an empty HTML renderer.

func (*Handler) ServeHTTP

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

ServeHTTP renders the configured value as HTML.

func (*Handler) WithColumns

func (h *Handler) WithColumns(columns ...string) *Handler

WithColumns selects and orders struct fields for object and slice rendering.

func (*Handler) WithEmptyText

func (h *Handler) WithEmptyText(text string) *Handler

WithEmptyText sets the text used for nil and empty values.

func (*Handler) WithLoader

func (h *Handler) WithLoader(loader func(*http.Request) (any, error)) *Handler

WithLoader configures the renderer to load the rendered value per request.

func (*Handler) WithObject

func (h *Handler) WithObject(value any) *Handler

WithObject configures the renderer to render value.

func (*Handler) WithTitle

func (h *Handler) WithTitle(title string) *Handler

WithTitle sets the page title and heading.

Jump to

Keyboard shortcuts

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