Added support for URLs with many parameters e.g. max-liked, max-results and max-comments. I'm not checking in the functional tests I'm using since I still haven't fixed the problem of getting back a usable list of JSON objects for pagination.

This commit is contained in:
ade@google.com
2010-08-20 23:24:56 +01:00
parent ce4e4c70cc
commit 850cf55b11
3 changed files with 58 additions and 31 deletions

View File

@@ -22,6 +22,7 @@ __author__ = 'jcgregorio@google.com (Joe Gregorio)'
import httplib2
import logging
import re
import simplejson
import urlparse
@@ -77,17 +78,21 @@ def key2param(key):
class JsonModel(object):
def request(self, headers, params):
model = params.get('body', None)
query = '?alt=json&prettyprint=true'
def request(self, headers, path_params, query_params, body_value):
query = self.build_query(query_params)
headers['accept'] = 'application/json'
if model == None:
return (headers, params, query, None)
if body_value is None:
return (headers, path_params, query, None)
else:
model = {'data': model}
model = {'data': body_value}
headers['content-type'] = 'application/json'
del params['body']
return (headers, params, query, simplejson.dumps(model))
return (headers, path_params, query, simplejson.dumps(model))
def build_query(self, params):
query = '?alt=json&prettyprint=true'
for key,value in params.iteritems():
query += '&%s=%s' % (key, value)
return query
def response(self, resp, content):
# Error handling is TBD, for example, do we retry
@@ -95,6 +100,7 @@ class JsonModel(object):
if resp.status < 300:
return simplejson.loads(content)['data']
else:
logging.debug('Content from bad request was: %s' % content)
if resp['content-type'] != 'application/json':
raise HttpError('%d %s' % (resp.status, resp.reason))
else:
@@ -107,7 +113,10 @@ def build(service, version, http=httplib2.Http(),
'api': service,
'apiVersion': version
}
resp, content = http.request(uritemplate.expand(discoveryServiceUrl, params))
requested_url = uritemplate.expand(discoveryServiceUrl, params)
logging.info('URL being requested: %s' % requested_url)
resp, content = http.request(requested_url)
d = simplejson.loads(content)
service = d['data'][service][version]
base = service['baseUrl']
@@ -149,45 +158,59 @@ def createResource(http, baseUrl, model, resourceName, resourceDesc):
pathUrl = methodDesc['pathUrl']
pathUrl = re.sub(r'\{', r'{+', pathUrl)
httpMethod = methodDesc['httpMethod']
args = methodDesc['parameters'].keys()
required = [] # Required parameters
pattern = {} # Parameters the must match a regex
argmap = {}
if httpMethod in ['PUT', 'POST']:
argmap['body'] = 'body'
required_params = [] # Required parameters
pattern_params = {} # Parameters that must match a regex
query_params = [] # Parameters that will be used in the query string
path_params = {} # Parameters that will be used in the base URL
for arg, desc in methodDesc['parameters'].iteritems():
param = key2param(arg)
if desc.get('pattern', ''):
pattern[param] = desc['pattern']
if desc.get('required', False):
required.append(param)
argmap[param] = arg
if httpMethod in ['PUT', 'POST']:
args.append('body')
argmap = dict([(key2param(key), key) for key in args])
if desc.get('pattern', ''):
pattern_params[param] = desc['pattern']
if desc.get('required', False):
required_params.append(param)
if desc.get('parameterType') == 'query':
query_params.append(param)
if desc.get('parameterType') == 'path':
path_params[param]=param
def method(self, **kwargs):
for name in kwargs.iterkeys():
if name not in argmap:
raise TypeError('Got an unexpected keyword argument "%s"' % name)
for name in required:
for name in required_params:
if name not in kwargs:
raise TypeError('Missing required parameter "%s"' % name)
for name, regex in pattern.iteritems():
for name, regex in pattern_params.iteritems():
if name in kwargs:
if re.match(regex, kwargs[name]) is None:
raise TypeError('Parameter "%s" value "%s" does not match the pattern "%s"' % (name, kwargs[name], regex))
params = {}
actual_query_params = {}
actual_path_params = {}
for key, value in kwargs.iteritems():
params[argmap[key]] = value
if key in query_params:
actual_query_params[argmap[key]] = value
if key in path_params:
actual_path_params[argmap[key]] = value
body_value = kwargs.get('body', None)
headers = {}
headers, params, query, body = self._model.request(headers, params)
headers, params, query, body = self._model.request(headers, actual_path_params, actual_query_params, body_value)
url = urlparse.urljoin(self._baseUrl,
uritemplate.expand(pathUrl, params) + query)
expanded_url = uritemplate.expand(pathUrl, params)
url = urlparse.urljoin(self._baseUrl, expanded_url + query)
logging.info('URL being requested: %s' % url)
resp, content = self._http.request(
url, method=httpMethod, headers=headers, body=body)

View File

@@ -61,7 +61,7 @@ class Discovery(unittest.TestCase):
except TypeError, e:
self.assertTrue('unexpected' in str(e))
def test_resources(self):
def test_buzz_resources(self):
self.http = HttpMock('buzz.json', {'status': '200'})
buzz = build('buzz', 'v1', self.http)
self.assertTrue(getattr(buzz, 'activities'))

View File

@@ -19,9 +19,11 @@ class Model(unittest.TestCase):
model = JsonModel()
headers = {}
params = {}
path_params = {}
query_params = {}
body = None
headers, params, query, body = model.request(headers, params)
headers, params, query, body = model.request(headers, path_params, query_params, body)
self.assertEqual(headers['accept'], 'application/json')
self.assertTrue('content-type' not in headers)
@@ -32,9 +34,11 @@ class Model(unittest.TestCase):
model = JsonModel()
headers = {}
params = {'body': {}}
path_params = {}
query_params = {}
body = {}
headers, params, query, body = model.request(headers, params)
headers, params, query, body = model.request(headers, path_params, query_params, body)
self.assertEqual(headers['accept'], 'application/json')
self.assertEqual(headers['content-type'], 'application/json')