API Docs
How to replace the embedded Scalar docs UI with your own OpenAPI viewer.
How-to guide
This page shows how to customize or replace the embedded API reference UI. Runtime toggles
(DisableSpecHandler, DisableDocsHandler, BaseURL, server URL injection, and so on) are
documented in Runtime Configuration.
When entrest.Config.DisableSpecHandler is false
at generation time, entrest embeds the OpenAPI spec in your generated rest package and registers
GET {BasePath}/openapi.json and GET {BasePath}/docs (an embedded Scalar
UI). With the stdlib handler, GET / (after BasePath is stripped) redirects to /docs.
See Configuration — Base URL and path for how mount paths
affect these URLs.

Default embedded UI
The /docs route is implemented by Server.Docs. It renders a single inline HTML document on each
request and loads Scalar from the jsDelivr CDN — there is no separate static site.
There is no runtime option to tweak Scalar's theme or layout on the embedded /docs handler. To change
the UI, disable the embedded docs route and serve your own page (see below).
Route registration, spec serving, and DisableDocsHandler are covered in
Configuration — OpenAPI spec endpoint and
API reference docs.
Replace the embedded UI
Any OpenAPI viewer that accepts a spec URL can replace the embedded Scalar page:
- Set
DisableDocsHandlertotrueso/docsis not registered by the generated handler. - Keep
/openapi.jsonenabled (unless you serve the spec from another origin). - Register your own
GEThandler that returns a single HTML document. - Point the viewer at
{BasePath}/openapi.json(or an absolute URL if the UI is on another host).
The examples below use RapiDoc and mount custom docs at /v1/docs.
Stdlib (http.ServeMux)
This example serves one self-contained HTML page from Go with fmt.Fprintf, loads RapiDoc from the
unpkg CDN, and overrides component attributes for a focused dark layout.
// [...]
func rapidocDocs(baseURL string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
uri := strings.TrimSuffix(baseURL, "/")
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, `<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="referrer" content="no-referrer">
<script type="module" src="https://unpkg.com/rapidoc@9.3.8/dist/rapidoc-min.js"></script>
<title>Pet Store API</title>
</head>
<body>
<rapi-doc
allow-server-selection="false"
bg-color="#18181C"
fill-request-fields-with-example="false"
font-size="large"
layout="row"
load-fonts="false"
mono-font="Consolas, monaco, monospace"
nav-bg-color="#0F0F0F"
nav-hover-bg-color="#1B1B1B"
primary-color="#10B981"
regular-font="Consolas, monaco, monospace"
render-style="focused"
schema-description-expanded="true"
show-curl-before-try="true"
show-header="false"
show-method-in-nav-bar="as-colored-text"
spec-url=%q
text-color="#BBBBBB"
theme="dark"
use-path-in-nav-bar="true"
persist-auth="true"
></rapi-doc>
</body>
</html>`, uri+"/openapi.json")
}
}
func main() {
// [...]
mux := http.NewServeMux()
mux.HandleFunc("GET /v1/docs{$}", rapidocDocs(cfg.BaseURL))
mux.Handle("/", srv.Handler())
log.Fatal(http.ListenAndServe(":8080", mux))
}Chi
Register the docs route on the same sub-router where you mount the generated API. Set BasePath to
match the mount point so spec URLs stay correct — see
Configuration — Stdlib vs chi.
cfg := &rest.ServerConfig{
BaseURL: "https://api.example.com/v1",
BasePath: "/v1",
DisableDocsHandler: true,
}
srv, err := rest.NewServer(db, cfg)
if err != nil {
panic(err)
}
r := chi.NewRouter()
r.Route("/v1", func(r chi.Router) {
r.Get("/docs", rapidocDocs(cfg.BaseURL))
srv.Handler(r)
})
http.ListenAndServe(":8080", r)Last updated on

