Files
Jakub Zych 1f8f5e1b51 feat(11.1-03): add the Architecture and Plugins docs sections
- architecture: introduction, Go modules and workspaces, application
  lifecycle, request lifecycle
- plugins: registration, scheduling, extending, testing
- verified Examples for backpack services, towel request context,
  pact schedules and festival events
- TestDocsRequiredPages lists the eight new pages
2026-09-30 22:12:08 +02:00
..

towel

Request-scoped actor, organization, collection and locale values carried through context.Context.

import "git.golem15.com/golem15/summercms/modules/towel"

Overview

towel replaces the request-global state that WinterCMS reads through facades (the current locale, the acting user) with explicit values on the request context. Middleware stores a value once, and any code further down the call chain that receives the context reads it back without a global lookup. surf sets the locale from Accept-Language (or the signed-in user's preferred locale) and the organization for every request, phrasebook reads the locale when it translates, and cabana sets it while localizing admin schemas.

Features

  • Four independent string values, each with a setter and a getter: actor (towel.WithActor, towel.Actor), organization (towel.WithOrganization, towel.Organization), collection (towel.WithCollection, towel.Collection) and locale (towel.WithLocale, towel.Locale).
  • Unexported context key types, so no other package can read or overwrite the values by accident.
  • Getters return (value, ok): a value that was set to an empty string is distinguishable from one that was never set.
  • Nil-safe: a setter given a nil context starts from context.Background(), and a getter given a nil context reports false.

Usage

package blog

import (
	"fmt"
	"net/http"

	"git.golem15.com/golem15/summercms/modules/towel"
)

// withAcmeScope tags every request with the organization and collection it serves.
func withAcmeScope(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := towel.WithOrganization(r.Context(), "acme")
		ctx = towel.WithCollection(ctx, "blog")
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func listPosts(w http.ResponseWriter, r *http.Request) {
	org, _ := towel.Organization(r.Context())
	locale, ok := towel.Locale(r.Context())
	if !ok {
		locale = "en"
	}
	fmt.Fprintf(w, "posts for %s in %s\n", org, locale)
}

API reference

Identifier Description
towel.WithActor / towel.Actor Store and read the acting user or client identifier.
towel.WithOrganization / towel.Organization Store and read the organization (tenant) the request belongs to.
towel.WithCollection / towel.Collection Store and read the collection the request operates on.
towel.WithLocale / towel.Locale Store and read the locale used for translations and localized responses.

Dependencies

  • SummerCMS modules: none.
  • Third-party: none.
  • Standard library: context.

Testing

go test ./modules/towel/...

The tests exercise plain contexts and need no external services.