apps/posts/handlers_api.go 3.0 K raw
1
package main
2
3
import (
4
	"net/http"
5
	"strconv"
6
7
	"github.com/stevedylandev/andromeda/pkg/web"
8
)
9
10
const defaultListLimit int64 = 30
11
12
type apiPostSummary struct {
13
	ShortID         string  `json:"short_id"`
14
	Title           *string `json:"title"`
15
	Slug            string  `json:"slug"`
16
	PublishedDate   *string `json:"published_date"`
17
	MetaDescription *string `json:"meta_description"`
18
	MetaImage       *string `json:"meta_image"`
19
	CanonicalURL    *string `json:"canonical_url"`
20
	Lang            string  `json:"lang"`
21
	Tags            *string `json:"tags"`
22
	Content         string  `json:"content"`
23
	CreatedAt       string  `json:"created_at"`
24
	UpdatedAt       string  `json:"updated_at"`
25
	Weather         *string  `json:"weather"`
26
}
27
28
type apiPostDetail struct {
29
	ShortID         string  `json:"short_id"`
30
	Title           *string `json:"title"`
31
	Slug            string  `json:"slug"`
32
	Alias           *string `json:"alias"`
33
	CanonicalURL    *string `json:"canonical_url"`
34
	PublishedDate   *string `json:"published_date"`
35
	MetaDescription *string `json:"meta_description"`
36
	MetaImage       *string `json:"meta_image"`
37
	Lang            string  `json:"lang"`
38
	Tags            *string `json:"tags"`
39
	Content         string  `json:"content"`
40
	CreatedAt       string  `json:"created_at"`
41
	UpdatedAt       string  `json:"updated_at"`
42
	Weather         *string  `json:"weather"`
43
}
44
45
func toSummary(p Post) apiPostSummary {
46
	return apiPostSummary{
47
		ShortID: p.ShortID, Title: p.Title, Slug: p.Slug,
48
		PublishedDate: p.PublishedDate, MetaDescription: p.MetaDescription,
49
		MetaImage: p.MetaImage, CanonicalURL: p.CanonicalURL,
50
		Lang: p.Lang, Tags: p.Tags, Content: p.Content,
51
		CreatedAt: p.CreatedAt, UpdatedAt: p.UpdatedAt, Weather: p.Weather,
52
	}
53
}
54
55
func toDetail(p Post) apiPostDetail {
56
	return apiPostDetail{
57
		ShortID: p.ShortID, Title: p.Title, Slug: p.Slug,
58
		Alias: p.Alias, CanonicalURL: p.CanonicalURL,
59
		PublishedDate: p.PublishedDate, MetaDescription: p.MetaDescription,
60
		MetaImage: p.MetaImage, Lang: p.Lang, Tags: p.Tags,
61
		Content: p.Content, CreatedAt: p.CreatedAt, UpdatedAt: p.UpdatedAt, Weather: p.Weather,
62
	}
63
}
64
65
func (a *App) apiListPosts(w http.ResponseWriter, r *http.Request) {
66
	limit := defaultListLimit
67
	if v := r.URL.Query().Get("limit"); v != "" {
68
		if n, err := strconv.ParseInt(v, 10, 64); err == nil && n >= 0 {
69
			limit = n
70
		}
71
	}
72
	posts, err := getPublishedPosts(a.DB, limit)
73
	if err != nil {
74
		web.WriteError(w, http.StatusInternalServerError, "internal server error")
75
		return
76
	}
77
	out := make([]apiPostSummary, 0, len(posts))
78
	for _, p := range posts {
79
		out = append(out, toSummary(p))
80
	}
81
	web.WriteJSON(w, http.StatusOK, map[string]any{"posts": out})
82
}
83
84
func (a *App) apiGetPost(w http.ResponseWriter, r *http.Request) {
85
	post, err := getPostBySlug(a.DB, r.PathValue("slug"))
86
	if err != nil {
87
		web.WriteError(w, http.StatusInternalServerError, "internal server error")
88
		return
89
	}
90
	if post == nil || post.Status != "published" {
91
		web.WriteError(w, http.StatusNotFound, "not found")
92
		return
93
	}
94
	web.WriteJSON(w, http.StatusOK, toDetail(*post))
95
}