Blog Atom Feed
Atom XML feed of the last 20 published blog posts. Same data as the RSS feed in Atom format. Content-Type application/atom+xml. CDN 15min/30min SWR.
GET /api/v1/public/blog/feed.atom โ ๐ Public ยท Rate limit: 30 req / minute
Returns the last 20 published blog posts as an Atom XML feed โ same data as GET /public/blog/feed (RSS 2.0) in Atom format. Use this for clients that prefer Atom (more strict spec, ISO 8601 timestamps).
Same data, different format. RSS and Atom present the same 20 posts โ pick whichever your reader prefers. Most modern feed readers handle both. Atom is generally preferred for new clients (cleaner spec, ISO 8601 timestamps), RSS for compatibility with older readers.
Different response shape from the rest of the portal. Returns raw XML with Content-Type: application/atom+xml; charset=utf-8 โ NOT the standard JSON envelope. Same caveat as the RSS feed.
Request
No body, no params, no headers required.
Response headers
| Header | Value |
|---|---|
Content-Type | application/atom+xml; charset=utf-8 |
Cache-Control | public, s-maxage=900, stale-while-revalidate=1800 |
Response
200 OK โ Atom XML
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>BIO.RE Blog</title>
<link href="https://bio.re/blog" rel="alternate"/>
<link href="https://bio.re/api/v1/public/blog/feed.atom" rel="self"/>
<id>https://bio.re/blog</id>
<updated>2026-04-29T20:00:00.000Z</updated>
<entry>
<title>Introducing BIO.RE</title>
<link href="https://bio.re/blog/introducing-biore"/>
<id>https://bio.re/blog/introducing-biore</id>
<updated>2026-04-29T20:00:00.000Z</updated>
<summary><![CDATA[A short excerpt of the post...]]></summary>
</entry>
</feed>XML elements
| Element | Source | Notes |
|---|---|---|
feed.title | hardcoded | BIO.RE Blog |
feed.link[rel=alternate] | hardcoded | https://bio.re/blog (the human-readable blog) |
feed.link[rel=self] | hardcoded | This feed's URL |
feed.id | hardcoded | https://bio.re/blog |
feed.updated | computed | The most recent publishedAt of any item, formatted as ISO 8601 (UTC) |
entry.title / entry.link / entry.id / entry.updated | per post | Individual post metadata. Title is XML-escaped server-side. |
entry.summary | per post | The post's excerpt (or empty), wrapped in CDATA[] |
Note: Atom feed does not include <category> elements (RSS-only). If you need category data, use the JSON GET /public/blog list.
Errors
| HTTP | Reason |
|---|---|
429 | Rate limit exceeded (30 req/min) |
Side effects
getBlogFeedItems()โ same call as the RSS feed (last 20 published, same selection).- Build Atom XML string by concatenation. Each user-controllable field passes through
xmlEscape(). - Set
Content-Type: application/atom+xml; charset=utf-8+ cache header on the raw response. - Return the XML body. No mutations.
Code samples
curl https://api.bio.re/api/v1/public/blog/feed.atomhttps://api.bio.re/api/v1/public/blog/feed.atomPaste this URL into a feed reader that supports Atom (most modern ones โ NetNewsWire, Feedly, Reeder, Inoreader).
// Server-side โ fetch + parse with rss-parser (handles Atom too)
import Parser from 'rss-parser';
const parser = new Parser();
async function fetchBlogAtomFeed() {
const feed = await parser.parseURL('https://api.bio.re/api/v1/public/blog/feed.atom');
for (const item of feed.items) {
console.log(item.title, item.link, item.isoDate);
}
}Try it
curl -X GET "https://loading/api/v1/public/blog/feed.atom"Source
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/content/public-content.controller.ts | 224โ237 (getBlogAtomFeed), 145โ147 (xmlEscape), 181โ207 (buildAtom) |
| Service | apps/api-core/src/modules/content/content.service.ts | 578โ... (getBlogFeedItems โ shared with RSS feed) |
| Prisma model | packages/prisma/prisma/schema.prisma | BlogPost (filter status = PUBLISHED) |
| Bot detection skip | apps/api-core/src/common/decorators/skip-bot-detection.decorator.ts | @SkipBotDetection() |
Blog RSS Feed
RSS 2.0 XML feed of the last 20 published blog posts. Content-Type application/rss+xml. Bot-detection skipped (feed readers should not be flagged). CDN 15min/30min SWR.
Get Blog Post (by slug)
Public read of a single blog post by slug. PUBLISHED-only. HTML body server-side sanitized. Categories embedded as { name, slug } pairs. 404 on missing/draft.