web_spa
Skill3 starsChanged 3 months agoMITView on GitHub
Okapi serves a front-end application (React, Vue, Svelte, Angular, …) alongside the API. Real files are served directly; any unmatched path under the prefix falls back to the index document so the client-side router takes over. Two entry points: SPA / SPAFS / SPAConfig are deprecated aliases of Web / WebFS / WebConfig. They still work unchanged. Register Web/WebFS after your API routes so the API keeps precedence. Use the all: prefix in the //go:embed directive so files beginning with…
In this repository20 other files it gives its agents.
- authenticationSkill
- cliSkill
- contextSkill
- dynamic_routesSkill
- error_handlingSkill
- http_clientSkill
- middlewareSkill
- openapiSkill
- overviewSkill
- request_bindingSkill
- responseSkill
- route_definitionSkill
- routingSkill
- sse_streamSkill
- std_compatSkill
- templatingSkill
- testingSkill
- tls_httpsSkill
- validationSkill
- websocketSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 2 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 49
Use the all: prefix in the //go:embed directive so files beginning with _ or .
- Distinctive: line 68
If the path maps to a real file, that file is served.
- Distinctive: line 88
When you want plain file serving without the SPA fallback:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Okapi Web / SPA Serving
Okapi serves a front-end application (React, Vue, Svelte, Angular, …) alongside the API. Real files are served directly; any unmatched path under the prefix falls back to the index document so the client-side router takes over.
Two entry points:
o.Web(prefix, dir string, cfg ...WebConfig) // from a directory on disk
o.WebFS(prefix string, fsys fs.FS, cfg ...WebConfig) // from any fs.FS (embed.FS, os.DirFS, …)
SPA/SPAFS/SPAConfigare deprecated aliases ofWeb/WebFS/WebConfig. They still work unchanged.
Register Web/WebFS after your API routes so the API keeps precedence.
Serve from Disk (development)
o := okapi.Default()
o.Get("/api/v1/users", listUsers)
// Serves ./web/index.html for "/", "/login", "/users/42", ...
o.Web("/", "./web")
o.Start()Serve from an Embedded FS (production, single binary)
//go:embed all:web/dist
var dist embed.FS
func main() {
o := okapi.Default()
o.Get("/api/v1/users", listUsers)
o.WebFS("/", dist, okapi.WebConfig{
Root: "web/dist", // sub-directory inside the embed.FS
MaxAge: time.Hour, // Cache-Control for assets
})
o.Start()
}Use the all: prefix in the //go:embed directive so files beginning with _ or . (common in build output) are included.
WebConfig
| Field | Type | Description |
Index | string | File served for client-side routes. Defaults to index.html. |
Root | string | Sub-directory inside the fs.FS holding the built app. WebFS only — ignored by Web. |
Exclude | []string | Extra path prefixes that must never fall back to the index. |
DisableAutoExclude | bool | Turn off auto-excluding the top-level segment of registered routes; only Exclude is consulted. |
MaxAge | time.Duration | Cache-Control max-age for asset files. The index is always no-cache. |
The zero value is valid: serve index.html, auto-exclude registered API routes, no asset caching header.
Resolution Order
For every unmatched GET/HEAD request under the prefix:
- A registered route always wins (register
Weblast). - If the path maps to a real file, that file is served.
- Otherwise the index document is returned.
The top-level segment of every registered route is auto-excluded from the fallback, so an unknown path under an API namespace 404s instead of silently serving HTML. With /api/v1/users registered, /api/v1/missing returns 404 — not index.html.
Excluding Extra Paths
o.Web("/", "./web", okapi.WebConfig{
Exclude: []string{"/metrics", "/healthz"},
})Caching Behaviour
- Index document — always
Cache-Control: no-cache, so a new deploy is picked up immediately. - Assets — honour
WebConfig.MaxAge.MaxAge: time.HouremitsCache-Control: public, max-age=3600. Zero adds no header.
Static Files (no index fallback)
When you want plain file serving without the SPA fallback:
o.Static("/assets", "public/assets") // serve a directory, no directory listing
o.StaticFile("/favicon.ico", "favicon.ico") // serve a single file
o.StaticFS("/assets", http.FS(embedFS)) // serve from any http.FileSystemDirectory listing is disabled by default.
Mounting a Standard File Server
A catch-all segment ({any...}) hands a whole subtree to an http.Handler:
o.HandleHTTP("GET", "/assets/{any...}",
http.StripPrefix("/assets/", http.FileServer(http.Dir("./public"))))Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

