<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hanné B</title>
    <description>The latest articles on DEV Community by Hanné B (@hannedev).</description>
    <link>https://dev.to/hannedev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4205592%2F3618108b-5a77-45df-b71a-2f12dd09bca9.jpg</url>
      <title>DEV Community: Hanné B</title>
      <link>https://dev.to/hannedev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hannedev"/>
    <language>en</language>
    <item>
      <title>Building a Music Theory API (and learning JavaScript along the way)</title>
      <dc:creator>Hanné B</dc:creator>
      <pubDate>Wed, 28 Oct 2026 00:34:01 +0000</pubDate>
      <link>https://dev.to/hannedev/building-a-music-theory-api-and-learning-javascript-along-the-way-2i3</link>
      <guid>https://dev.to/hannedev/building-a-music-theory-api-and-learning-javascript-along-the-way-2i3</guid>
      <description>&lt;h2&gt;
  
  
  Building a Music Theory API (and learning JavaScript along the way)
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So I built one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API
&lt;/h2&gt;

&lt;p&gt;The Music Theory Explorer is a REST API built with Python and Flask that encodes core music theory concepts as retrievable endpoints:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scale spellings across major, natural minor, and harmonic minor&lt;/li&gt;
&lt;li&gt;Interval identification and inversion&lt;/li&gt;
&lt;li&gt;Triad and seventh chord spellings with inversions&lt;/li&gt;
&lt;li&gt;Diatonic chord sets with Roman numerals&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The data reflects the modern equal temperament tradition and what’s generally known as the common practice period.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I needed a frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning JavaScript reactively
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Some things that clicked quickly:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const&lt;/code&gt; is just a named box&lt;/p&gt;

&lt;p&gt;js&lt;br&gt;
&lt;code&gt;const API = '/api';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A constant is a label for a value that won’t change.&lt;/p&gt;

&lt;p&gt;Template literals are Python f-strings&lt;/p&gt;

&lt;p&gt;js&lt;br&gt;
&lt;code&gt;const url =&lt;/code&gt;${API}/scales/${tonic}/${mode}&lt;code&gt;;&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;data.field&lt;/code&gt; is dictionary lookup&lt;/p&gt;

&lt;p&gt;js&lt;br&gt;
&lt;code&gt;const notes = data.scale;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When your API returns JSON, JavaScript reads it as an object. &lt;code&gt;data.scale&lt;/code&gt; is the same idea as &lt;code&gt;data["scale"]&lt;/code&gt; in Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that taught me the most
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;C major was showing as: C D E F G A Bb&lt;/p&gt;

&lt;p&gt;The fix was luckily just one word: removing the conversion function call, and displaying the note directly. &lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like now
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Deploying to a platform like Render, so musicians can use it without cloning a repo&lt;/li&gt;
&lt;li&gt;A chord progression analyser (&lt;code&gt;/key/{tonic}/{mode}/analyze&lt;/code&gt;) that returns Roman numeral analysis&lt;/li&gt;
&lt;li&gt;Historical tuning system support in a future version&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>frontend</category>
      <category>musictheory</category>
    </item>
    <item>
      <title>Why Figured Bass Notation did not Make it into v1 of my Music Theory API</title>
      <dc:creator>Hanné B</dc:creator>
      <pubDate>Tue, 27 Oct 2026 00:27:55 +0000</pubDate>
      <link>https://dev.to/hannedev/why-figured-bass-notation-did-not-make-it-into-v1-of-my-music-theory-api-4ana</link>
      <guid>https://dev.to/hannedev/why-figured-bass-notation-did-not-make-it-into-v1-of-my-music-theory-api-4ana</guid>
      <description>&lt;p&gt;My initial plan when building the Music Theory API v1 was to include figured bass notation as a field in the chord endpoints. &lt;/p&gt;

&lt;p&gt;The idea was straightforward: return the standard numeric figures alongside the chord notes so that the response would be useful for anyone working with Baroque-era notation or voice leading analysis.&lt;/p&gt;

&lt;p&gt;The initial json implementation looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "root": "C",&lt;br&gt;
  "quality": "minor",&lt;br&gt;
  "name": "C minor",&lt;br&gt;
  "inversion": "first inversion",&lt;br&gt;
  "bass": "Eb",&lt;br&gt;
  "notes": ["Eb", "G", "C"],&lt;br&gt;
  "basso_continuo": "6/3"&lt;br&gt;
}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;For root position, first inversion, and second inversion triads, the figures map cleanly to inversion number: root position is 5/3, first inversion is 6/3, second inversion is 6/4. For seventh chords the same logic applies: root position is 7/5/3, first inversion is 6/5/3, second inversion is 6/4/3, third inversion is 6/4/2. This works until you try a diminished triad in root position.&lt;/p&gt;

