Update: If you look at the comments down below you’ll see a comment from Thor Mitchell. Thor is the product manager for the Google Maps API. His comment informed me that the technique I demonstrate below (using a server-side proxy service to relay geocoded addresses) is needlessly complicated and against the Google Terms of Service. Consequently, I updated my code and published this code in an new blog post. I recommend that you use alternate technique to validate street addresses.
I’ve never been a fan of address forms that look like this;
From a data entry perspective, it forces users to hit TAB constantly. And users who are less web savvy will transition between the mouse and the keyboard to negotiate these fields. It’s not a natural way to type an address.
By contrast, here is a human friendly address form:
While typing an address into this field, users can stay on the keyboard and simply type the address in a way that feels natural. The problem [for programmers] is parsing and validating this raw text once the form has been submitted.
Converting raw text to a valid address
Overcoming this challenge was part of a recent project. In a past life, I worked with the US Census Bureau TIGER data to validate & geocode addresses. I was only marginally successfully at this task.
Thankfully, since that time, Google Maps was created and Google made available an API for validating & geocoding addresses. My plan was to tackle this challenge with the following 3 ingredients:
On paper, this appeared relatively straight-forward. However, in practice I encountered several hurdles. Below I’ve detailed how I overcame these hurdles.
Fetching a geocoded address from the Google Map API
It’s relatively simple to get a geocoded address from Google’s Map API. Furthermore, Google does an incredible job of converting seemingly bad input into valid input. Take, for example, the following address:
1600 Amphitheatre Pkwy
I’ve not specified a city, a state or a zip code. This address looks invalid. However, because this address is unique enough, Google is able to resolve this incomplete address into a valid address. This can be done using the following URL:
http://maps.google.com/maps/api/geocode/json?address=1600%20Amphitheatre%20Parkway&sensor=false
The address parameter contains the value of the possible address. Google will attempt to resolve this address. If resolved, a geocoded full address is returned using JSON. Click the link above to see the JSON data and explore the structure of the data.
By the way, the address could also be returned in XML by replacing json, in the URL above, with xml.
Creating a proxy service for the Google Maps API
Fetching the Google geocode URL (shown above) is extremely easy. As a result, my inclination was to write some Javascript to fetch this URL from the web browser and then use the result to validate (or invalidate) the address.
However, when I executed this client-side Javascript code, I received the following error:
XMLHttpRequest cannot load http://maps.google.com/maps/api/geocode/json?address=1600%20Amphitheatre%20Parkway&sensor=false. Origin http://localhost:52306 is not allowed by Access-Control-Allow-Origin.
After some research I discovered this is not possible due to cross site scripting prohibitions that Google has applied to the Google Maps API. If you’re interested in more information about these limitations, check out the following links:
To make a long story short, it is not possible to get client-side scripting access to the Google Maps Geocode API and then handoff the result to custom Javscript method . To overcome this challenge it is necessary to create a proxy service (server-side) that fetches the Google Maps API result on behalf of the client.
Here are the basic steps this proxy service needs to perform:
- Accept a possible address from the client web browser
- Pass this address to Google to geocode
- Receive the result from Google
- Pass the result to the client
There are many different flavors of server-side environments & languages. Consequently, I’m not going to be able to help everyone. The language I use most often is C#. The particular web site I was creating was based on ASP.NET MVC. Below is the controller I created for this service. I documented the steps in my code to help anyone who is converting this code to another languages:
~/Controllers/ApiController.cs
using System.Linq;
using System.Web.Mvc;
using System.Xml.Linq;
using MvcApplication.Models;
namespace MvcApplication.Controllers
{
public class ApiController : Controller
{
/// <summary>
/// The controller for http://myurl/api/geocode
/// </summary>
/// <param name="address">The address to be geocoded by Google Maps</param>
/// <returns></returns>
public JsonResult Geocode(string address)
{
// I hate magic strings, so I created a strongly-typed class to hold the address values
var geoAddress = new Address();
// This is the Google Maps API URL that will geocode this address
var geoxml = XDocument.Load("http://maps.google.com/maps/api/geocode/xml" + "?address=" + address + "&sensor=false");
if (geoxml.Descendants("result").Any())
{
// Use LINQ to XML to extract the geocode values from the returned XML
var parts = from part in geoxml.Descendants("result").First().Descendants("address_component")
select new
{
LongName = part.Element("long_name").Value,
ShortName = part.Element("short_name").Value,
TypeName = part.Element("type").Value,
};
// Ensure Google returned at least one result
if (parts.Count() > 0)
{
// Loop through each item
foreach (var part in parts)
{
switch (part.TypeName)
{
case "street_number":
geoAddress.StreetNumber = part.LongName;
break;
case "route":
geoAddress.StreetName = part.LongName;
break;
case "locality":
geoAddress.City = part.LongName;
break;
case "administrative_area_level_1":
geoAddress.State = part.LongName;
geoAddress.StateAbbreviation = part.ShortName;
break;
case "postal_code":
geoAddress.Zip = part.LongName;
break;
}
}
}
}
// Serialize the Address class (created above) to JSON and return to the client
return Json(geoAddress, JsonRequestBehavior.AllowGet);
}
}
}
I’m also using a strongly-typed model to represent the address. Here is the code:
~/Models/Address.cs
namespace MvcApplication.Models
{
public class Address
{
public string StreetNumber { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
public string State { get; set; }
public string StateAbbreviation { get; set; }
public string Zip { get; set; }
}
}
At the conclusion of this step, you should be able to make a request to your web server and receive a geocoded JSON address. Example:
http://localhost/api/geocode?address=1600%20Amphitheatre%20Parkway
{"StreetNumber":"1600","StreetName":"Amphitheatre Pkwy","City":"Mountain View","State":"California","StateAbbreviation":"CA","Zip":"94043"}
Creating the web form
The proxy service (created above) can now relay address validation back & forth between the Google Maps API and the web client. However, what is missing is the client-side Javascript to make all of this function.
To get started, I’ll create the simple web form shown in the screenshot above:
<form id="MyForm" name="MyForm" action="form.html">
<div>
<label for="Name">Name</label>
<input id="Name" name="Name" type="text" />
</div>
<div>
<label for="FullAddress">Address</label>
<textarea id="FullAddress" name="FullAddress" cols="40" rows="5" class="fulladdressvalidator"></textarea>
</div>
<div>
<input id="Submit" name="Submit" value="Submit" type="button" />
</div>
</form>
Creating an address jQuery Validator
Next, I’ll create a custom jQuery validator that performs the following tasks:
- Sends the address to my proxy service
- Get the result from the proxy service
- Return a true/false value indicating whether the input is valid
This seems simple, but it involves an asynchronous call to the proxy service. This means processing continues after the initial proxy service request is made. Before the result is received the validator needs to return a true/false value indicating whether the address is valid or not.
To overcome this challenge, I added an IsChecking flag using jQuery’s data method. This flag is set to true when the request is sent to the proxy service. When a form is submitted I’m able to check this flag to see whether the field has truly been validated.
Here is the code for this jQuery full address validator:
function FullAddressValidator(value, element, paras) {
// Convert the value variable into something a bit more descriptive
var CurrentAddress = value;
// If the address is blank, then this is for the required validator to deal with.
if (value.length == 0) {
return true;
}
// If we've already validated this address, then just return the previous result
if ($(element).data("LastAddressValidated") == CurrentAddress) {
return $(element).data("IsValid");
}
// We have a new address to validate, set the IsChecking flag to true and set the LastAddressValidated to the CurrentAddress
$(element).data("IsChecking", true);
$(element).data("LastAddressValidated", CurrentAddress);
// The URL for my geocode proxy service
var geocodeUrl = '/api/geocode?address=' + escape(CurrentAddress);
// Make an asynchronous call to the geocode proxy service.
$.ajax({
url: geocodeUrl,
type: "GET",
dataType: 'json',
success: function (data, textStatus, XMLHttpRequest) {
// The code below only gets run after a successful proxy service call has completed.
// Because this is an asynchronous call, the validator has already returned a 'true' result
// to supress an error message and then cancelled the form submission. The code below
// needs to fetch the true validation from the proxy service and then re-execute the
// jQuery form validator to display the error message. Futhermore, if the form was
// being submitted, the code below needs to resume that submit.
// If StreetNumber exists, then the address is valid
if (data.StreetNumber) {
var address = data.StreetNumber + ' ' + data.StreetName + "\n" + data.City + ', ' + data.StateAbbreviation + ' ' + data.Zip;
$(element).val(address);
$(element).data("LastAddressValidated", address);
$(element).data("IsValid", true);
// Otherwise the address is invalid
} else {
$(element).data("IsValid", false);
}
// We're no longer in the midst of validating
$(element).data("IsChecking", false);
// Get the parent form element for this address field
var form = $(element).parents('form:first');
// This code is being run after the validation for this field,
// if the form was being submitted before this validtor was
// called then we need to re-submit the form.
if ($(element).data("SubmitForm") == true) {
form.submit();
} else {
// Re-validate this property so we can return the result.
form.validate().element(element);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$(element).data("IsValid", false);
$(element).data("IsChecking", false);
$(element).data("SubmitForm", false);
}
});
return true;
}
$.validator.addMethod("fulladdress", FullAddressValidator);
Putting it all together
The steps above describe how to:
- Create a proxy service to the Google Maps Geocode API
- Create a custom jQuery Validator to use this proxy service for address validation
The final step is to combine all of these pieces into a working form. Below is the completed client-side code for the form shown above.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Example Form </title>
<link href="./css/site.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
</head>
<body>
<div class="page">
<div id="main">
<form id="MyForm" name="MyForm" action="form.html">
<div>
<label for="Name">
Name</label>
<input id="Name" name="Name" type="text" />
</div>
<div>
<label for="FullAddress">
Address</label>
<textarea id="FullAddress" name="FullAddress" cols="40" rows="5" class="fulladdressvalidator"></textarea>
</div>
<div>
<input id="Submit" name="Submit" value="Submit" type="button" />
</div>
</form>
</div>
</div>
<script type="text/javascript">
// The following code show execute only after the page is fully loaded
$(document).ready(function () {
if ($('#MyForm').exists()) {
// Enable jQuery Validation for the form
$("#MyForm").validate();
// Add validation rules to the FullAddress field
$("#FullAddress").rules("add", {
fulladdress: true,
required: true,
messages: {
fulladdress: "Google cannot locate this address."
}
});
// This function will be executed when the form is submitted
function FormSubmit() {
$.submitForm = true;
if (!$('#MyForm').valid()) {
return false;
} else {
if ($("#FullAddress").data("IsChecking") == true) {
$("#FullAddress").data("SubmitForm", true);
return false;
}
return false;
}
}
// Attach the FormSubmit function to the Submit button
if ($('#Submit').exists()) {
$("#Submit").click(FormSubmit);
}
// Execute the ForumSubmit function when the form is submitted
$('#MyForm').submit(FormSubmit);
}
});
// Create a jQuery exists method
jQuery.fn.exists = function () { return jQuery(this).length > 0; }
// FullAddress jQuery Validator
function FullAddressValidator(value, element, paras) {
// Convert the value variable into something a bit more descriptive
var CurrentAddress = value;
// If the address is blank, then this is for the required validator to deal with.
if (value.length == 0) {
return true;
}
// If we've already validated this address, then just return the previous result
if ($(element).data("LastAddressValidated") == CurrentAddress) {
return $(element).data("IsValid");
}
// We have a new address to validate, set the IsChecking flag to true and set the LastAddressValidated to the CurrentAddress
$(element).data("IsChecking", true);
$(element).data("LastAddressValidated", CurrentAddress);
// The URL for my geocode proxy service
var geocodeUrl = '/api/geocode?address=' + escape(CurrentAddress);
// Make an asynchronous call to the geocode proxy service.
$.ajax({
url: geocodeUrl,
type: "GET",
dataType: 'json',
success: function (data, textStatus, XMLHttpRequest) {
// The code below only gets run after a successful proxy service call has completed.
// Because this is an asynchronous call, the validator has already returned a 'true' result
// to supress an error message and then cancelled the form submission. The code below
// needs to fetch the true validation from the proxy service and then re-execute the
// jQuery form validator to display the error message. Futhermore, if the form was
// being submitted, the code below needs to resume that submit.
// If StreetNumber exists, then the address is valid
if (data.StreetNumber) {
var address = data.StreetNumber + ' ' + data.StreetName + "\n" + data.City + ', ' + data.StateAbbreviation + ' ' + data.Zip;
$(element).val(address);
$(element).data("LastAddressValidated", address);
$(element).data("IsValid", true);
// Otherwise the address is invalid
} else {
$(element).data("IsValid", false);
}
// We're no longer in the midst of validating
$(element).data("IsChecking", false);
// Get the parent form element for this address field
var form = $(element).parents('form:first');
// This code is being run after the validation for this field,
// if the form was being submitted before this validtor was
// called then we need to re-submit the form.
if ($(element).data("SubmitForm") == true) {
form.submit();
} else {
// Re-validate this property so we can return the result.
form.validate().element(element);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$(element).data("IsValid", false);
$(element).data("IsChecking", false);
$(element).data("SubmitForm", false);
}
});
return true;
}
$.validator.addMethod("fulladdress", FullAddressValidator);
</script>
</body>
</html>
All this work, just so I can do this:
Damn!





Pingback: Geocode addresses | 747mediagroup