Mentionwell

React + Vite / Create React App

Vite/CRA apps don't have a built-in server, so you need a tiny proxy to keep MENTIONWELL_API_KEY off the client. The most common pattern is a serverless function (Vercel, Netlify, Cloudflare).

1. Proxy endpoint

Pick whichever runtime fits.

Vercel Edge Function

// api/blog/[...path].ts
export default async function handler(req: Request) {
  const url = new URL(req.url);
  const target = `${process.env.MENTIONWELL_API_URL}/api/public/${process.env.MENTIONWELL_SITE_SLUG}/${url.pathname.split("/").slice(3).join("/")}${url.search}`;
  const upstream = await fetch(target, {
    headers: { Authorization: `Bearer ${process.env.MENTIONWELL_API_KEY}` }
  });
  return new Response(upstream.body, {
    status: upstream.status,
    headers: { "content-type": upstream.headers.get("content-type") ?? "application/json" }
  });
}

Cloudflare Worker

export default {
  async fetch(req: Request, env: { MENTIONWELL_API_URL: string; MENTIONWELL_SITE_SLUG: string; MENTIONWELL_API_KEY: string }) {
    const url = new URL(req.url);
    const target = `${env.MENTIONWELL_API_URL}/api/public/${env.MENTIONWELL_SITE_SLUG}/${url.pathname.replace(/^\/blog/, "posts")}`;
    const upstream = await fetch(target, {
      headers: { Authorization: `Bearer ${env.MENTIONWELL_API_KEY}` }
    });
    return new Response(upstream.body, upstream);
  }
};

2. Client fetch

// src/Blog.tsx
import { useEffect, useState } from "react";

export function Blog() {
  const [posts, setPosts] = useState<any[]>([]);
  useEffect(() => {
    fetch("/api/blog/posts")
      .then((r) => r.json())
      .then((data) => setPosts(data.posts ?? []));
  }, []);
  return (
    <ul>
      {posts.map((post) => <li key={post.slug}>{post.title}</li>)}
    </ul>
  );
}

3. Detail page

Match /blog/:slug in your router (React Router, TanStack Router) and fetch /api/blog/posts/{slug}. Render post.html via dangerouslySetInnerHTML.

If you really want to call the Mentionwell API directly from the browser, you can — the API supports CORS — but you'll need to embed the API key in the bundle, which makes it visible. Only do this on a deliberately public-info app.