GoTuna handles routing with the famous gorilla/mux package. For more info on how to use the Gorilla router please visit the official docs.

Action handlers

For every route, you should create a corresponding action handler.

package main

import (


func main() {
	app := gotuna.App{
		Router: gotuna.NewMuxRouter(),

	app.Router.Handle("/", handlerHome(app))
	app.Router.Handle("/login", handlerLogin(app)).Methods(http.MethodGet, http.MethodPost)
	app.Router.Handle("/api/shapes", handlerShapes(app))

	fmt.Println("Running on http://localhost:8888")
	http.ListenAndServe(":8888", app.Router)

func handlerHome(app gotuna.App) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Dashboard")

func handlerLogin(app gotuna.App) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Login form...")

func handlerShapes(app gotuna.App) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cars := []string{


Grouping routes

You can group several routes that share the same functionality. This is called “subrouting”.

// middlewares for all routes

// for logged in users
user := app.Router.NewRoute().Subrouter()
user.Handle("/", handlerHome(app)).Methods(http.MethodGet)
user.Handle("/profile", handlerProfile(app)).Methods(http.MethodGet, http.MethodPost)
user.Handle("/logout", handlerLogout(app)).Methods(http.MethodPost)

// for guests
guests := app.Router.NewRoute().Subrouter()
guests.Handle("/login", handlerLogin(app)).Methods(http.MethodGet, http.MethodPost)

Serving static files

A special handler is provided by the framework to serve your static files configured under app.Static with optional prefix app.StaticPrefix.

You can provide a custom handler to be used when the file is not found (404 page).

app.Static = os.DirFS("./static")

// this route is usually placed at the bottom (catch-all)
	Handler(http.StripPrefix(app.StaticPrefix, app.ServeFiles(http.NotFoundHandler()))).

Static files are passed into the app’s configuration using the io/fs package’s FS interface. This means that you can use both os.DirFS or go:embed to pack all your static files directly into the final binary.

Edit this page on GitHub