/v1/openapi.json is the API clients use — OpenAI's endpoints, Anthropic's, and what llmgw adds — in OpenAPI 3.1, generated from internal/clientapi's route table by the generator the admin API's document comes from, now told each document's title, server, token and error. A test reads the router's mux.HandleFunc calls and refuses a route described and not mounted, or mounted and not described. Asked for before there is a key, so it needs none. /docs/api shows it in Swagger UI 5.33.1 (Apache 2.0, served from the gateway as the page's policy requires): Authorize takes a key, Try it out sends to this gateway. Staff are offered the admin API's document too, from /docs/api/admin.json, which nobody else is given. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
39 lines
1.2 KiB
Go
39 lines
1.2 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"html/template"
|
|
"net/http"
|
|
)
|
|
|
|
type apiDocsData struct {
|
|
Version string
|
|
Nav Nav
|
|
SignedIn bool
|
|
SignIn bool
|
|
// Specs are the documents the page offers, as Swagger UI's urls: the
|
|
// client API's to everyone, the admin API's to staff.
|
|
Specs template.JS
|
|
}
|
|
|
|
// APIDocs renders the APIs' reference: their OpenAPI documents in Swagger
|
|
// UI, served from the gateway like every other script here.
|
|
func APIDocs(version string, signIn bool) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
d := apiDocsData{Version: version, SignIn: signIn}
|
|
if n, ok := r.Context().Value(navKey{}).(Nav); ok {
|
|
n.Current = "docs"
|
|
d.Nav, d.SignedIn = n, true
|
|
}
|
|
specs := []map[string]string{{"name": "client API (/v1)", "url": "/v1/openapi.json"}}
|
|
if d.Nav.Admin {
|
|
// The admin API is on its own listener, which a browser here
|
|
// does not reach: its document is offered to read, not to try.
|
|
specs = append(specs, map[string]string{"name": "admin API (admin listener)", "url": "/docs/api/admin.json"})
|
|
}
|
|
b, _ := json.Marshal(specs)
|
|
d.Specs = template.JS(b) //nolint:gosec // our own JSON
|
|
render(w, r, "apidocs", d)
|
|
}
|
|
}
|