Headless blog

JavaScript SDK

A tiny ES module with no dependencies. Load it from your server or copy it into your site.

Load it

Your server serves it at https://drive.example.com/sdk/stavo-blog.js. You can import it from there, or download the file and ship it with your site (it's one file).

js
import { createClient } from "https://drive.example.com/sdk/stavo-blog.js";

const blog = createClient({ url: "https://drive.example.com", blog: "weeknight-kitchen", key: "stc_YOUR_CONTENT_KEY" });

createClient({ url, blog, key, fetch })

  • url: your Stavo server.
  • blog: the blog's address name or id.
  • key: a Content API key.
  • fetch: optional, your own fetch (for tests, or runtimes with a special one).

Reading

js
const { posts, meta } = await blog.posts.list({ limit: 10, page: 1, tag: "pasta", include: "tags,authors" });
const post = await blog.posts.get("lemon-pasta");   // null when it doesn't exist
const about = await blog.pages.get("about");
const { tags } = await blog.tags.list();
const sam = await blog.authors.get("sam");
const settings = await blog.settings();

list(options) takes the same options as the API (page, limit, tag, author, featured, order, fields, include, formats) and answers the API's JSON. get(slugOrId) answers the item, or null on a 404 so your site can show its own "not found". Other errors throw a StavoError with status and code.

Drop-in list

No JavaScript of your own: a list of the latest posts, linking to /blog/<slug>.

html
<div data-stavo-posts data-url="https://drive.example.com" data-blog="weeknight-kitchen" data-key="stc_YOUR_CONTENT_KEY" data-limit="5" data-base="/blog"></div>
<script type="module" src="https://drive.example.com/sdk/stavo-blog.js?auto"></script>

Drop-in blog section with your own 404

mountBlog reads the address: on /blog it lists posts (with Newer and Older links), on /blog/<slug> it shows that post, and when the post doesn't exist it calls your notFound.

js
import { createClient, mountBlog } from "https://drive.example.com/sdk/stavo-blog.js";

const blog = createClient({ url: "https://drive.example.com", blog: "weeknight-kitchen", key: "stc_YOUR_CONTENT_KEY" });
mountBlog(blog, {
  root: document.querySelector("#blog"),
  base: "/blog",
  notFound: () => location.replace("/404.html"),
});

The markup it writes uses plain classes (stavo-posts, stavo-post-title, stavo-article, stavo-content) for your stylesheet. postListHtml(posts) and postHtml(post) are exported too if you want the markup without the router.