&lt;p&gt;A diminished triad has a diminished fifth above the bass, not a perfect fifth. Returning 5/3 for a diminished triad in root position is technically incorrect: the five needs to be altered by accidental. In standard figured bass notation, a diminished fifth is written as b5, giving &lt;code&gt;b5/3&lt;/code&gt;for a diminished triad in root position.&lt;/p&gt;

&lt;p&gt;The figures need to carry interval quality information, not just interval numbers. That is solvable if I can extract the quality from the interval name and prepend the appropriate accidental symbol, but this is where the real problem appears.&lt;/p&gt;

&lt;p&gt;In basso continuo practice, figures are always relative to the key signature. A major third in C major is written as &lt;code&gt;3&lt;/code&gt;: the key signature already implies the major third, so no extra accidental is needed. The same major third in C minor requires a sharp, i.e. &lt;code&gt;#3&lt;/code&gt;, because the key signature has an Eb and the performer needs to be told to raise it. The same interval, the same note, different figures depending on context.&lt;/p&gt;

&lt;p&gt;This means that correct figured bass notation cannot be derived from the chord spelling alone.The key must be known. Right now the API’s chord endpoints take a root and a quality — they have no key context. Adding a key parameter to the chord endpoints would conflate two separate concerns: what a chord is in isolation versus what function it serves in a key.&lt;/p&gt;

&lt;p&gt;The right place for figured bass notation is therefore not the chord endpoint but a future key-aware endpoint; something that takes a tonic, a mode, and a chord, and returns the Roman numeral analysis alongside correct context-dependent figures. That endpoint is planned but not yet built.&lt;/p&gt;

&lt;p&gt;For now, the &lt;code&gt;basso_continuo&lt;/code&gt; field has been removed from the chord response entirely. For the moment a missing field is preferable to a field that returns correct-looking but context-independent figures that would be wrong in any key with accidentals in the signature.&lt;/p&gt;

</description>
      <category>musictheory</category>
      <category>python</category>
      <category>flask</category>
      <category>api</category>
    </item>
    <item>
      <title>Why F# Breaks OpenAPI rendering: Note Names, URL Encoding, and the Clash Between Music Notation and pre-existing Web Standards</title>
      <dc:creator>Hanné B</dc:creator>
      <pubDate>Sat, 24 Oct 2026 23:52:29 +0000</pubDate>
      <link>https://dev.to/hannedev/why-f-breaks-openapi-rendering-note-names-url-encoding-and-the-clash-between-music-notation-and-3573</link>
      <guid>https://dev.to/hannedev/why-f-breaks-openapi-rendering-note-names-url-encoding-and-the-clash-between-music-notation-and-3573</guid>
      <description>&lt;p&gt;I'm building a music theory API. I typed F# as root note into the "tonic" interface, which OpenAPI translated into a URL and I got a subsequent 404. Everything broke. Here's what happened and how I created a work-around.&lt;/p&gt;

&lt;h2&gt;
  
  
  What # means to a URL
&lt;/h2&gt;

&lt;p&gt;The # character is reserved in URLs to signal a fragment identifier. Everything after the # character is interpreted by the browser as an anchor on the page, not part of the path. So something like &lt;code&gt;/scales/F#/major&lt;/code&gt; is parsed as &lt;code&gt;/scales/F with fragment major&lt;/code&gt;. The server never even sees the # and we get a 404 error response right away when trying to render in OpenAPI.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the # symbol means to a musician
&lt;/h2&gt;

&lt;p&gt;The sharp symbol in music applies to a note name to raise it by a semitone. In the context of naming scales, as for the API, the root note is the name given to the scale and so F# must be the root note for a scale beginning on the note F-sharp. This becomes a matching issue in pre-programmed interfaces like OpenAPI interfaces, which weren't designed for music first formats initially but the two now have to "talk to" each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solutions People have Reached for
&lt;/h2&gt;

&lt;p&gt;URL encoding (F%23), query parameters, string substitution (Fs) are all potential solutions to the issue. Each one works technically, but breaks something musically or semantically, because it's clumsy to annotate to non-technical users, and string substitution like Fs doesn't make sense musically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The German Naming Solution
&lt;/h2&gt;

&lt;p&gt;German music notation uses the suffix "is" for sharps and "es" for flats i.e. Fis, Cis, Es, but notably B for Bb. Despite the workaround, no special characters are needed. Clean URLs. (Also, it's not a hack; it's a centuries-old naming convention used in some of the greatest musical traditions.) &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>musictheory</category>
      <category>openapi</category>
      <category>coding</category>
    </item>
  </channel>
</rss>
