Created
June 8, 2017 01:14
-
-
Save Thomascountz/b7cf1813b9467e64a9c0778c64c64312 to your computer and use it in GitHub Desktop.
API wrapper for Propublica's Congress API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Abstracts queries to The Propublica Congress API into methods | |
class Congress | |
attr_reader :query | |
def initialize(args) | |
@query = args.fetch(:query, nil) | |
end | |
def members_of_senate(senate_number = 115) | |
get("#{senate_number}/senate/members.json") | |
end | |
private | |
def get(path) | |
query.get(path) | |
end | |
end | |
# Interface to build API requests | |
class Query | |
attr_reader :request, :base_url, :api_key | |
def initialize(args) | |
@request = args.fetch(:request, nil) | |
@base_url = args.fetch(:base_url, nil) | |
@api_key = args.fetch(:api_key, nil) | |
end | |
def get(path) | |
request.get(full_path(path), headers) | |
end | |
private | |
def full_path(path) | |
base_url.to_s + path.to_s | |
end | |
def headers | |
{ headers: { 'X-API-Key' => api_key } } | |
end | |
end | |
require 'HTTParty' | |
base_url = 'http://api.propublica.org/congress/v1/' | |
puts Congress.new( | |
query: Query.new(request: HTTParty, | |
base_url: base_url, | |
api_key: API_KEY) | |
).members_of_senate | |
# Query, what's your base_url? # => YES! | |
# Query, what's your api_key? # => YES! | |
# Query, what's your request? # => YES! | |
# Congress, what's your members_of_senate? # => YES! | |
# Congress, what's your query? # => YES! | |
# Congress has at least four dependencies on Request | |
# - The name of another class | |
# -- Congress expects a class named Request to exist | |
# => SOLUTION | |
# Dependency Injection. Congress now depends only on a 'duck' that responds to | |
# .get. Though Congress needs to send .get, somewhere, it doesn't need to know | |
# about Request. We can now pass in any object that has a .get method. | |
# - The name of the message it intends to send to somehwere other than self | |
# -- Congress expects Request to response to .get | |
# => SOLUTION | |
# Isolate vulnerable external messages. You can decrease a method's relience on | |
# an external method by wrapping it's external message in a method of it's own. | |
# Now, if Query#get changes, Congress will only have to change it's external | |
# call in one place. | |
# - The arguement that a message requires | |
# -- Congress knows that Request#new requires a base_url and api_key, etc. | |
# => SOLUTION | |
# When you send a message that requires arguemnts, having knowledge of those | |
# arguments are inevitable. But a bigger problem is the arguement order. | |
# See next. | |
# - The order of those arguments | |
# -- Congress knows the first argument of Request#new should be base_url, etc. | |
# => SOLUTION | |
# Remove argument order dependencies with an intialize hash and explicitly | |
# defining defaults by using "||", ".fetch", or isolating them inside of a | |
# seperate "defaults" method and ".merge" them into the initialize args hash. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment