Skip to content

Instantly share code, notes, and snippets.

@eskilandreen
Last active September 4, 2016 15:39
Show Gist options
  • Save eskilandreen/5807d559f47003bb24add5dc64558dd6 to your computer and use it in GitHub Desktop.
Save eskilandreen/5807d559f47003bb24add5dc64558dd6 to your computer and use it in GitHub Desktop.
Better python service
''' Responsible for querying remote services and validating the result. '''
from simplejson import JSONDecodeError
import requests
# Exceptions
class ValidationError(Exception): pass
class RequestError(Exception): pass
# Types for representing results from backend services.
# Data from the backend service will be passed to the constructor
# using dictionary unpacking (the ** operator). Any parameters
# specified in the constructor will be captured and any others
# will end up in the ignored dictionary, which will be ignored.
# This means that we only need to handle those parts of the data
# that we care about. Besides saving some keystrokes, it also makes
# our code less brittle if somebody wants to make changes to what
# fields the other service exposes.
class Bill(object):
def __init__(self, amount, **ignored):
self.amount = amount
class Merchant(object):
def __init__(self, name, **ignored):
self.name = name
# Fetching and validation.
def get_merchant(merchant_id):
data = _query('http://merchant/merchant/' + merchant_id)
try:
return Merchant(**data)
except:
raise ValidationError('Could not validate Merchant')
def get_billing(merchant_id):
data = _query('http://billing/merchant/' + merchant_id)
try:
return [Bill(**item) for item in data]
except:
raise ValidationError('Could not validate Bills')
# Helper for making the request and checking the status code.
def _query(url):
res = requests.get(url)
if res.status_code != 200:
raise RequestError('Status code != 200')
try:
return res.json()
except JSONDecodeError:
raise RequestError('Could not decode JSON')
from bottle import route, run
from mako.template import Template
import query
template = Template('''
<dl>
<dd>Name</dd>
<dt>${merchant.name}</dt>
<dd>Number of bills</dd>
<dt>${merchant.number_of_bills}</dt>
<dd>Total of bills</dd>
<dt>${merchant.total_of_bills}</dt>
</div>
''')
class MerchantWithBilling(object):
def __init__(self, merchant, bills):
self.name = merchant.name
self.number_of_bills = len(bills)
self.total_of_bills = sum(x.amount for x in bills)
@route('/merchants/<merchant_id>')
def get_merchant(merchant_id):
query = Query()
merchant = query.get_merchant(merchant_id)
billing = query.get_billing(merchant_id)
aggregate = MerchantWithBilling(merchant, billing)
return template.render(merchant=aggregate)
if __name__ == '__main__':
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment