Build a Restaurant Discovery App
Fetch restaurants in any area with names, cuisine types, and map coordinates using live OpenStreetMap data. This example shows how to handle the two ways OSM mappers represent restaurants - as a single point node or as a full building footprint - and how the API's centroid field makes placing map pins effortless in both cases.
What you'll build
A restaurant discovery card list with name, cuisine type, and a map pin coordinate for every restaurant in a given bounding box. The same pattern powers food-finder apps, travel guides, and local search features. Because OSM mappers model restaurants in two different ways - a simple point node, or a building footprint polygon - you need to handle both geometry types. The MapLark API makes this trivial: every polygon feature includes a precomputed properties.centroid (a GeoJSON Point) so you always have a pin coordinate without any extra computation.
Prerequisites
Run these commands on a Bash terminal.
pip install osmfeaturesScript
View full source code: test_restaurant_guide.py
"""
App idea: restaurant discovery card list with name, cuisine, and a map pin.
Gamla Stan is Stockholm's old town and a popular tourist dining destination.
Restaurants can be mapped as nodes (a single point) or as building footprints
(ways); the centroid is used as the display coordinate for polygons.
API call: ``type=node,way&tags=amenity=restaurant``
"""
from collections import defaultdict
from osmfeatures import OSMFeature, OSMFeatureCollection, OSMFeaturesClient
GAMLA_STAN_BBOX = "18.063,59.322,18.082,59.332"
def test_restaurant_guide(client: OSMFeaturesClient):
data = client.query(
bbox=GAMLA_STAN_BBOX,
type="node,way",
tags="amenity=restaurant",
limit=50,
)
assert isinstance(data, OSMFeatureCollection)
assert len(data["features"]) > 0, "Expected restaurants in Gamla Stan"
named = []
cuisines: dict[str, int] = defaultdict(int)
for f in data["features"]:
assert isinstance(f, OSMFeature)
tags = f.tags
assert tags.get("amenity") == "restaurant"
# Derive a display coordinate: use the centroid for polygon restaurants,
# or the point geometry directly for node restaurants.
if f["geometry"]["type"] == "Point":
display_coord = f["geometry"]["coordinates"]
else:
assert f.centroid is not None
display_coord = f.centroid["coordinates"]
assert len(display_coord) == 2
if tags.get("name"):
named.append(tags["name"])
if tags.get("cuisine"):
cuisines[tags["cuisine"]] += 1
assert len(named) > 0, "Expected at least some named restaurants"
print(f"\n[restaurant guide] {len(data['features'])} restaurants, {len(named)} named")
print(f" Sample names: {named[:5]}")
print(f" Cuisines: {dict(sorted(cuisines.items(), key=lambda x: -x[1])[:5])}")
How it works
This query sets type=node,way so the API returns point nodes and way footprints, and skips relations. That matches how restaurants are usually mapped in OSM. Filtering to type=node alone would silently miss any restaurant mapped as a building footprint.
| Parameter | Value | What it does |
|---|---|---|
bbox | min_lon,min_lat,max_lon,max_lat | Spatial anchor - required when using tag filters without osm_ids. |
tags | amenity=restaurant | Exact tag match. Multiple tags values are AND-combined - useful for querying restaurants of a specific cuisine. |
type | node,way | Nodes (points) and ways (footprints). Excludes relations. Needed so polygon-mapped restaurants are included. |
properties.centroid - a precomputed GeoJSON Point at the geometric centre. Use it directly as the map pin location. For type=node Point features, centroid is absent; read from geometry.coordinates instead. Adapt it
Swap the tags value to build any dining or hospitality guide:
| Tags value | What you get |
|---|---|
amenity=cafe | Coffee shops and cafés |
amenity=bar | Bars and pubs |
amenity=fast_food | Fast food outlets |
amenity=food_court | Food courts |
tourism=hotel | Hotels (use centroid for the map pin) |
More examples
Park Bench Finder
The simplest possible MapLark query - fetch point nodes in a bbox and place them on a map.
Cycling Trail Finder
Use OR-combined tag filters to find bike-permitted paths and forestry tracks.
Walking Route Planner
Build Dijkstra-based walking directions on a real OSM footway network.
API Playground
Explore the OSM dataset with preset tag filters and test all API parameters.