Response Helpers
The contract/response package provides functions for writing HTTP responses with proper content types and status codes. Since Cosmos handlers return error, these functions return error too, letting you chain them in a single return statement.
Serialize any value to JSON:
import "github.com/studiolambda/cosmos/contract/response"
func listUsers(w http.ResponseWriter, r *http.Request) error { users := []User{{Name: "Alice"}, {Name: "Bob"}} return response.JSON(w, http.StatusOK, users)}Sets Content-Type: application/json and uses json.Encoder for streaming serialization.
Serialize to XML:
return response.XML(w, http.StatusOK, catalog)Sets Content-Type: application/xml.
Write an HTML string:
return response.HTML(w, http.StatusOK, "<h1>Hello</h1>")Sets Content-Type: text/html.
HTML Templates
Section titled “HTML Templates”Render a Go html/template:
tmpl := template.Must(template.ParseFiles("page.html"))
func page(w http.ResponseWriter, r *http.Request) error { return response.HTMLTemplate(w, http.StatusOK, *tmpl, data)}Plain Text
Section titled “Plain Text”Write plain text:
return response.String(w, http.StatusOK, "OK")Sets Content-Type: text/plain; charset=utf-8.
Text Templates
Section titled “Text Templates”Render a Go text/template:
tmpl := template.Must(template.New("").Parse("Hello, {{.Name}}!"))
return response.StringTemplate(w, http.StatusOK, *tmpl, data)Raw Bytes
Section titled “Raw Bytes”Write raw bytes. If no Content-Type header is set, defaults to application/octet-stream:
return response.Raw(w, http.StatusOK, rawData)Binary Data
Section titled “Binary Data”Write binary data with Content-Type: application/octet-stream:
return response.Bytes(w, http.StatusOK, fileContents)Status Only
Section titled “Status Only”Send a status code with no body:
return response.Status(w, http.StatusNoContent)Redirects
Section titled “Redirects”Send an HTTP redirect:
return response.Redirect(w, http.StatusFound, "/dashboard")Common status codes for redirects:
301— Moved Permanently302— Found (temporary)303— See Other (after POST)307— Temporary Redirect (preserves method)308— Permanent Redirect (preserves method)
Safe Redirects
Section titled “Safe Redirects”When the redirect URL comes from user input, use SafeRedirect to prevent open redirect vulnerabilities:
return response.SafeRedirect(w, http.StatusFound, userProvidedPath)SafeRedirect validates that the URL is a relative path (starts with /). It rejects absolute URLs, protocol-relative URLs (//), and dangerous schemes like javascript: or data:. Returns response.ErrUnsafeRedirect for invalid URLs.
Streaming
Section titled “Streaming”Stream data to the client in real time using channels:
func streamLogs(w http.ResponseWriter, r *http.Request) error { ch := make(chan []byte)
go func() { defer close(ch) for line := range logSource { ch <- []byte(line + "\n") } }()
return response.Stream(w, r, ch)}Stream sets Cache-Control: no-cache and Connection: keep-alive, then reads from the channel and flushes after each write. It returns when:
- The channel is closed (graceful shutdown, returns
nil). - The request context is canceled (returns the context error).
If the http.ResponseWriter does not support http.Flusher, it returns response.ErrNonFlushableWriter.
Server-Sent Events (SSE)
Section titled “Server-Sent Events (SSE)”For SSE, use the SSE function which adds the Content-Type: text/event-stream header and delegates to Stream:
func events(w http.ResponseWriter, r *http.Request) error { ch := make(chan []byte)
go func() { defer close(ch) for event := range eventSource { data, _ := json.Marshal(event) ch <- append([]byte("data: "), append(data, '\n', '\n')...) } }()
return response.SSE(w, r, ch)}You’re responsible for formatting the SSE data according to the EventSource specification — the function handles the streaming transport.