DEV Community

Hanné B
Hanné B

Posted on

Building a Music Theory API (and learning JavaScript along the way)

Building a Music Theory API (and learning JavaScript along the way)

Back when I was a grad student, I’ve always wanted a tool that could quickly spell out complex chords. In advanced music theory courses, verifying a chord spelling meant physically stacking thirds and writing them out on paper — a process that gets tedious fast when you’re working with augmented major sevenths in Ab harmonic minor at 11pm.

So I built one.

The API

The Music Theory Explorer is a REST API built with Python and Flask that encodes core music theory concepts as retrievable endpoints:

  1. Scale spellings across major, natural minor, and harmonic minor
  2. Interval identification and inversion
  3. Triad and seventh chord spellings with inversions
  4. Diatonic chord sets with Roman numerals

The data reflects the modern equal temperament tradition and what’s generally known as the common practice period.

The backend felt natural as I had built apps in Python/Flask before. Python’s readable syntax maps pretty well onto music theory logic; e.g. a scale is just a dictionary lookup, a chord is a list of notes derived from that scale.

The problem

When the API was complete, I realised something: music majors with no programming background can’t explore a REST API. Showing a fellow musician a JSON response and expecting them to find it useful is like handing someone a car engine and asking them to go for a drive.

I needed a frontend.

Learning JavaScript reactively

Here’s the honest part: I didn’t know JavaScript until now. I’d worked with Python and had a plan for the UI, but the actual JS was new territory.

Rather than sitting through tutorials, I wrote the frontend code with Claude and then walked through every change myself — one bug at a time. The approach was simple: make a change, understand why, move on. No change went in without me knowing what it did.

Some things that clicked quickly:

const is just a named box

js
const API = '/api';

A constant is a label for a value that won’t change.

Template literals are Python f-strings

js
const url =${API}/scales/${tonic}/${mode};

The backticks and ${} syntax does exactly what Python’s f-strings do; paste a value into a string. Once I saw that parallel it made sense.

data.field is dictionary lookup

js
const notes = data.scale;

When your API returns JSON, JavaScript reads it as an object. data.scale is the same idea as data["scale"] in Python.

The bug that taught me the most

The most instructive moment was a note conversion bug. My Flask API internally uses German notation (H for B natural, B for Bb -- see my first Blog Post for why!) but converts everything to English before responding. My JavaScript was then running those already-converted notes through a second German→English conversion — turning B into Bb, since Claude had given the initial template without looking at my existing code.

C major was showing as: C D E F G A Bb

The fix was luckily just one word: removing the conversion function call, and displaying the note directly.

What it looks like now

The finished frontend has four sections: Scales, Intervals, Chords, and Diatonic Chords. Each call the relevant API endpoint and display the results in a musician-friendly way. No JSON visible anywhere. Roman numerals, note spellings, interval names all presented cleanly for a non-technical musician.

The API URL is shown at the bottom of each result, though, for technically curious users who want to peek under the hood.

What’s next

  1. Deploying to a platform like Render, so musicians can use it without cloning a repo
  2. A chord progression analyser (/key/{tonic}/{mode}/analyze) that returns Roman numeral analysis
  3. Historical tuning system support in a future version

Top comments (0)