feat(handlers): /api/healthz, posts, comments, authors, channels
This commit is contained in:
parent
c93e236267
commit
4927eb6a11
1 changed files with 158 additions and 0 deletions
158
handler.go
Normal file
158
handler.go
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
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})
|
||||
}
|
||||
|
||||
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
count, errors := s.store.FlushStats()
|
||||
mem := s.store.MemUsage()
|
||||
writeJSON(w, 200, map[string]any{
|
||||
"status": "ok",
|
||||
"flushes": count,
|
||||
"flush_errors": errors,
|
||||
"mem": mem,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) handleListPosts(w http.ResponseWriter, r *http.Request) {
|
||||
channel := r.URL.Query().Get("channel")
|
||||
posts := s.store.ListPosts(channel, 20)
|
||||
if posts == nil {
|
||||
posts = []*Post{}
|
||||
}
|
||||
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, ok := s.store.GetPost(id)
|
||||
if !ok {
|
||||
jsonError(w, 404, "not found")
|
||||
return
|
||||
}
|
||||
comments := s.store.ListComments(id)
|
||||
if comments == nil {
|
||||
comments = []*Comment{}
|
||||
}
|
||||
writeJSON(w, 200, PostWithComments{Post: *post, Comments: comments})
|
||||
}
|
||||
|
||||
func (s *Server) handleCreatePost(w http.ResponseWriter, r *http.Request) {
|
||||
author := r.Header.Get("X-Posts-Author")
|
||||
if author == "" {
|
||||
jsonError(w, 401, "X-Posts-Author required")
|
||||
return
|
||||
}
|
||||
var req CreatePostRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
jsonError(w, 400, "bad json")
|
||||
return
|
||||
}
|
||||
m := &CreatePost{
|
||||
AuthorID: author,
|
||||
Title: req.Title,
|
||||
Body: req.Body,
|
||||
Channels: req.Channels,
|
||||
}
|
||||
if err := Submit(r.Context(), s.store, m); err != nil {
|
||||
jsonError(w, 400, err.Error())
|
||||
return
|
||||
}
|
||||
post, _ := s.store.GetPost(m.ResolvedPostID())
|
||||
writeJSON(w, 201, post)
|
||||
}
|
||||
|
||||
func (s *Server) handleCreateComment(w http.ResponseWriter, r *http.Request) {
|
||||
author := r.Header.Get("X-Posts-Author")
|
||||
if author == "" {
|
||||
jsonError(w, 401, "X-Posts-Author required")
|
||||
return
|
||||
}
|
||||
parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
|
||||
if len(parts) != 4 || parts[0] != "api" || parts[1] != "posts" || parts[3] != "comments" {
|
||||
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
|
||||
}
|
||||
m := &AddComment{
|
||||
PostID: postID,
|
||||
ParentID: req.ParentID,
|
||||
AuthorID: author,
|
||||
Body: req.Body,
|
||||
}
|
||||
if err := Submit(r.Context(), s.store, m); err != nil {
|
||||
jsonError(w, 400, err.Error())
|
||||
return
|
||||
}
|
||||
comments := s.store.ListComments(postID)
|
||||
var created *Comment
|
||||
for _, c := range comments {
|
||||
if c.ID == m.ResolvedCommentID() {
|
||||
created = c
|
||||
break
|
||||
}
|
||||
}
|
||||
writeJSON(w, 201, created)
|
||||
}
|
||||
|
||||
|
||||
func (s *Server) handleUpsertAuthor(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
ID string `json:"id"`
|
||||
Kind string `json:"kind"`
|
||||
DisplayName string `json:"display_name"`
|
||||
AvatarURL string `json:"avatar_url,omitempty"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
jsonError(w, 400, "bad json")
|
||||
return
|
||||
}
|
||||
m := &UpsertAuthor{ID: req.ID, AuthorKind: req.Kind, DisplayName: req.DisplayName, AvatarURL: req.AvatarURL}
|
||||
if err := Submit(r.Context(), s.store, m); err != nil {
|
||||
jsonError(w, 400, err.Error())
|
||||
return
|
||||
}
|
||||
a, _ := s.store.GetAuthor(m.ID)
|
||||
writeJSON(w, 200, a)
|
||||
}
|
||||
|
||||
func (s *Server) handleUpsertChannel(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Slug string `json:"slug"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
jsonError(w, 400, "bad json")
|
||||
return
|
||||
}
|
||||
m := &UpsertChannel{Slug: req.Slug, Name: req.Name, Description: req.Description}
|
||||
if err := Submit(r.Context(), s.store, m); err != nil {
|
||||
jsonError(w, 400, err.Error())
|
||||
return
|
||||
}
|
||||
c, _ := s.store.GetChannel(m.Slug)
|
||||
writeJSON(w, 200, c)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue