119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
func writeJSON(w http.ResponseWriter, code int, v any) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(code)
|
|
_ = json.NewEncoder(w).Encode(v)
|
|
}
|
|
|
|
func jsonError(w http.ResponseWriter, code int, msg string) {
|
|
writeJSON(w, code, map[string]string{"error": msg})
|
|
}
|
|
|
|
// healthz — for k8s probes / load balancer.
|
|
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
|
writeJSON(w, 200, map[string]string{"status": "ok"})
|
|
}
|
|
|
|
func (s *Server) handleListPosts(w http.ResponseWriter, r *http.Request) {
|
|
channel := r.URL.Query().Get("channel")
|
|
posts, err := s.store.ListPosts(channel, 20)
|
|
if err != nil {
|
|
jsonError(w, 500, err.Error())
|
|
return
|
|
}
|
|
if posts == nil {
|
|
posts = []Post{} // never return null to clients
|
|
}
|
|
writeJSON(w, 200, map[string]any{"posts": posts})
|
|
}
|
|
|
|
func (s *Server) handleGetPost(w http.ResponseWriter, r *http.Request) {
|
|
id := strings.TrimPrefix(r.URL.Path, "/api/posts/")
|
|
if id == "" || strings.Contains(id, "/") {
|
|
jsonError(w, 400, "bad id")
|
|
return
|
|
}
|
|
post, err := s.store.GetPost(id)
|
|
if err != nil {
|
|
jsonError(w, 404, "not found")
|
|
return
|
|
}
|
|
comments, err := s.store.ListComments(id)
|
|
if err != nil {
|
|
jsonError(w, 500, err.Error())
|
|
return
|
|
}
|
|
if comments == nil {
|
|
comments = []Comment{}
|
|
}
|
|
writeJSON(w, 200, PostWithComments{Post: *post, Comments: comments})
|
|
}
|
|
|
|
func (s *Server) handleCreatePost(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
jsonError(w, 405, "POST only")
|
|
return
|
|
}
|
|
author := r.Header.Get("X-Posts-Author")
|
|
if author == "" {
|
|
jsonError(w, 401, "X-Posts-Author required (v0: no auth, just header)")
|
|
return
|
|
}
|
|
var req CreatePostRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
jsonError(w, 400, "bad json")
|
|
return
|
|
}
|
|
if strings.TrimSpace(req.Body) == "" {
|
|
jsonError(w, 400, "body required")
|
|
return
|
|
}
|
|
post, err := s.store.CreatePost(author, req.Title, req.Body, req.Channels)
|
|
if err != nil {
|
|
jsonError(w, 500, err.Error())
|
|
return
|
|
}
|
|
writeJSON(w, 201, post)
|
|
}
|
|
|
|
func (s *Server) handleCreateComment(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
jsonError(w, 405, "POST only")
|
|
return
|
|
}
|
|
author := r.Header.Get("X-Posts-Author")
|
|
if author == "" {
|
|
jsonError(w, 401, "X-Posts-Author required")
|
|
return
|
|
}
|
|
// path: /api/posts/:id/comments
|
|
parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
|
|
// expected: ["api","posts",":id","comments"]
|
|
if len(parts) != 4 {
|
|
jsonError(w, 400, "bad path")
|
|
return
|
|
}
|
|
postID := parts[2]
|
|
var req CreateCommentRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
jsonError(w, 400, "bad json")
|
|
return
|
|
}
|
|
if strings.TrimSpace(req.Body) == "" {
|
|
jsonError(w, 400, "body required")
|
|
return
|
|
}
|
|
c, err := s.store.AddComment(postID, req.ParentID, author, req.Body)
|
|
if err != nil {
|
|
jsonError(w, 400, err.Error())
|
|
return
|
|
}
|
|
writeJSON(w, 201, c)
|
|
}
|