Search code examples
c#asp.net-coreapi-designgoogle-geocoder

Get County from Zip in Google GeoCode API


I'm new to APIs in general. I'm trying to learn how to use the Google GeoCode API to get the county from a user input zip code. I'm using .NET Core MVC

An example payload can be seen with the following URL: http://maps.googleapis.com/maps/api/geocode/json?address=77379&sensor=true

which produces the payload:

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "77379",
               "short_name" : "77379",
               "types" : [ "postal_code" ]
            },
            {
               "long_name" : "Spring",
               "short_name" : "Spring",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Harris County",
               "short_name" : "Harris County",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "Texas",
               "short_name" : "TX",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "United States",
               "short_name" : "US",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Spring, TX 77379, USA",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 30.088189,
                  "lng" : -95.47364999999999
               },
               "southwest" : {
                  "lat" : 29.9871611,
                  "lng" : -95.5887879
               }
            },
            "location" : {
               "lat" : 30.0314279,
               "lng" : -95.5302337
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 30.088189,
                  "lng" : -95.47364999999999
               },
               "southwest" : {
                  "lat" : 29.9871611,
                  "lng" : -95.5887879
               }
            }
         },
         "place_id" : "ChIJtZcGtDLNQIYRtGE9AgmSOPQ",
         "postcode_localities" : [ "Klein", "Spring" ],
         "types" : [ "postal_code" ]
      }
   ],
   "status" : "OK"
}

For example, I would like to get the string "Harris County" from the above's url JSON result.

In my model, I have:

public class GoogleAddress

{
    public List<Result> results;
}

[DataContract]
public class Result
{
    [DataMember(Name = "long_name")]
    public string long_name { get; set; }
    [DataMember(Name = "short_name")]
    public string short_name { get; set; }
    [DataMember(Name = "types")]
    public string types { get; set; }
}

In my controller, I have the following within my method:

//zip to be passed as a parameter in my method later, hardcoded here for testing
string zip = "77379";
string county = "";
var serializer = new DataContractJsonSerializer(typeof(GoogleAddress));
//example url: http://maps.googleapis.com/maps/api/geocode/json?address=77379&sensor=true
string url = "http://maps.googleapis.com/maps/api/geocode/json?address=" + zip + "&sensor=true";
var client = new HttpClient();
var streamTask = client.GetStreamAsync(url);
var address = (GoogleAddress)serializer.ReadObject(await streamTask);
var result = address.results;
//how do I get the county from the result?

return View(county);

How should my model be set up to match the payload and how do I get the County name from the payload?


Solution

  • Consider using a framework like Json.Net. Using this you can dynamically parse your json response and get only those parts which are usefull for you:

    var jsonResult = "some json from google api";
    dynamic jsonObject = JObject.Parse(jsonResult);
    var long_name = jsonObject.results[0].address_components[2].long_name;
    var short_name = jsonObject.results[0].address_components[2].short_name;
    

    If you want to work with the whole data set returned from google, you can create a suitable class structure (this can be automated by using a tool such as json2csharp or Visual Studios Paste Special functionality) and deserialize your json result regarding:

    Class structure

    public class AddressComponent
    {
        public string long_name { get; set; }
        public string short_name { get; set; }
        public List<string> types { get; set; }
    }
    
    public class Northeast
    {
        public double lat { get; set; }
        public double lng { get; set; }
    }
    
    public class Southwest
    {
        public double lat { get; set; }
        public double lng { get; set; }
    }
    
    public class Bounds
    {
        public Northeast northeast { get; set; }
        public Southwest southwest { get; set; }
    }
    
    public class Location
    {
        public double lat { get; set; }
        public double lng { get; set; }
    }
    
    public class Northeast2
    {
        public double lat { get; set; }
        public double lng { get; set; }
    }
    
    public class Southwest2
    {
        public double lat { get; set; }
        public double lng { get; set; }
    }
    
    public class Viewport
    {
        public Northeast2 northeast { get; set; }
        public Southwest2 southwest { get; set; }
    }
    
    public class Geometry
    {
        public Bounds bounds { get; set; }
        public Location location { get; set; }
        public string location_type { get; set; }
        public Viewport viewport { get; set; }
    }
    
    public class Result
    {
        public List<AddressComponent> address_components { get; set; }
        public string formatted_address { get; set; }
        public Geometry geometry { get; set; }
        public string place_id { get; set; }
        public List<string> postcode_localities { get; set; }
        public List<string> types { get; set; }
    }
    
    public class RootObject
    {
        public List<Result> results { get; set; }
        public string status { get; set; }
    }
    

    Deserialize json

    var data = JsonConvert.DeserializeObject<RootObject>(jsonResult);
    var long_name = data.results[0].address_components[2].long_name;
    var short_name = data.results[0].address_components[2].short_name;
    

    Edit

    Full example:

    string zip = "77379";
    string url = "http://maps.googleapis.com/maps/api/geocode/json?address=" + zip + "&sensor=true";
    var client = new HttpClient();
    
    // 'using' forces proper cleanup after finishing the operation
    using(var response = await client.GetAsync(url))
    {
        if(response.IsSuccessStatusCode)
        {
            var jsonResult = await response.Content.ReadAsStringAsync();    
            dynamic jsonObject = JObject.Parse(jsonResult);
    
            // Consider doing some validation first to be sure that 'results' and 'address_components' contains any elements to avoid exceptions
            var long_name = jsonObject.results[0].address_components[2].long_name;
            var short_name = jsonObject.results[0].address_components[2].short_name;
        }
    }