Open main menu

API:Nearby places viewer

Contents

OverviewEdit

In this tutorial, you will learn how to search for wiki pages near your location using the MediaWiki Action API.

This tutorial will teach you how to do this using:

A step-by-step process for building this application:

Step 1: Set up Python and Flask development environmentEdit

To set up the Python development environment for a Flask application, you will need to install Python, create a virtual environment and install Flask.

Note: This application uses Python3, the recommended version for new Python projects. Learn more about the differences between Python2 and Python3 here. To install Python3 on your local machine, follow step-by-step instructions in these installation guides.

Here is how to set up the development environment for building the application:

$ mkdir nearby-places-viewer
$ cd nearby-places-viewer/
This will create a new directory and change into it
$ python3 --version #Python 3.6.5
This command checks your Python version 
$ python3 -m venv venv
This command will create a virtual environment named 'venv'
$ source venv/bin/activate
This will activate the virtual environment
$ pip install Flask
This command will install the Flask package with all its dependencies

Step 2: Create a simple Flask applicationEdit

Render a simple static pageEdit

Place the following code in $HOME/nearby-places-viewer/nearby.py

#!/usr/bin/python3

"""
    nearby.py

    MediaWiki Action API Code Samples
    
    Nearby places viewer app: Demo of geo search for wiki pages 
    near a location using the Geolocation API and MediaWiki Action 
    API's Geosearch module. 

    MIT license
"""

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    """ Displays the index page accessible at '/'
    """
    return render_template('places.html')

if __name__ == '__main__':
    app.run()

Drop this one line of code <h1>Nearby places viewer</h1> in a HTML file inside the templates folder: $HOME/nearby-places-viewer/templates/places.html

Note: In this simple application, we are using render_template method which renders the template named places.html from the templates directory.

Next run your flask app with the command python nearby.py and open http://127.0.0.1:5000/ to view your app in the browser. You should be able to see "Nearby places viewer" in your browser window.

Style your appEdit

Let's do some app styling. Add a button element for accepting search input in the HTML file and link tags to load an external and internal stylesheet. External stylesheet, in this case, is the URL of a CSS file for a Google Font Amatic.

Replace the existing code in $HOME/nearby-places-viewer/templates/places.html with the following:

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Amatic+SC:700">
<link rel="stylesheet" href="/static/style.css">

<h1>Nearby places viewer</h1>
<button>Click here to search</button>

Place the following code in $HOME/nearby-places-viewer/static/static.css

h1 {
    font-family: 'Amatic SC', cursive;
    font-size: 2.5em;
    font-weight: normal;
    color: black;
}

button {
    font-size: 16px;
    padding: 10px 25px;
    cursor: pointer;
    text-decoration: none;
    color: white;
    border-radius: 4px;
    background-color: #7c7ce0;
    margin-bottom: 20px;
}
 
Nearby places viewer demo app screenshot (1)

Application layoutEdit

$HOME/nearby-places-viewer
├── templates/
│   └── places.html
├── static/
│   └── static.css
├── nearby.py
└── venv/

Step 3: Obtain coordinates of your current locationEdit

As a first step, to search for wiki pages nearby, you will need to obtain coordinates of your current location. To do so, you can use the Geolocation API along with some Javascript code.

When you click the Click here to search button, the app makes a call to the Geolocation API and retrieves the current position of your device via the API's Navigator.geolocation object. The API's response in return is a Position object from which you can obtain the latitude and longitude.

Note: When your app makes a call to the API you will be notified and asked to grant permission to your browser to access your location.

Place the following code in $HOME/nearby-places-viewer/static/places.js

$( document ).ready(function() {
	var x = document.getElementById( "places-list" );
	
	$( 'button' ).click(function() { 
		getLocation(); 
	});

	function getLocation() {
		x.innerHTML = "Searching your location..";

		if (navigator.geolocation) {
			navigator.geolocation.getCurrentPosition(fetchPlaces);
		} else { 
			x.innerHTML = "Geolocation is not supported by this browser.";
		}
	}

	function fetchPlaces(position) {
		x.innerHTML = position.coords.latitude + "|" + position.coords.longitude;
	}
});

Link the custom javascript /static/places.js and JQuery from the HTML file: $HOME/nearby-places-viewer/templates/places.html

