A while back, I wrote a post that outlined a simple approach to finding words that rhyme using the CMU pronunciation dictionary. I recently built out a web-based version of the same idea as a full stack web app, using a number of modern web technologies. In this post, I’ll briefly explain how the various pieces fit together. My primary goal for this project was to dive deeper into a few bits of web tech that I’d been dabbling with, including Nest, Typescript, Docker, and modern React.

The live link of the app is currently available here. And here’s a screenshot for reference, in case I eventually take the demo down:

Rhyming word search

To implement the rhyme search itself, I started with a straight-forward conversion of the C++ implementation that I shared before. One interesting twist was that I realized I didn’t need to write any custom JS/TS loader code, nor use a database of any kind. Instead, I simply modified the C++ code to export all of the pre-loaded structures and dictionary information in JSON format. By loading the JSON directly (using Node/CommonJS require or Typescript’s resolveJsonModule), I could access the full, deeply nested hierarchy data in memory with very little work. Without all the loading fluff, the actual search was somewhere only around 100 lines of code.

The Backend

For past NodeJS backends, I typically worked directly with Express. Despite being overkill for a project this small, I decided to give Nest a try. It has a much steeper learning curve than some of the lighter frameworks out there, but seems generally well designed and quite capable. I particularly like the heavy use of Typescript– which I’ve been shifting more towards– as well as TypeORM integration for database work. It reminds me of the more enjoyable parts of .NET I’ve worked with in the past. Though I didn’t end up using much from Nest on this project (there’s only a single route), I learned enough to want to use it for larger, future projects. And it was at least useful for type validation of the input query parameters.

The Frontend

In terms of frontend, most of my recent work had been with Vue 2 (or Blazor for .NET.) For this project, I decided to take a fresh look at “modern React” to build out the UI. In doing so, I came to really appreciate the flexibility of functional component design. The UI for the app is pretty simple (a handful of components using Material-UI for the controls and themes), but it was the perfect project size to jump back in to React.

Deploying the App

For deployment purposes, the backend is a listening Node app, with nginx as a reverse proxy. The frontend is a collection of static content that’s served up by nginx. My intention was to work out a system that I could tie into my local CI/CD workflow (recently switched to Gitlab from Jenkins) for testing and auto-deploying to AWS. I ended up using Docker-compose. The script builds the required node/nginx images, pushes them to AWS ECR, and deploys to EC2 via the AWS and ECS command line tools.

While almost everything on this project was a bit overkill, it was a fun exercise to actually go through and tie all of the pieces together from top to bottom. If this were a “real” project, I’d probably add a few more things, like redis for caching. There were several bits, particularly on the automated Docker to AWS deployment side, where I’d read enough documentation to think I knew how things would work, but hadn’t actually tested them out myself. As expected, there were plenty of annoying configuration quirks and details to sort out along the way, but it was nice to see everything finally working together.