Building Mapzen Search’s product demo

Hello Mapzen newsletter readers! An old URL snuck in – here is that Guardian article. Sorry about that! (But this post is pretty good too.)

In the five months since we launched the production service of Mapzen Search, we’ve talked to many of our users and learned quite a lot about how people use it. So, with new feedback in mind, it was time to update our website with a brand-new demo that shows off what it can do. You can take a look for yourself on the Mapzen Search project page, or better yet, just keep your eyeballs on this blog post and I’ll go ahead and embed that for you.

This looks better on the project page. Go there now! ➹

We had two primary goals in mind:

  1. Keep it simple. It should tease the service, not be a full-fledged search application.
  2. Show off the API. It should demonstrate which service endpoints are active and what data they return.

It turns out that finding that proper balance between these two goals is much harder than you’d think once combined into one project. With the Mapzen Search Leaflet geocoder plugin in our toolkit, we could easily build a prototype that hits both goals in broad strokes in just a couple of days. But finessing the interface took about four times as long (as Joel Spolsky says of craftsmanship, “fixing a 1% defect takes 500% effort”—and if you look too closely, you still might find the edge cases we haven’t worked out yet).

The self-guided tour

Early on, we decided to resist the urge to create a “guided tour” experience, which would have the effect of preventing visitors from making esoteric search queries that might not return correct results from existing open data sources. The reality is that the data is in the best shape it’s ever been, and we’re constantly improving it. It’s important to show that evolution as time goes on, so the search box allows you to explore whatever location you’d like.

But we didn’t want people to sit around thinking of something to search for, so we put a prompt underneath the search box. Many people already type in their home address or the town they grew up in, because it’s a familiar setting and easy to gauge against the accuracy of the geocoder. But in case you’re struggling to think of an address, we’ve provided an example you can use (it’s the address of Mapzen headquarters in New York City). Click on it, and it simulates typing for you.

As you type (or, if you prefer robots to do all your work, as JavaScript simulates your keystrokes), we send each new input to the /autocomplete endpoint of Mapzen Search, providing real-time, predictive feedback about the query you’re trying to make. At any point, you can press the Enter or Return key to send a query to the /search endpoint, for the set of results that match your query.

Confused about the difference? Don’t worry, you’re not the only one! One way to illustrate the difference between the two endpoints is this: imagine that you’re typing the query “yolo.” When you’re sending that query to /autocomplete, you might not be done typing yet, so the first four results from Mapzen Search might be:

  • Yolöten, Mary, Turkmenistan
  • Yolombó, Antioquia, Colombia
  • Yolo County, CA
  • Yolonan, Chamula, Mexico

But maybe you are trying to search for “yolo”, as in Yolo County, California. So results from /search would include:

  • Yolo, Yolo County, CA
  • Yolo County, CA
  • La Puerta del Yolo, Cuautepec de Hinojosa, Mexico
  • Yolo, Mopti, Mali

Here’s another way to think about it: suppose you’re typing, and so far you have typed “Lond”. Chances are, you really mean London, England, and it’s less likely that you meant Lond, Pakistan, so /autocomplete predicts the most likely anticipated results and surfaces those for you. (And if you really did want Lond, Pakistan, /search has your back.)

Nuts and bolts

We wanted to make it really clear what’s actually happening behind the scenes when our demo makes a request and shows the raw data that gets sent back. So, for every request, we show you exactly the API endpoint our demo is querying, for instance:

https://search.mapzen.com/v1/search?text=San%20Diego

(We actually mask the API key, which is otherwise required for every request.)

But, because we’re just showing a basic use, we aren’t making any queries that include the adjustments that you might normally want in a full-fledged application like narrowing search results to your country or filtering by data type. Still, the results you get back will always be in the same format. Glancing through the returned JSON object, you can very quickly understand how you might craft your application to use the data that we serve.

Using the Leaflet geocoder plugin

As I’ve mentioned earlier, using our own homegrown Leaflet geocoder plugin allowed the team to get up and running with a prototype demo very quickly. In the process, we were even able to squash a few bugs and include support for the /place endpoint, which led to our most recent release of the plugin.

But we’ve certainly pushed the limits of what it could do for us. There’s a lot of custom UI that’s required, and the plugin was never designed to support this amount of functionality to be bolted to it. For instance, the results list that appears after you type in some search term is attached to the boxes where we output the JSON data and API query endpoint. The plugin creates all of its required elements inside of Leaflet, so how did we get it to display anything else?

To do this, we use the plugin’s event listeners to respond to certain actions, like whenever results are returned. Each event provides access to the raw data and query information, so that’s how we can reconstruct that information in a separate part of the demo.

But that separate area doesn’t otherwise know anything about Leaflet, and Leaflet doesn’t know where the results are supposed to go. To gather these two separate parts in one place, we do a little manipulation of the HTML using JavaScript:

var resultsEl = document.querySelector('.leaflet-pelias-results');
var resultsContainerEl = document.getElementById('results-placeholder');
resultsContainerEl.parentNode.replaceChild(resultsEl, resultsContainerEl);

Basically, we move the results list outside of Leaflet and into another part of the page!

Since the geocoder plugin “remembers” the HTML element, it doesn’t matter where on the page it actually exists. We can move it anywhere, and the plugin still knows how to get to it! You can actually do this with the geocoder input itself, which is something we didn’t do for this demo, but it would have worked just as well.

Ultimately, though, this experience has taught us that when it comes to slightly more complex work, we spent more time than we needed to (and nursed several headaches) trying to override assumptions we made in the geocoder plugin. We designed the geocoder UI to allow it to work smoothly right out of the box for most users, across as many different devices and browsers as possible. But for this demo, the UI surrouding the geocoder is very different, so it felt very much like taking a very nicely made square peg but trying to force it into a tangentially related round hole. In future iterations of the demo (where we fix bugs, clean up code, and add new search features as they evolve), we could fork the plugin code rather than depend on the plugin as a dependency. This will make the demo much easier to maintain, easier to modify, and not make as many tradeoffs in usability for underlying technical reasons.

Build, measure, learn

The year of 2015 was a year of releasing a lot of product into the wild. The year of 2016 will be a year of learning from 2015 and iterating so that we can make our products even better. You’ll definitely see this from the Mapzen Search team and also in the demo we built to show it off, so stay tuned!

Note: This post was updated on May 31, 2017 to remove outdated API request links.