Skip to content

Repository files navigation

ntnu-api

npm

TypeScript client for NTNU course data. Wraps the three public, no-auth data sources for course information at the Norwegian University of Science and Technology behind one typed interface. Fetch-based with zero runtime dependencies — works in Node ≥ 20, Cloudflare Workers, browsers, and any other fetch-capable runtime.

Namespace Data Backing source
client.courses catalog search, per-course schedules & weekly timetables ntnu.no course-page JSON (Liferay)
client.courses.details exam info (date, time, duration, aid code, rooms), fact box, descriptions, study programs ntnu.no course-page HTML (scraped — no JSON upstream)
client.grades grade distributions per course/year/semester HK-dir DBH statistics API
client.semesters term ids (26h/26v), teaching weeks, exam periods NTNU's TP timetable system

See docs/api-research.md for the full survey of NTNU data sources (including the dead and auth-gated ones) and the exact upstream request shapes.

Usage

npm install ntnu-api
import { NTNUClient } from "ntnu-api";

const client = new NTNUClient();

// Server-side course search (one 500-course page)
const page = await client.courses.search(2026, "objektorientert");
for (const hit of page.courses.slice(0, 3)) {
  console.log(hit.courseCode, hit.courseName);
}

// Full catalog iteration (dedups the upstream's duplicate entries)
for await (const resultPage of client.courses.searchAll(2026)) {
  // ...
}

// Dated teaching activities and the summarized weekly grid
const activities = await client.courses.schedules("TDT4100", 2026);
const grid = await client.courses.timetable("TDT4100", 2026);

// Everything else on the course page (HTML-only upstream, scraped):
// exams with start time/duration/hjelpemiddelkode/rooms, credits, level,
// descriptions, and the study programs the teaching is planned for —
// details.studyPrograms maps the studyProgramKeys on schedule/timetable
// entries to program names.
const details = await client.courses.details("TDT4100", 2026);
for (const exam of details?.exams ?? []) {
  console.log(exam.occasion, exam.date, exam.time, exam.duration, exam.aidCode);
}

// Grade distribution (accepts bare or DBH-versioned codes)
for (const row of await client.grades.distribution("TDT4100", { years: [2023] })) {
  console.log(row.year, row.semesterName, row.grade, row.total);
}

// Terms as known by NTNU's timetable system
const current = await client.semesters.current();

All errors derive from NTNUAPIError (with NotFoundError, RateLimitError, APITimeoutError, ... subclasses). Transient failures (429, 502–504, connection errors) are retried with exponential backoff, honoring Retry-After. Upstream payloads are parsed into plain typed objects; helpers like bestName() (trilingual name fallback) and weekNumbers() (ISO-week range expansion) are exported alongside them.

A word of caution: the ntnu.no endpoints are NTNU's own internal AJAX surface, not a documented API — treat results accordingly and be polite (the client ships a descriptive User-Agent by default).

MCP server

The ntnu-mcp sibling repo hosts a remote MCP server built on this package (Cloudflare Worker), exposing the client as ten LLM-shaped tools — connect Claude or ChatGPT to https://ntnu-mcp.martinsundal.no/mcp. Upstream fixes and new data sources land here; the MCP repo only shapes typed data for LLMs.

Stack

  • TypeScript (strict), ESM-only, zero runtime dependencies
  • vitest — tests over captured live fixtures
  • Biome — linting + formatting
  • mise — pins Node and exposes task shortcuts
  • Dev Container — reproducible environment

Development

mise install     # pinned Node
npm install
Task Command
mise run test vitest run
mise run lint biome check .
mise run fmt biome check --write .
mise run typecheck tsc --noEmit
mise run build tsc -p tsconfig.build.jsondist/
mise run check lint + typecheck + test

The default test run is fully mocked (injected fetch) against real captured payloads in tests/fixtures/. To also verify against the live endpoints (drift check):

NTNU_API_LIVE=1 npm test

Releases are tag-driven: npm version <patch|minor|major> && git push --follow-tags. The release workflow then verifies the tag, runs the full check suite, publishes to npm (trusted publishing with provenance — no token secrets), and creates the GitHub Release with generated notes. The prepare script builds dist/, so github:MartinSA04/ntnu-api installs also work between releases.

History

This library began as an async Python client (httpx + pydantic, with a CLI and a stdio MCP server); it was ported 1:1 to TypeScript so one codebase serves Node, Workers, and browsers, per docs/ts-migration-spec.md. The final Python state is preserved at the python-final tag.

Roadmap

  • MCP server exposing the client as tools → ntnu-mcp
  • Expose the remaining catalog search facets (campus, level, faculty/institute)
  • Course detail scraping (exams, description, credits, prerequisites — HTML-only upstream) → courses.details()
  • TP emner.php semester catalog (English names, campus ids — see docs/api-research.md)
  • TP iCal export as a secondary timetable source once semesters publish

About

TypeScript client for NTNU course data (catalog search, schedules, timetables, grade statistics, semesters)

Topics

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages