Skip to content

chartforge/chartforge-api

Repository files navigation

ChartForge API

A stateless HTTP API that turns chart and diagram specs into PNG, SVG, or PDF. One endpoint. Four renderers (Chart.js, Mermaid, Graphviz, Vega-Lite). Any chart.

Local dev (macOS)

Node 20 is required (canvas@3 has no prebuilt binaries past Node 20 ABI). Use fnm to get the right version automatically via the committed .node-version file.

# one-time: install Node 20 and system deps for the canvas native module
brew install fnm pkg-config pixman cairo pango librsvg giflib
fnm install 20
eval "$(fnm env --use-on-cd)"   # add to ~/.zshrc for auto-switch on cd

# project setup
cp .env.example .env   # fill in DATABASE_URL (Neon)
pnpm install
pnpm migrate           # runs migrations/0001_init.sql
pnpm seed you@example.com pro   # creates a user + prints a cf_test_ key (shown once)
pnpm dev               # Fastify on :8080

Then curl -H "Authorization: Bearer <the key>" http://127.0.0.1:8080/v1/me.

Seed a test API key

-- 1) Create a user
INSERT INTO users (id, email, plan) VALUES (gen_random_uuid(), 'you@example.com', 'pro');

-- 2) Generate a token outside psql: node -e "console.log('cf_test_' + require('crypto').randomBytes(24).toString('hex'))"
-- 3) SHA-256 hash it: echo -n 'cf_test_...' | shasum -a 256
-- 4) Insert it:
INSERT INTO api_keys (user_id, key_hash, prefix, name)
VALUES ((SELECT id FROM users WHERE email='you@example.com'), '<sha256>', 'cf_test', 'local-dev');

curl examples

# Chart.js bar chart -> PNG
curl -X POST https://api.chartforge.dev/v1/render/chart \
  -H "Authorization: Bearer cf_live_yourkey" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "bar",
    "data": {
      "labels": ["Jan","Feb","Mar"],
      "datasets": [{"label":"MRR","data":[1200,1900,2400]}]
    },
    "width": 800, "height": 500, "format": "png"
  }' --output chart.png

# Mermaid via GET (drop straight into Markdown)
curl "https://api.chartforge.dev/v1/render/mermaid?diagram=graph%20TD%3B%20A--%3EB&format=png&key=cf_live_yourkey" \
  --output flow.png

# Quota state
curl https://api.chartforge.dev/v1/me -H "Authorization: Bearer cf_live_yourkey"

Architecture notes

  • Cache: SHA-256 of {renderer, canonical_input, format, w, h} → R2. All responses are deterministic, so the cache hit ratio climbs fast. Cache hits do NOT count against the monthly quota (enforced in src/routes/render.ts).
  • Auth: API key SHA-256 hash stored in Postgres; raw key never persisted. Keys use the cf_live_ / cf_test_ prefix pattern.
  • Rate limit: in-memory token bucket keyed on API key ID. Swap for Redis when scaling past one machine.
  • Renderers: Chart.js is MVP-complete. Mermaid, Graphviz, and Vega are stubbed with install-and-implement instructions inline in each renderer file.

Pricing tiers (enforced in src/lib/quota.ts)

Tier Price Renders/mo Burst
Free $0 2,500 5 req/s
Hobby $19 25,000 30 req/s
Pro $79 250,000 100 req/s
Scale $299 2,000,000 500 req/s

Cached renders don't count against quota on any tier.

Tests

pnpm test

Deploy to Fly

fly launch --no-deploy --copy-config
fly secrets set DATABASE_URL=... R2_ACCOUNT_ID=... R2_ACCESS_KEY_ID=... R2_SECRET_ACCESS_KEY=... R2_BUCKET=chartforge-cache STRIPE_SECRET_KEY=... STRIPE_WEBHOOK_SECRET=...
fly deploy

First build is slow (~5 min) due to node-canvas native compilation. Subsequent builds reuse the cached deps layer.

Roadmap

  1. Week 1 — Chart.js renderer live, auth, quota, Stripe, Fly deploy
  2. Week 2 — Mermaid (Playwright + warm Chromium), Graphviz (wasm), Vega (native), playground UI
  3. Week 3 — MCP server, LangChain/LlamaIndex/CrewAI tools, Node/Python/Go SDKs
  4. Week 4 — Public launch: Product Hunt Wednesday, Show HN the following Tuesday

About

One API for Chart.js, Mermaid, Graphviz, and Vega-Lite — stateless HTTP chart rendering

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors