package page import ( "bytes" "encoding/json" "errors" "io/fs" "net/http" ) // RenderJSON is analogous to Render, though it renders the page, // as a JSON key "content", optionally from the YAML it'll include // additional keys in the json if specified under the 'pageJson' key. // E.g. // // --- // title: Some page // description: Some page desc // jsonvars: // - includeMeInJSON // vars: // notIncluded: some value // includeMeInJSON: // some: arbitrary // data: to // send: down // |-- // My page content, wee! func RenderJSON(w http.ResponseWriter, r *http.Request, //nolint:funlen path string, vars map[string]interface{}, statusCode int) { // Sepcifically use the specified path for the page p := NewPage(path) if vars != nil { p.Vars = vars } out := map[string]interface{}{} buf := &bytes.Buffer{} err := p.Render(buf) if err != nil { if errors.Is(err, fs.ErrNotExist) { renderJSONErr(w, "Not found", http.StatusNotFound) return } logErr(r, "rendering JSON encountered", err) renderJSONErr(w, "Internal server error", http.StatusInternalServerError) return } if r.URL.Query().Get("content") == "1" { out["Content"] = buf.String() } if r.URL.Query().Get("markdown") == "1" { p.setRenderingMarkdownOnly() // Tossing the error, since it would've been revealed above md, _ := p.GetMarkdown() out["Markdown"] = md } // Make a "set" of keys keys := map[string]struct{}{} for _, k := range p.JSONVars { keys[k] = struct{}{} } // And chuck the keys specified into the output for k, v := range p.Vars { _, ok := keys[k] if ok { out[k] = v } } w.WriteHeader(statusCode) enc := json.NewEncoder(w) enc.SetIndent("", " ") enc.SetEscapeHTML(false) err = enc.Encode(out) if err != nil { logErr(r, "while writing to buf", err) return } logReq(r, statusCode) } func renderJSONErr(w http.ResponseWriter, msg string, statusCode int) { enc := json.NewEncoder(w) w.WriteHeader(statusCode) _ = enc.Encode(&struct { StatusCode int Msg string }{ StatusCode: statusCode, Msg: msg, }) }