https://github.com/alesr/templator
A type-safe HTML template rendering engine for Go
https://github.com/alesr/templator
code-generation go-template template
Last synced: 8 months ago
JSON representation
A type-safe HTML template rendering engine for Go
- Host: GitHub
- URL: https://github.com/alesr/templator
- Owner: alesr
- License: mit
- Created: 2025-01-14T18:29:33.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-06-01T13:09:22.000Z (10 months ago)
- Last Synced: 2025-06-08T16:40:02.602Z (9 months ago)
- Topics: code-generation, go-template, template
- Language: Go
- Homepage:
- Size: 69.3 KB
- Stars: 7
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-go - templator - A type-safe HTML template rendering engine for Go. (Template Engines / HTTP Clients)
- awesome-go-cn - templator - safe HTML template rendering engine for Go. [![godoc][D]](https://godoc.org/github.com/alesr/templator) (模板引擎 / HTTP客户端)
- awesome-go-with-stars - templator - safe HTML template rendering engine for Go. | 2026-02-20 | (Template Engines / HTTP Clients)
- fucking-awesome-go - templator - A type-safe HTML template rendering engine for Go. (Template Engines / HTTP Clients)
- awesome-go - templator - A type-safe HTML template rendering engine for Go. (Template Engines / HTTP Clients)
README
# Templator
[](https://codecov.io/gh/alesr/templator)
[](https://goreportcard.com/report/github.com/alesr/templator)
[](https://pkg.go.dev/github.com/alesr/templator)
A type-safe HTML template rendering engine for Go.
> **Note**: This is an experimental project in active development. While it's stable enough for use, expect possible API changes. Feedback and contributions are welcome!
## Table of Contents
- [Problem Statement](#problem-statement)
- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Usage Examples](#usage-examples)
- [Template Generation](#template-generation)
- [Configuration](#configuration)
- [Contributing](#contributing)
- [License](#license)
## Problem Statement
Go's built-in template package lacks type safety, which can lead to runtime errors when template data doesn't match what the template expects. For example:
```go
// Traditional approach with Go templates
tmpl := template.Must(template.ParseFiles("home.html"))
// This compiles but will fail at runtime if the template expects different fields
tmpl.Execute(w, struct {
WrongField string
MissingRequired int
}{})
// No compile-time checks for:
// - Missing required fields
// - Wrong field types
// - Typos in field names
```
Templator solves this by providing compile-time type checking for your templates:
```go
// Define your template data type
type HomeData struct {
Title string
Content string
}
// Initialize registry with type parameter
reg, _ := templator.NewRegistry[HomeData](fs)
// Get type-safe handler and execute template
home, _ := reg.GetHome()
home.Execute(ctx, w, HomeData{
Title: "Welcome",
Content: "Hello",
})
// Won't compile - wrong data structure
home.Execute(ctx, w, struct{
WrongField string
}{})
```
## Features
- Type-safe template execution with generics
- Concurrent-safe template management
- Custom template functions support
- Clean and simple API
- HTML escaping by default
## Installation
```bash
go install github.com/alesr/templator
```
## Quick Start
```go
package main
import (
"context"
"log"
"os"
"github.com/alesr/templator"
)
// Define your template data
type HomeData struct {
Title string
Content string
}
func main() {
// Use the filesystem of your choice
fs := os.DirFS(".")
// Initialize registry with your data type
reg, err := templator.NewRegistry[HomeData](fs)
if err != nil {
log.Fatal(err)
}
// Get type-safe handler for home template
home, err := reg.GetHome()
if err != nil {
log.Fatal(err)
}
// Execute template with proper data
err = home.Execute(context.Background(), os.Stdout, HomeData{
Title: "Welcome",
Content: "Hello, World!",
})
if err != nil {
log.Fatal(err)
}
}
```
## Usage Examples
### Type-Safe Templates
```go
// Define different data types for different templates
type HomeData struct {
Title string
Content string
}
type AboutData struct {
Company string
Year int
}
// Create registries for different template types
homeReg := templator.NewRegistry[HomeData](fs)
aboutReg := templator.NewRegistry[AboutData](fs)
// Get handlers
home, _ := homeReg.GetHome()
about, _ := aboutReg.GetAbout()
// Type safety enforced at compile time
home.Execute(ctx, w, HomeData{...}) // ✅ Compiles
home.Execute(ctx, w, AboutData{...}) // ❌ Compile error
```
### Using Template Functions
```go
// Define your custom functions
funcMap := template.FuncMap{
"upper": strings.ToUpper,
"lower": strings.ToLower,
}
// Create registry with functions
reg, err := templator.NewRegistry[PageData](fs,
templator.WithTemplateFuncs[PageData](funcMap))
// Use functions in your templates:
//
{{.Title | upper}}
```
### File System Support
```go
// Embedded FS
//go:embed templates/*
var embedFS embed.FS
reg := templator.NewRegistry[HomeData](embedFS)
// OS File System
reg := templator.NewRegistry[HomeData](os.DirFS("./templates"))
// In-Memory (testing)
fsys := fstest.MapFS{
"templates/home.html": &fstest.MapFile{
Data: []byte(`
{{.Title}}
`),
},
}
reg := templator.NewRegistry[HomeData](fsys)
```
### Field Validation
```go
type ArticleData struct {
Title string // Only these two fields
Content string // are allowed in templates
}
// Enable validation during registry creation
reg := templator.NewRegistry[ArticleData](
fs,
templator.WithFieldValidation(ArticleData{}),
)
// Example templates:
// valid.html:
//
{{.Title}}
// ✅ OK - Title exists in ArticleData
// {{.Content}}
// ✅ OK - Content exists in ArticleData
// invalid.html:
//
{{.Author}}
// ❌ Error - Author field doesn't exist
// {{.PublishedAt}}
// ❌ Error - PublishedAt field doesn't exist
// Using the templates:
handler, err := reg.Get("valid") // ✅ Success - all fields exist
if err != nil {
log.Fatal(err)
}
handler, err := reg.Get("invalid") // ❌ Error: "template 'invalid' validation error: Author - field 'Author' not found in type ArticleData"
// The validation error provides:
// - Template name
// - Invalid field path
// - Detailed error message
if validErr, ok := err.(*templator.ValidationError); ok {
fmt.Printf("Template: %s\n", validErr.TemplateName)
fmt.Printf("Invalid field: %s\n", validErr.FieldPath)
fmt.Printf("Error: %v\n", validErr.Err)
}
```
This validation happens when loading the template, not during execution, helping catch field mismatches early in development.
## Template Generation
Templates are automatically discovered and type-safe methods are generated:
```zsh
templates/
├── home.html -> reg.GetHome()
├── about.html -> reg.GetAbout()
└── components/
└── header.html -> reg.GetComponentsHeader()
# Generate methods
go generate ./...
```
The generation process creates a `templator_methods.go` file containing type-safe method handlers for each template. For example:
```go
// Code generated by go generate; DO NOT EDIT.
func (r *Registry[T]) GetHome() (*Handler[T], error) {
return r.Get("home")
}
func (r *Registry[T]) GetAbout() (*Handler[T], error) {
return r.Get("about")
}
```
This file is automatically generated and should not be manually edited.
## Configuration
```go
reg, err := templator.NewRegistry[HomeData](
fs,
// Custom template directory
templator.WithTemplatesPath[HomeData]("views"),
// Enable field validation
templator.WithFieldValidation(HomeData{}),
)
```
### Development Requirements
- Go 1.21 or higher
## License
MIT