Server technologies

Node.js

Serve published article JSON from an Express backend using the built-in fetch API.

PeopleTide Content · HTTP integration guides

1. Prepare your project.

Use Node 22+ and an ES module project (package.json type: module). Install express, save the shared helper as delivery.js, set the three CONTENT_* environment variables, and save the example as server.mjs.

2. Add the shared delivery helper.

Copy this helper into the path named above. It follows a single published release without exposing authoring credentials.

JavaScript
// delivery.js — no SDK or API key required. Node 22+ or a modern browser.
export async function getArticle({ origin, organization, site, slug }) {
  const base = new URL(origin);
  if (base.protocol !== 'https:' && !['localhost', '127.0.0.1'].includes(base.hostname)) {
    throw new Error('Use an HTTPS Content origin');
  }
  if (![organization, site].every(id => /^[a-f0-9-]{36}$/.test(id))) {
    throw new Error('Set your organization and site UUIDs');
  }
  const prefix = '/delivery/v1/' + organization + '/' + site + '/';
  async function read(path) {
    const url = new URL(path, base);
    if (url.origin !== base.origin || !url.pathname.startsWith(prefix) || url.search || url.hash) {
      throw new Error('Unexpected delivery URL');
    }
    const response = await fetch(url, {
      credentials: 'omit', cache: 'no-store', redirect: 'error',
      signal: AbortSignal.timeout(8000),
    });
    if (!response.ok) throw new Error('Content delivery returned ' + response.status);
    return response.json();
  }
  const current = await read(prefix + 'current.json');
  const manifest = await read(current.url);
  const entry = manifest.entries.find(item => item.type === 'article' && item.slug === slug);
  if (!entry) return null;
  const document = await read(entry.url);
  return { releaseId: current.releaseId, document };
}

Connect and render.

Publish an article of type article with slug welcome and a body field before running the example. Split the labelled files into the paths shown.

JavaScript
// server.mjs — npm install express; node server.mjs
import express from 'express';
import { getArticle } from './delivery.js';
const app = express();
app.get('/articles/:slug', async (req, res) => {
  try {
    const result = await getArticle({
      origin: process.env.CONTENT_ORIGIN || 'https://content.peopletide.com',
      organization: process.env.CONTENT_ORGANIZATION_ID,
      site: process.env.CONTENT_SITE_ID, slug: req.params.slug,
    });
    if (!result) return res.status(404).json({ error: 'Article not published' });
    res.json(result); // Render with your template engine, or return JSON.
  } catch (error) {
    console.error('Content retrieval failed', error.message);
    res.status(503).json({ error: 'Content temporarily unavailable' });
  }
});
app.listen(3000);

Choose when content refreshes.

This example fetches on every request and returns JSON. If you add a cache, cap discovery freshness at 30 seconds and cache immutable content by its URL. Render HTML using a template engine that escapes text.

Verify success and failure.

Run node --env-file=.env server.mjs and request /articles/welcome. Verify 200 JSON, a 404 for an unknown slug, and a 503 when delivery is unavailable. Inspect the returned releaseId.