<!-- Add these two lines at the top -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="/static/places.js"></script> 

<!-- Add this line after the button element -->
<div id="places-list"></div>

Step 4: Send location data to the server with AJAXEdit

This app uses jQuery's AJAX method to send the location data obtained in Step 3 to the server and POST it without page refresh to a Python Flask route / in $HOME/nearby-places-viewer/nearby.py.

As a next step, let's add AJAX call to the function fetchPlaces in $HOME/nearby-places-viewer/static/places.js.

Note: At this point, if you try to run your app, it is likely that you will see an error in the browser window as we have not added support to the route / to handle post requests.

function fetchPlaces(position) {
	var data = { 
		"latitude": position.coords.latitude, 
		"longitude": position.coords.longitude
	};

	$.ajax({
		url: "/",
		type: "POST",
		data: JSON.stringify(data),
		contentType: "application/json",
		dataType: "json",

		success: function (response) { 
			x.innerHTML = "Success!";
		}, 
		error: function () { 
			x.innerHTML = "An error occured while fetching places!"; 
		}
	});
}

Step 5: Fetch nearby places via MediaWiki Action APIEdit

First, extend the Python Flask route / in $HOME/nearby-places-viewer/nearby.py to handle POST requests. You can do so by adding both GET and POST in the methods argument list in the route decorator. Next, you can obtain location data available in JSON format from the request object and pass it to fetch_places_nearby() function for further processing.

@app.route('/', methods=['GET', 'POST'])
def index():
    """ Displays the index page accessible at '/'
    """

    if request.method == "POST":
        data = request.get_json()
        latitude = data['latitude']
        longitude = data['longitude']

        results = fetch_places_nearby(latitude, longitude)
        return jsonify(results=results)

    return render_template('places.html')

The code in the fetch_places_nearby() function makes a GET request to the Action API to search for wiki pages near a location. API call consists of an endpoint https://en.wikipedia.org/w/api.php and query string parameters. Some of the key parameters are:

  • action=query main module to query information
  • generator=geosearch query module's submodule list used as a generator module to get search results for a set of pages
  • prop=coordinates|pageimages|description|info tells which properties to return for pages

Note: For more information on the geosearch module visit API:Geosearch.

def fetch_places_nearby(lat, lon):
    params = {
        "action": "query",
        "prop": "coordinates|pageimages|description|info",
        "inprop": "url",
        "pithumbsize": 144,
        "generator": "geosearch",
        "ggsradius": 10000,
        "ggslimit": 10,
        "ggscoord": str(lat) + "|" + str(lon),
        "format": "json",
    }

    res = SESSION.get(url=API_ENDPOINT, params=params)
    data = res.json()
    places = data['query'] and data['query']['pages'] 
    # TODO: further process 'places' list
    
    return places

View complete Python and Flask code with import statements and processed places list. This app uses Haversine package available in Python to calculate distance between two geographic coordinates.

Step 6: Create a user interface for list of places from JSON responseEdit

Handle the returned JSON data from the server in AJAX's success callback and use HTML DOM innerHTML property to alter the div contents.

success: function (response) { 
	var places = response["results"],
		no_thumb = "..";

	x.innerHTML = "";
	
	for (var p in places) {
		var thumbnail = places[p].thumbnail || no_thumb;

		x.innerHTML += "<div class=\"item\"><div class=\"col-xs-8 no-padding\"><h5><a href=\"" +
			places[p]["articleUrl"] + "\" target=\"_blank\">" +
			places[p]["title"] + "</a></h5><p>" +
			places[p]["description"] + "</p><span>📍" + places[p]["distance"] +
			" miles</p></div><div class=\"col-xs-4 no-padding\"><img src=\"" +
			thumbnail + " \"></div></div>";
	}
}

View complete Javascript code with AJAX success callback.

Step 7: Style changes with BootstrapEdit

You might have noticed that the code snippet in Step 6 uses Bootstrap class names. Yes, we are integrating the Bootstrap framework at this step to add a responsive layout design to the Places UI. To do so, let's make some more tweaks to CSS and HTML files.

View complete CSS and HTML code.

 
Nearby places viewer demo app screenshot (2)

Next stepsEdit

See alsoEdit