3.0 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | ||||
|---|---|---|---|---|---|---|---|---|
| api | Blog Endpoints | Public blog listing and administrator-only post management endpoints. |
|
2026-07-23T10:12:24Z |
Endpoints
| Method | Path | Access | Behavior |
|---|---|---|---|
GET |
/api/v1/blog/posts |
Public | Returns published posts only, newest publication first. |
GET |
/api/v1/admin/blog/posts |
Admin | Returns drafts and published posts, ordered by most recently updated. |
GET |
/api/v1/admin/blog/posts/:id |
Admin | Returns one post or 404 NOT_FOUND. |
POST |
/api/v1/admin/blog/posts |
Admin + CSRF | Creates a draft or published post; defaults to draft. |
PUT |
/api/v1/admin/blog/posts/:id |
Admin + CSRF | Partially updates title, Markdown body, or status. |
DELETE |
/api/v1/admin/blog/posts/:id |
Admin + CSRF | Deletes a post and returns 204; missing posts return 404 NOT_FOUND. |
The public route is marked @Public(). Admin routes require a Bearer JWT with the administrator role, and unsafe requests use the standard CSRF cookie/header contract from REST API Overview.
Schema
Public list response
{
"posts": [
{
"id": "post-id",
"title": "Event update",
"publishedAt": "2026-07-23T10:00:00.000Z",
"bodyMd": "# Welcome"
}
]
}
Drafts and administrative fields such as status, createdAt, and updatedAt are excluded.
Admin post
| Field | Type | Description |
|---|---|---|
id |
string | Server-generated UUID. |
title |
string | Trimmed title, required, maximum 200 characters. |
bodyMd |
string | Markdown body, maximum 200,000 characters. |
status |
draft or published |
Visibility state. |
createdAt |
ISO 8601 string | Creation time. |
updatedAt |
ISO 8601 string | Last persistence update. |
publishedAt |
ISO 8601 string or null | First publication time. |
POST accepts title, optional bodyMd, and optional status. PUT accepts any subset of those fields. Validation failures use HTTP 400 with code VALIDATION_FAILED.
Publication behavior
- Creating with
status: "published"setspublishedAt; omitted status creates a draft. - Publishing a never-published draft sets
publishedAtonce. - Editing a published post does not change
publishedAt. - Moving a post back to draft preserves
publishedAt; republishing retains the original timestamp. - Only rows currently marked
publishedare returned by the public endpoint.
Wiring
BlogModule registers BlogController/BlogService for the public list and AdminBlogController/AdminBlogService for management. Both services access BlogPostEntity through TypeOrmModule.forFeature([BlogPostEntity]). The Angular BlogApiService calls these routes for the admin page, authenticated Blog page, and landing-page post list.