Jampot.dev

Creating a prototype with Svelte

January 31, 2021

In the last part I built out a simple backend that gets the release dates for a film, using the TMDb (The Movie Database) API. Now I want to build out a minimum viable frontend, as quickly as possible.

I’ve played around with Vue in the past, but I’ve heard word on the steet about a new way of building frontends, that compiles straight to native javascript: Svelte.

I’ll explain the syntax as I go, so let’s get started.

I decided that the simplest useful form would be a search input that has some fuzzy properties, that I can then relay to my backend service and get the film release dates.

First things first, let’s make the input:

<script>
  let value = '';
</script>

<div class="app">
  <h1>
    Movie release dates
  </h1>

  <div>
    <input type='text' bind:value={value} />
  </div>
</div>

Pretty self explanatory, I’ve bound the value of the input box to the value variable in the JS, so as the user types into the input box, that value will continually update.

Now it’s time to hook it up to the backend and display what we’re searching.

So let’s make a function that queries the backend:

  const getMoviesForSearch = async searchStr => {
    if (searchStr == '') return [];

    const response = await fetch(`http://localhost:8081/movies/${searchStr}`);
    return await response.json();
  }

Then we can loop through it and display all of the results with a bit of Svelte await-in-the-html magic:

    {#await getMoviesForSearch(value) then movies }
      {#each movies as movie (movie.id) }
          <div class="movieInfo">
            <div class="movieTitle">{ @html movie.htmlTitle }</div>
            <div class="movieReleaseDate">{ movie.releaseDate }</div>
          </div>
        </div>
      {/each}
    {/await}

Again, as seems to be the way with Svelte, what it does makes sense at first glance. Get all of the films for a value (value being the same one referenced in the <input> tag), then for each of them, new up a div with its info. Magic!

That solves the main concern of searching for and getting the release dates, but the search isn’t great. Lots of results aren’t what you would expect, as we’re relying on the TMDb API to do this for use, which it isn’t really built for. As a stop gap, let’s use a fuzzy library to give us some better matching.

Lucky for us there’s a popular js library fuzzysort, that also lets us change the scoring function (this will be handy later). TMDb also has a popularity score for each film, so combining that with the fuzzy score should help make the results close to what we’d expect.

So let’s import it

  import fuzzysort from 'fuzzysort';

Set up some of its options (unfortunately scorefn can only be updated when using a list of keys, hence the array access):

  const fuzzysortOptions = {
    keys: ['title'],
    limit: 10,
    allowTypo: true,
    scoreFn: a => a[0] ? a[0].score + a.obj.popularity : null
  };

Then instead of passing films to the #each directly, use the result of this function:

  const getFilteredMovieElements = movies => {
    var rankedMovies = fuzzysort.go(value, movies, fuzzysortOptions)
    for (const rankedMovie of rankedMovies) {
      rankedMovie.obj.htmlTitle = fuzzysort.highlight(rankedMovie[0]);

      var releaseDate = moment(rankedMovie.obj.releaseDate);
      rankedMovie.obj.releaseDate = releaseDate.format('MMMM Do YYYY');
    }
    return rankedMovies.map(x => x.obj);
  };

It’s not super obvious what’s happening on first glance, but the general gist is that fuzzysort.go does the fuzzy ranking, and fuzzysort.highlight highlights (in html) the letters the fuzzy logic matched. This lets us display the letters being matched in the frontend, which looks nice!

Put all of this together and we have the end result: the movie release finder in all its glory

I’m pretty happy with how painless it was to build this, and am definitely interested in using Svelte more. Compiling to native JS is great and this feels like the future, but time will tell where frontend technologies go.

On the end result, it’s pretty good, better than I’d have expected with the shackles of another api, but isn’t the best experience. Maybe the next post will be populating my own database of movie information, and see what I can come up with!