Stories Get
Return a single story by slug. Resolves real DB rows first, then falls back to the demo set — so the public /story/[slug] page on the frontend works for both onboarded publishers' articles and the curated demo content. When the article has a completed render-job, audio_url is populated so the frontend player can stream the pre-rendered audio without paying for a second inference call.
Perf 5-17: a single story is effectively immutable for the cache window — body_text + audio_url only flip when a render completes or an operator re-curates. 60s shared cache + SWR absorbs the bursty "10 listeners open the same share link" pattern (e.g., social shares) without hitting Fly for every fetch. The frontend story page was cold-fetching this endpoint on every nav and paying 18s on cold start; the edge cache eliminates that path entirely after the first visitor.
Pool-safety (2026-08-11 SEV) — TWO PHASES, ONE CONNECTION AT A TIME
This handler used to carry db: AsyncSession = Depends(get_db). That bound a PRIMARY connection to the whole request while phase 1 below independently checked out a REPLICA connection — so every /v1/stories/{slug} hit pinned two pooled connections at once, and held the primary one completely idle across the expensive replica read AND across the synchronous boto3 R2 head_object round-trips get_story_full issues per audio variant (app/search.py has_audio).
On 2026-08-11 a ~3.4x burst on this endpoint (713 requests in five minutes, almost all daily-brief-*) drove the single app task to 99% CPU; with the event loop starved, every parked coroutine kept its connections, and BOTH pools hit their 15+5 ceiling within ~90 seconds. Twelve endpoints returned QueuePool limit of size 15 overflow 5 reached.
Fix: run the expensive read holding ZERO primary connections, then open a short-lived primary session for the cheap point-lookups and release it in a finally. Peak concurrent connections per request drops from 2 to 1, and the primary is never held across R2.
Request
- Base URL: https://api.storyflo.com (the document declares no server; this is the origin it was published from)
- URL: https://api.storyflo.com/v1/stories/{slug}
- Auth: none declared
Path parameters
Headers
Response
Successful Response
Changes
No recorded changes to this operation across all 1 revision of this API.