LegisLately: A Tale of Angular and APIs

The last time I built an SPA (with Rails and jQuery), I was pretty down on the whole concept. Performance wasn’t great, it broke the browser’s back button, and I was constantly fighting to keep my code from turning into callback nightmare spaghetti.

This time, I used Angular, and I’m thinking maybe SPAs are all right.

I learned a ton building this app. I worked with multiple external APIs, including one that went through some pretty significant changes during the building process; I tried a different approach to planning/preparing that mostly paid off; and I learned all the ins and outs of working with Angular and Rails.

APIs ARE AMAZING. AND FRUSTRATING.

I ended up working with 4 APIs during this project, not including my own Rails back end: the Google Geocoding API, the Google Civic Information API, the Sunlight Congress API, and the ProPublica Congress API. Only two of them are included in the final version of the project.

I got to learn first-hand the joys and hazards of relying on external APIs. Originally, I planned to use only the Sunlight API and the Google Geocoding API (to convert an address to latitude and longitude so the legislators/locate API call could find a user’s local senators and House rep). Calls to the SCAPI didn’t require a key, so I put all my API calls directly into the front end Angular code:

function SCAPIFactory($http, $sce) {
return {
getComingSoon: getComingSoon
}
function getComingSoon() {
return $http.get('https://congress.api.sunlightfoundation
.com/upcoming_bills');
};
}
angular
.module('legislately')
.factory('SCAPIFactory', SCAPIFactory);

However. Sunlight Labs shut down in November 2016. I didn’t realize it at the time, but the Sunlight Congress API was no longer being maintained and was in the process of being taken over and incorporated into ProPublica’s existing Congress API.

So about two-thirds of the way through my initial build, I realized I was going to have to migrate over to the ProPublica Congress API. Easy, I thought, I’ll just change over the URLs.

But what to do about that API key? Obviously I couldn’t just have it sitting in a Javascript file, freely available to anyone with the slightest knowledge of Chrome Dev Tools. My next idea was setting up a Rails route on the back end to respond with the key whenever it was needed — but anyone who glanced at the code on GitHub would know just what path to follow to get it.

I couldn’t set up an entire set of back end routes just to bounce these external API calls… could I? That seemed so… inefficient.

And yet there’s just no way to truly conceal an API key if it’s ever in front-end code.

So I rewrote large chunks of the front and back ends to allow the external API calls to be made via Rails and Faraday, with the API key nicely concealed via an environment variable. Now my external API calls look something like this:

def info
legislator_id = params[:id]
url = "https://api.propublica.org/congress/v1/members/#{legislator_id}.json"
@resp = Faraday.get url do |req|
req.headers['X-API-Key'] = ENV['PROPUBLICA_API_KEY']
end
    body_hash = JSON.parse(@resp.body)
legislator = body_hash['results'][0]
render json: legislator
end

Instead of making a request directly to the external API, an Angular factory makes a call to the back end, which grabs the API key and makes the external API call, then returns the data through Rails to the front end. Complex, but hey — the whole concept of having freely available data you can get just by sending an HTTP request is pretty mind-boggling.

NEATEST TRICK LEARNED

If you’ve worked with Bootstrap before, you may be familiar with the somewhat laborious process of attempting to change or override the default colors/fonts/etc to make it look a little less Bootstrappy.

But I have good news — you don’t have to abuse the !important rule in your CSS anymore! If you use the bootstrap-sass gem, you can redefine Bootstrap colors, fonts, spacing and more with Sass variables right there in your application.scss. Just make sure you put in the variable declarations before you @import "bootstrap". Like so:

$body-bg: #0971B2;
$headings-font-family: 'Open Sans Condensed', sans-serif;
$headings-font-weight: 300;
$headings-color: #FEFFFE;
@import "bootstrap";

For a full list of Bootstrap variables and defaults, go here.

WORKFLOW EXPERIMENTS

I tried out a new approach by completely separating out design and application logic for the first phase of this project. That is to say, I built out the entire initial app in plain text. No styling whatsoever until the app logic was pretty well fleshed out.

This worked really well for me because I work best when I can concentrate deeply on one problem at a time. In the past, I’ve tried to build the design alongside the logic and ended up feeling scattered and distracted (plus the time suck of trying to redesign things on the fly when I was in the middle of working out a thorny technical problem).

This approach definitely wouldn’t work well with a team, but it was an interesting experiment for a solo project. Apparently separation of concerns is good for workflows too! Who knew?

RESOURCES

Aside from the amazing APIs mentioned above, I took advantage of a variety of excellent resources while building this app:

To explore the code for this project, check it out on GitHub.