Thursday, December 11, 2014

Data.Gov: Public Government Data API's


Intro

Believe it or not, there are actually a few free things out there. Freedom may cost you $1.05, but there are tons of freely available public APIs. Some are corporate APIs for retrieving information on weather, traffic and other useful things. You can probably find plenty such APIs with a small amount of Google-fu. Some free public APIs are made available by our government. You can retrieve data on economics, oceanography, demographics,utility rates, and more.


The API I Want to Use

We have to start somewhere, and I've picked an API that gives information on alternative fuel stations. Go ahead and dig around on this site for a minute then come back. This API includes information on fueling stations that use alternative fuels such as hydrogen, natural gas, ethanol and more. I don't have such a vehicle, but hey it's an interesting topic and I want to play with this API. Feel free to start somewhere else with your own code if you like.

The method I'm most interested in right now is the one that lists all locations which match specified query parameters. I could picture this information being useful for a person who wants to find the alternative fuel stations near their home or work so they can plan their daily commute.

This method has a large number of request parameters that you can supply on the querystring. It also allows you to specify whether you wish to receive the results as xml or json. Either way, the request is a simple HTTP GET with a specific URL and chosen querystring parameters, and you parse out the response with code. For example, let's say I want to retrieve a list of the first 5 alternative fuel stations in zip code 75006 that have E85 ethanol gasoline or electric refueling. For this API I would use the url: http://developer.nrel.gov/api/alt-fuel-stations/v1.json?api_key=DEMO_KEY&fuel_type=E85,ELEC&zip=75006&limit=5. The first part, "http://developer.nrel.gov/api/alt-fuel-stations/v1", is the base url of the service. the next part, ".json" tells the service that I want my results in JSON format. other possible values are ".xml" and ".csv" for this API. Next up, "api_key=DEMO_KEY". This is how we authenticate with the API. In our case we're just going to use their demo key rather than creating an API key on the website. Now we get to the first filter of our querystring, "fuel_type=E85,ELEC". This tells the API that we want to return a list of stations that are E85 Ethanol or electric refuel/recharge capable. Next up is the zip code, and the last querystring chunk, "limit=5", tells the API we want only the first 5 results. Paste this sucker into your browser and see what you GET (ha, internet pun!). You should see something like this, except mine's formatted nicer:

{
   "station_locator_url":"http://www.afdc.energy.gov/afdc/locator/stations/",
   "total_results":2,
   "station_counts":{
      "total":8,
      "fuels":{
         "E85":{
            "total":0
         },
         "ELEC":{
            "total":8,
            "stations":{
               "total":2
            }
         },
         "HY":{
            "total":0
         },
         "LNG":{
            "total":0
         },
         "BD":{
            "total":0
         },
         "CNG":{
            "total":0
         },
         "LPG":{
            "total":0
         }
      }
   },
   "fuel_stations":[
      {
         "access_days_time":"MON: 24 hours | TUE: 24 hours | WED: 24 hours | THU: 24 hours | FRI: 24 hours | SAT: 24 hours | SUN: 24 hours",
         "cards_accepted":null,
         "date_last_confirmed":"2014-12-11",
         "expected_date":null,
         "fuel_type_code":"ELEC",
         "id":45129,
         "groups_with_access_code":"Private",
         "open_date":null,
         "owner_type_code":null,
         "status_code":"E",
         "station_name":"Carrier Enterprise HQ",
         "station_phone":"888-998-2546",
         "updated_at":"2014-12-11T08:09:02Z",
         "geocode_status":"GPS",
         "latitude":32.933474,
         "longitude":-96.92574,
         "city":"Carrollton",
         "intersection_directions":null,
         "plus4":null,
         "state":"TX",
         "street_address":"2000 Luna Rd",
         "zip":"75006",
         "bd_blends":null,
         "e85_blender_pump":null,
         "ev_connector_types":[
            "J1772"
         ],
         "ev_dc_fast_num":null,
         "ev_level1_evse_num":null,
         "ev_level2_evse_num":4,
         "ev_network":"Blink Network",
         "ev_network_web":"http://www.blinknetwork.com/",
         "ev_other_evse":null,
         "hy_status_link":null,
         "lpg_primary":null,
         "ng_fill_type_code":null,
         "ng_psi":null,
         "ng_vehicle_class":null,
         "ev_network_ids":{
            "station":[
               "51671"
            ],
            "posts":[
               "20199",
               "19577",
               "11721",
               "9055"
            ]
         }
      },
      {
         "access_days_time":null,
         "cards_accepted":null,
         "date_last_confirmed":"2014-04-04",
         "expected_date":null,
         "fuel_type_code":"ELEC",
         "id":46370,
         "groups_with_access_code":"Private",
         "open_date":"2011-08-13",
         "owner_type_code":"P",
         "status_code":"E",
         "station_name":"General Electric - Dallas Office",
         "station_phone":null,
         "updated_at":"2014-04-04T19:00:52Z",
         "geocode_status":"GPS",
         "latitude":32.9838,
         "longitude":-96.845317,
         "city":"Carrollton",
         "intersection_directions":null,
         "plus4":null,
         "state":"TX",
         "street_address":"2508 Highlander Way",
         "zip":"75006",
         "bd_blends":null,
         "e85_blender_pump":null,
         "ev_connector_types":[
            "J1772"
         ],
         "ev_dc_fast_num":null,
         "ev_level1_evse_num":null,
         "ev_level2_evse_num":4,
         "ev_network":null,
         "ev_network_web":null,
         "ev_other_evse":null,
         "hy_status_link":null,
         "lpg_primary":null,
         "ng_fill_type_code":null,
         "ng_psi":null,
         "ng_vehicle_class":null
      }
   ]
}


I'll just summarize the results rather than detailing all of it: we found 2 stations that match our criteria, both of which are electric recharging stations. We also got their address, which is kinda nifty and we'll use that in a few minutes.


Code it Like It's Hot

This wouldn't be a very good coder's blog if I didn't code something, so let's call the API. Create yourself a new web project in Visual Studio. I chose an empty WebForms project, and it will be easier for you to follow along if you do the same. Now add a default page to your site, named "Default". Drop a button on there and give it the same properties as the button you see in my code below:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="BlogPublicApi.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Public API Test</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="btnExecuteApi" runat="server" Text="Execute API" OnClick="btnExecuteApi_Click" />
    </div>
    </form>
</body>
</html>



Now go to the code behind of your page. The first thing you'll want to do is install the Microsoft Web API Client Libraries. It's a NuGet package. You can find it by searching for "Microsoft.AspNet.WebApi.Client" within the NuGet package manager. After you've added that to your solution/site, copy the code from my button click event into your own:

using System;
using System.Net.Http;


namespace BlogPublicApi
{
    public partial class Default : System.Web.UI.Page
    {
        protected void btnExecuteApi_Click(object sender, EventArgs e)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://developer.nrel.gov/");
                var response = client.GetAsync("api/alt-fuel-stations/v1.json?api_key=DEMO_KEY&fuel_type=E85,ELEC&zip=75006&limit=5").Result;
                if (response.IsSuccessStatusCode)
                {
                    dynamic stationResponseData = response.Content.ReadAsAsync<Object>().Result;
                    Response.Write("Total Results: " + stationResponseData.total_results + "<br />");
                    foreach (dynamic station in stationResponseData.fuel_stations)
                    {
                        Response.Write(String.Format("<a target='_blank' href='https://www.google.com/maps/place/{0},+{1},+{2}+{3}'>{4}</a>", 
                            station.street_address, station.city, station.state, station.zip, station.station_name));
                        Response.Write("<br />");
                    }
                    Response.Write("Raw Result Object: <div>" + stationResponseData + "</div>");
                }
            }

        }
    }
}


The magic starts with the using statement within btnExecuteApi_Click. This is where we create our http client object. The next line of code we set the base address, and then after that we get our response. Assuming the request was successful, we then pull out the json from the response as a dynamic object so that we can access its properties. We write out the total # of results, then loop through the individual fuel stations to create a link. Then for a little extra fun, we link to the station on Google maps. Try plugging in your own zip code and give the code a whirl! It's pretty neat to see the results on a map.

Here's a screenshot of the results so you can visualize what we've done:



What's Next?

There are lots of other free, public APIs out there. Look around, and see what you can make with all the free data. Maybe you'll end up with a great idea for an app for your phone.


References

APIs | Data.gov
Alternative Fuel Stations API
All Stations API | Alternative Fuel Stations
JSON Formatter & Validator 
Calling a Web API From a .Net Client

No comments:

Post a Comment