Gothic is a batteries-included Go framework for building full-stack apps. It prioritizes simplicity and productivity.
Goals
- Fullstack Go Go is the only language you write
- Simplicity Optimized for readability and understanding whats going on
- Opinionated Fewer decisions to make, focus on building
A taste
The syntax is under active development and subject to change. See the guestbook, TodoMVC, accounts, Gothicbook, router, nested components, and the virtualized list for working code.
// app.gth
package main
import (
"context"
"github.com/metruzanca/gothic"
)
type Message struct{ Text string }
type EntryProps struct{ Item Message }
type Model struct {
Draft string
Messages []Message
}
type DraftChanged struct{ Text string }
type PostClicked struct{}
type Posted struct{ Message Message }
type PostFailed struct{ Message string }
// Procedures declares the RPC calls available to the client.
// The embedded gothic.RPCService marks it for code generation.
type Procedures interface {
gothic.RPCService
Post(ctx context.Context, text string) (Message, error)
}
func (m Model) Init() gothic.Cmd { return nil }
func (m Model) Update(msg gothic.Msg) (gothic.Model, gothic.Cmd) {
switch msg := msg.(type) {
case DraftChanged:
m.Draft = msg.Text
case PostClicked:
text := m.Draft
if text == "" {
return m, nil
}
m.Draft = ""
return m, func() gothic.Msg {
posted, err := Post(text)
if err != nil {
return PostFailed{Message: err.Error()}
}
return Posted{Message: posted}
}
case Posted:
m.Messages = append(m.Messages, msg.Message)
case PostFailed:
m.Messages = append(m.Messages, Message{Text: msg.Message})
}
return m, nil
}
view Entry(props EntryProps) {
<li>{ props.Item.Text }</li>
}
view App(model Model) {
<div class="app">
<input value={ model.Draft } oninput={ DraftChanged{Text: event.target.value} } onenter={ PostClicked{} } />
<button onclick={ PostClicked{} }>Post</button>
if len(model.Messages) == 0 {
<p>No messages yet.</p>
} else {
<ul>
for i, message := range model.Messages {
<Entry key={ i } item={ message } />
}
</ul>
}
</div>
}// main.go
package main
import (
"context"
"errors"
"log"
"strings"
"github.com/metruzanca/gothic"
)
type procedures struct{}
func (procedures) Post(ctx context.Context, text string) (Message, error) {
text = strings.TrimSpace(text)
if text == "" {
return Message{}, errors.New("write something first")
}
return Message{Text: text}, nil
}
func main() {
s := gothic.NewServer()
RegisterProcedures(s, procedures{})
s.MountApp("/", gothic.NewApp(Model{}))
log.Fatal(s.ListenAndServe(":8080"))
}The full example adds an in-memory store so messages survive reloads, plus tests: examples/guestbook.
UI kit
The optional UI kit is a separately versioned Go module:
go get github.com/metruzanca/gothic/uiSee ui/README.md and the Gothicbook demo.
Status
Early, working proof of concept. Every example above runs end to end: server
rendering, hydration, the update loop, typed procedures, pure and stateful
components, conditionals, keyed lists, routing, an installable UI kit, and
server-rendered documents with OpenGraph metadata. Browser interop ships as the
separate browser module, long-list windowing as the separate virtual module,
and sessions and auth as the separate session and auth modules. The
guide covers the whole loop, and
SYNTAX.md is the full reference.
Credits
The gothic logo mark and wordmark are by Mackenzie Child (X). See CREDITS.md.
Learn more
Start with the quickstart guide.
Guide:
Reference: