feat(handlers): /api/healthz, posts, posts/:id, posts/:id/comments
This commit is contained in:
parent
a12b4da978
commit
124784dd79
1 changed files with 119 additions and 0 deletions
119
api/handler.go
Normal file
119
api/handler.go
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue