ResearchForge / Calculators
← back

Calculator API

Every ResearchForge calculator is also a JSON endpoint. Discover them, inspect their input schemas, and POST inputs to compute. The same pure function that runs on the React page runs on the server — you'll get identical results.

51
endpoints
51
compute modules
113
test cases

Endpoints

GET/api/calculators

Catalog every calculator with input schema and URLs.

Example
curl https://<your-host>/api/calculators
Response
{
  "count": 29,
  "calculators": [
    {
      "course_slug": "dynamics",
      "calc_slug": "stopping-distance",
      "title": "Stopping Distance",
      "topic": "stopping-distance",
      "test_status": "passing",
      "test_count": 2,
      "inputs": [ ... ],
      "compute_url": "/api/calculators/dynamics/stopping-distance/compute",
      "detail_url": "/api/calculators/dynamics/stopping-distance"
    },
    ...
  ]
}
GET/api/calculators/[course]/[calc]

Full metadata for one calculator — inputs, sample test cases, compute URL.

Example
curl https://<your-host>/api/calculators/dynamics/stopping-distance
Response
{
  "course_slug": "dynamics",
  "calc_slug": "stopping-distance",
  "title": "Stopping Distance",
  "topic": "stopping-distance",
  "test_status": "passing",
  "test_count": 2,
  "inputs": [
    { "name": "reaction_time", "label": "Reaction Time (s)", "type": "number", "default": 0.75 },
    { "name": "deceleration",  "label": "Deceleration (ft/s²)", "type": "number", "default": 2 },
    { "name": "initial_speed", "label": "Initial Speed (ft/s)", "type": "number", "default": 44 }
  ],
  "test_cases": [
    { "inputs": { "reaction_time": 0.75, "deceleration": 2, "initial_speed": 44 },
      "expected": 517.0, "tolerance": 1e-06 }
  ],
  "compute_url": "/api/calculators/dynamics/stopping-distance/compute"
}
POST/api/calculators/[course]/[calc]/compute

Run the calculator with user-supplied inputs. Returns { ok, value, formula? }.

Example
curl -X POST https://<your-host>/api/calculators/dynamics/stopping-distance/compute \
  -H "Content-Type: application/json" \
  -d '{"inputs":{"reaction_time":0.75,"deceleration":2,"initial_speed":44}}'
Response
{
  "ok": true,
  "value": 517,
  "formula": "$ d_{total} = d_{reaction} + d_{stopping} = v_{0} * t_{reaction} + \\frac{v_{0}^{2}}{2 * a} $"
}

Client examples

Same compute, multiple languages. Replace <your-host> with the URL the site is served from (e.g. localhost:3001).

JavaScript (fetch)
const r = await fetch("/api/calculators/dynamics/stopping-distance/compute", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    inputs: { reaction_time: 0.75, deceleration: 2, initial_speed: 44 },
  }),
});
const data = await r.json();
console.log(data.value);  // 517
Python (requests)
import requests

r = requests.post(
    "http://localhost:3001/api/calculators/dynamics/stopping-distance/compute",
    json={"inputs": {"reaction_time": 0.75, "deceleration": 2, "initial_speed": 44}},
)
print(r.json()["value"])  # 517
Python (httpx, async)
import httpx, asyncio

async def main():
    async with httpx.AsyncClient() as c:
        r = await c.post(
            "http://localhost:3001/api/calculators/dynamics/stopping-distance/compute",
            json={"inputs": {"reaction_time": 0.75, "deceleration": 2, "initial_speed": 44}},
        )
        print(r.json()["value"])

asyncio.run(main())
Shell (curl)
curl -sX POST http://localhost:3001/api/calculators/dynamics/stopping-distance/compute \
  -H "Content-Type: application/json" \
  -d '{"inputs":{"reaction_time":0.75,"deceleration":2,"initial_speed":44}}' \
  | jq .value

Try it on a live calculator

Pick any calculator below. Its input schema is pre-filled with the default values — click Call API to hit the endpoint from your browser and see the JSON response.

POST /api/calculators/calculus-cal-2/improper-integral-comparison/compute
Response
(click Call API)

Notes

  • Source of truth: each compute function lives atlib/calcs/_generated/<course>__<calc>.ts— auto-generated at build time from the same React page that renders the calculator UI. The API and the UI can never diverge.
  • Identifiers: use the course_slug and calc_slug from the catalog — those never change even if the human-facing title does.
  • Input shape: POST body is { inputs: { <name>: <value>, ... } } where each name matches the calculator's declared input schema. Missing fields fall back to the calc's own defaults.
  • Output shape: success returns { ok: true, value, formula?, unit? }; failure returns { ok: false, error } with a 4xx/5xx status.
  • Safety: compute functions are pure — no filesystem, database, or network access. They don't mutate state.