API del blog: come recuperare e renderizzare contenuti da un CMS headless in qualsiasi framework
Ogni framework ha il proprio tutorial di SDK CMS. La doc di Next.js vi mostra Contentful. La doc di Nuxt vi mostra Sanity. La doc di SvelteKit vi mostra Storyblok. La doc di Astro vi mostra Strapi. Nessuna vi mostra quello che volete davvero: un endpoint, una forma JSON, cinque frontend che la consumano senza alcun SDK proprietario in nessuno di essi. Il risultato sono team che scelgono un CMS, restano legati alla sua libreria client, e ri-piattaformano ogni volta che cambiano framework. Una API del blog che restituisce REST JSON puro rompe questo schema. Questo articolo percorre un endpoint del genere, la forma che restituisce e il codice fetch esatto per Next.js, Nuxt, SvelteKit, Astro e React puro.
Punti chiave rapidi
- Una API del blog è semplicemente un endpoint REST che restituisce articoli in JSON. Nessun SDK richiesto.
- Lo stesso endpoint può alimentare Next.js, Nuxt, SvelteKit, Astro e React con meno di 15 righe di fetch per framework.
- Una forma di risposta pulita include id, title, slug, content (markdown o HTML), excerpt, featured_image_url, language e parent_article_id per le traduzioni.
- Kamaan è il centro di comando per fondatori multi-prodotto e agenzie che gestiscono molti blog SaaS: gestite ogni blog da un'unica dashboard, e conducete ogni operazione su tutti da Claude, ChatGPT, Cursor o qualsiasi client MCP.
- Il cablaggio iniziale richiede 40-60 minuti a uno sviluppatore. I blog successivi riutilizzano lo stesso schema di fetch.
Perché una API del blog portabile conta più di un nuovo SDK
Il lavoro di un CMS è memorizzare contenuti e restituirli. Gli SDK aggiungono un involucro attorno a questo lavoro. Gli involucri sembrano utili all'inizio, poi diventano attrito. Aggiornate il framework, l'SDK si rompe. Cambiate framework, l'SDK non esiste. Avviate un secondo prodotto, pagate per space e per posto per un SDK attorno a cui avete già scritto codice di collegamento. Una semplice API REST salta tutto questo. Se il vostro CMS restituisce JSON, il vostro frontend può renderizzarlo.
Questo articolo usa la REST API di Kamaan come esempio guida perché restituisce una forma JSON piatta e prevedibile e perché lo stesso endpoint serve ogni sito del vostro account. Lo schema sotto funziona contro qualsiasi CMS che esponga REST. Se volete un'introduzione più profonda alla scelta architetturale, il pilastro su come aggiungere un blog a un SaaS copre quando scegliere headless rispetto a un blog interno all'app. Il pezzo complementare su cos'è un CMS headless spiega la separazione tra memorizzazione del contenuto e rendering.
Ecco come appare lo stesso fetch a colpo d'occhio sui cinque framework:

L'endpoint di esempio e la forma di risposta
Ecco la chiamata che ogni framework sotto effettua:
GET https://api.kamaan.io/v1/sites/{site_id}/articles?language=en&status=published
Authorization: Bearer kmn_pk_live_xxxxxxxxxxxxxxxx
La risposta è un array JSON di articoli. Ogni voce appare così:
{
"id": "art_2k1nB7Vy8q",
"title": "Blog API: How to Fetch and Render Headless CMS Content in Any Framework",
"slug": "blog-api",
"content": "# Blog API\n\nEvery framework has its own CMS SDK tutorial...",
"excerpt": "One Kamaan endpoint, rendered five different ways.",
"featured_image_url": "https://cdn.kamaan.io/img/km0013_featured.png",
"language": "en",
"parent_article_id": null,
"status": "published",
"published_at": "2026-05-29T10:14:00Z",
"updated_at": "2026-05-29T10:14:00Z",
"meta_title": "Blog API: One Endpoint, Five Frontends",
"meta_description": "How to fetch and render headless CMS content...",
"tags": ["headless-cms", "blog-api", "developer-integration"]
}
Per ottenere un singolo articolo tramite slug:
GET https://api.kamaan.io/v1/sites/{site_id}/articles/blog-api?language=en
Le traduzioni puntano alla sorgente tramite parent_article_id. Per chiedere la versione tedesca dello stesso pezzo, cambiate language=en in language=de. Non c'è un endpoint di traduzione aggiuntivo. L'oggetto articolo ha la stessa forma in tutte le lingue, il che significa che il vostro livello di routing non deve ramificarsi sulla locale.
Fetch numero uno: Next.js App Router
Componente server, gira al build o on-demand con controllo della cache:
// app/blog/page.tsx
const SITE_ID = process.env.KAMAAN_SITE_ID!;
const TOKEN = process.env.KAMAAN_TOKEN!;
async function getArticles() {
const res = await fetch(
`https://api.kamaan.io/v1/sites/${SITE_ID}/articles?language=en&status=published`,
{
headers: { Authorization: `Bearer ${TOKEN}` },
next: { revalidate: 600 },
},
);
if (!res.ok) throw new Error("Kamaan fetch failed");
return res.json();
}
export default async function BlogIndex() {
const articles = await getArticles();
return (
<ul>
{articles.map((a: any) => (
<li key={a.id}>
<a href={`/blog/${a.slug}`}>{a.title}</a>
<p>{a.excerpt}</p>
</li>
))}
</ul>
);
}
La riga next: { revalidate: 600 } dice a Next.js di mettere in cache la risposta per 10 minuti. Per un blog marketing che pubblica qualche volta a settimana, è il default giusto. Se volete pura staticità, passate a force-cache. Se volete ogni richiesta fresca, passate a no-store. Per lo schema completo, inclusa la pagina di dettaglio dell'articolo e la rigenerazione statica incrementale, vedete la guida Next.js per CMS headless.
Fetch numero due: Nuxt 3
Stesso endpoint, composable useFetch, gira lato server durante l'SSR:
<!-- pages/blog/index.vue -->
<script setup lang="ts">
const config = useRuntimeConfig();
const { data: articles } = await useFetch(
`https://api.kamaan.io/v1/sites/${config.kamaanSiteId}/articles`,
{
query: { language: "en", status: "published" },
headers: { Authorization: `Bearer ${config.kamaanToken}` },
server: true,
},
);
</script>
<template>
<ul>
<li v-for="a in articles" :key="a.id">
<NuxtLink :to="`/blog/${a.slug}`">{{ a.title }}</NuxtLink>
<p>{{ a.excerpt }}</p>
</li>
</ul>
</template>
useFetch deduplica automaticamente la chiamata tra render server e idratazione client. La runtime config tiene il token fuori dal bundle client.
Fetch numero tre: SvelteKit
La funzione load lato server vi dà controllo totale sugli header di cache:
// routes/blog/+page.server.ts
import { KAMAAN_SITE_ID, KAMAAN_TOKEN } from "$env/static/private";
export async function load({ fetch, setHeaders }) {
const res = await fetch(
`https://api.kamaan.io/v1/sites/${KAMAAN_SITE_ID}/articles?language=en&status=published`,
{ headers: { Authorization: `Bearer ${KAMAAN_TOKEN}` } },
);
setHeaders({ "cache-control": "public, max-age=600" });
return { articles: await res.json() };
}
<!-- routes/blog/+page.svelte -->
<script lang="ts">
export let data;
</script>
<ul>
{#each data.articles as a (a.id)}
<li>
<a href={`/blog/${a.slug}`}>{a.title}</a>
<p>{a.excerpt}</p>
</li>
{/each}
</ul>
Fetch numero quattro: Astro
Astro fa il fetch di default al momento del build, il che si adatta perfettamente a un blog ricco di contenuti:
---
// src/pages/blog/index.astro
const SITE_ID = import.meta.env.KAMAAN_SITE_ID;
const TOKEN = import.meta.env.KAMAAN_TOKEN;
const res = await fetch(
`https://api.kamaan.io/v1/sites/${SITE_ID}/articles?language=en&status=published`,
{ headers: { Authorization: `Bearer ${TOKEN}` } },
);
const articles = await res.json();
---
<ul>
{articles.map((a) => (
<li>
<a href={`/blog/${a.slug}`}>{a.title}</a>
<p>{a.excerpt}</p>
</li>
))}
</ul>
Se passate Astro in modalità SSR, lo stesso codice gira a ogni richiesta. Nessuna modifica al codice.
Fetch numero cinque: React puro (Vite)
Fetch lato client in una semplice app React. Utile quando il blog vive dentro una dashboard SaaS autenticata:
// src/pages/Blog.tsx
import { useEffect, useState } from "react";
const SITE_ID = import.meta.env.VITE_KAMAAN_SITE_ID;
const TOKEN = import.meta.env.VITE_KAMAAN_TOKEN;
export function Blog() {
const [articles, setArticles] = useState<any[]>([]);
useEffect(() => {
fetch(
`https://api.kamaan.io/v1/sites/${SITE_ID}/articles?language=en&status=published`,
{ headers: { Authorization: `Bearer ${TOKEN}` } },
)
.then((r) => r.json())
.then(setArticles);
}, []);
return (
<ul>
{articles.map((a) => (
<li key={a.id}>
<a href={`/blog/${a.slug}`}>{a.title}</a>
<p>{a.excerpt}</p>
</li>
))}
</ul>
);
}
Per un'app React lato client, esponete un token pubblico a sola lettura. Non spedite mai un token con permessi di scrittura al browser.
Ecco la stessa immagine come singola scheda di riferimento: un endpoint in alto, il path del file dove vive il fetch di ogni framework sotto.

Due scenari reali
Scenario uno: un fondatore solo con tre prodotti SaaS. Ogni prodotto ha il proprio sito marketing su uno stack diverso, scelto in momenti diversi. Il prodotto A è su Next.js, il prodotto B su Astro, il prodotto C su una dashboard React pura. Senza una API del blog portabile, il fondatore mantiene tre integrazioni CMS diverse, tre workflow di contenuto diversi e tre fatture diverse. Con un solo account Kamaan e tre siti dentro, lo stesso schema di fetch sopra gira su tutti e tre. I nuovi articoli redatti in Claude atterrano nel sito giusto tramite il MCP Server, e ogni frontend li raccoglie alla prossima rivalidazione. Tempo totale di integrazione sui tre frontend: sotto le tre ore.
Scenario due: una piccola agenzia con sette blog SaaS clienti. L'agenzia non vuole insegnare sette interfacce CMS a sette clienti. Gestiscono tutti e sette i blog da un'unica dashboard Kamaan, danno a ogni cliente un posto editor limitato al suo sito, e lasciano il loro team contenuti scrivere in batch su tutti e sette da una sola finestra ChatGPT. Ogni sito cliente usa il framework con cui l'agenzia l'ha costruito, recuperando la stessa forma JSON.
Dove si inserisce Kamaan
Kamaan è il centro di comando per fondatori multi-prodotto e agenzie che gestiscono molti blog SaaS: gestite ogni blog da un'unica dashboard, e conducete ogni operazione su tutti da Claude, ChatGPT, Cursor o qualsiasi client MCP. L'endpoint REST mostrato sopra ha la stessa forma su ogni sito del vostro account. Auto-Multilingual Delivery significa che le traduzioni appaiono automaticamente alla pubblicazione, restituite dallo stesso endpoint articles con language=de, language=fr e così via. Il campo parent_article_id collega ogni traduzione alla sua sorgente inglese, così il vostro livello di routing può risolvere le varianti di locale senza una seconda richiesta.
Il prezzo è di 19 dollari al mese, flat, siti illimitati, senza tariffe per sito, per space o per posto. Il primo mese è gratis, senza carta di credito per iniziare, cancellazione in qualsiasi momento. Un piano a vita è disponibile per team che preferiscono pagare una volta sola. I crediti di traduzione AI vengono consumati solo se è Kamaan a tradurre. Se incollate le vostre traduzioni da Claude o ChatGPT, il caricamento non costa nulla.
Il lato CMS della prima pubblicazione richiede circa 14 minuti dall'iscrizione al primo post in linea. L'integrazione lato sviluppatore, la parte che questo articolo copre, richiede onestamente 40-60 minuti per il primo cablaggio incluse variabili d'ambiente, rotta index, rotta dettaglio e sitemap. Dopo, ogni nuovo sito riutilizza lo stesso fetch.
FAQ
Cos'è una API del blog?
Una API del blog è un endpoint HTTP che restituisce articoli del blog come dati strutturati, di solito JSON. Il vostro codice frontend chiama l'endpoint, riceve gli articoli e li renderizza come preferite. Il CMS gestisce memorizzazione, modifica e pubblicazione. Il frontend gestisce la presentazione.
Ho bisogno di un SDK proprietario per usare una API del blog?
No. La funzione fetch nativa integrata in ogni runtime JavaScript moderno è sufficiente. Gli SDK possono aggiungere comodità (risposte tipizzate, logica di retry, trasformazioni di immagini) ma vi vincolano. Un endpoint REST che restituisce JSON puro funziona con qualsiasi framework, in qualsiasi anno, in qualsiasi versione.
La stessa API del blog può alimentare più frontend?
Sì. Questo è il punto del headless. Potete renderizzare gli stessi articoli su un sito marketing Next.js, un sito di doc Astro e una dashboard React contemporaneamente, tutti tirando da un unico endpoint. Al CMS non importa come viene renderizzato il contenuto.
Come gestisco le traduzioni da una API del blog?
Cercate un CMS che restituisca le traduzioni come oggetti articolo separati collegati alla sorgente tramite un campo parent. Kamaan usa parent_article_id. Per recuperare la versione tedesca, passate language=de sullo stesso endpoint articles. Evitate CMS che annidano le traduzioni dentro un singolo oggetto articolo, perché ciò costringe ogni frontend a fare il parsing della logica di locale.
Dovrei mettere in cache le risposte della API del blog?
Sì, in quasi ogni caso. Il contenuto di un blog marketing non cambia spesso. Per framework a export statico come Astro o Next.js con revalidate, il fetch avviene al build o su un intervallo lungo. Per framework SSR, una cache da 5 a 10 minuti è di solito sicura. Saltate la cache solo quando dovete far apparire subito le bozze di anteprima per gli editor loggati.
E per le bozze di anteprima?
Passate status=draft e aggiungete un header di auth o un token di anteprima che i vostri editor portino con sé. La maggior parte dei team spedisce una rotta /preview/[slug] separata che recupera contenuto bozza, dietro un gate di login.
Come renderizzo il markdown restituito dalla API?
Scegliete un parser markdown che si abbini al vostro runtime. Per React, react-markdown funziona. Per Vue, vue-markdown-render. Per Svelte, svelte-markdown. Per Astro, il componente integrato. Il CMS dovrebbe restituire markdown grezzo così ogni frontend può sanitizzarlo come preferisce.
In cosa differisce dallo scegliere Contentful o Sanity?
Contentful e Sanity espongono entrambi endpoint REST, quindi lo schema di fetch sopra funziona anche contro di loro. Le differenze stanno nel modello di prezzi e nella superficie operativa. Kamaan fattura un forfait di 19 dollari al mese per siti illimitati e vi dà orchestrazione AI tramite MCP così potete condurre ogni operazione di blog da Claude, ChatGPT o Cursor.
Da leggere anche su Kamaan
- Come aggiungere un blog al vostro SaaS copre la decisione architetturale prima di scrivere codice.
- Cos'è un CMS headless spiega la separazione memorizzazione-rendering che questo articolo dà per scontata.
- CMS headless per Next.js approfondisce le specificità Next.js: ISR, rivalidazione on-demand, domini immagine.
- Migliori CMS headless per startup confronta prezzi e adeguatezza operativa per team in fase iniziale.
Iniziare con Kamaan
Kamaan è il centro di comando per fondatori multi-prodotto e agenzie che gestiscono molti blog SaaS: gestite ogni blog da un'unica dashboard, e conducete ogni operazione su tutti da Claude, ChatGPT, Cursor o qualsiasi client MCP. Auto-Multilingual Delivery significa che una traduzione appare su ogni locale automaticamente alla pubblicazione. Multi-Site Management significa un account, una fattura, ogni blog che gestite. La REST API Delivery mostrata in questo articolo ha la stessa forma su ogni sito del vostro account.
Il prezzo è di 19 dollari al mese, flat, siti illimitati, senza tariffe per sito, per space o per posto. Il primo mese è gratis, senza carta di credito per iniziare, cancellazione in qualsiasi momento. Un piano a vita è disponibile se preferite pagare una volta sola. Provatelo sul vostro prossimo blog e tenetevi il codice di fetch che avete già scritto.

