Skip to content

Commit 5f2fb5a

Browse files
committed
Set up basic framework for handling versioning of interface.
Version order: 1) accept header version=X specifier application/vnd.x.y; version=1 2) from type in accept-header type/subtype-vX application/vnd.x.y-v1 3) from @Apiver in query string to make browser use easy Make parse_accept_header pass back version info as string rather than as float. This allows dispatch to handle interpretation of the version string. Also set __default_api_version and __supported_api_versions on RestfulInstance class. Use them in RestfulInstance describe method invoked on a get of /rest. Also fix url in documentation. /rest/issue.json -> /rest/data/issue.json
1 parent 660015a commit 5f2fb5a

File tree

1 file changed

+52
-4
lines changed

1 file changed

+52
-4
lines changed

roundup/rest.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def parse_accept_header(accept):
209209
# add the version as a media param
210210
try:
211211
version = media_params.append(('version',
212-
float(rest)))
212+
rest))
213213
except ValueError:
214214
version = 1.0 # could not be parsed
215215
# add the vendor code as a media param
@@ -324,6 +324,9 @@ class RestfulInstance(object):
324324
}
325325
__default_accept_type = "json"
326326

327+
__default_api_version = 1
328+
__supported_api_versions = [ 1 ]
329+
327330
def __init__(self, client, db):
328331
self.client = client
329332
self.db = db
@@ -477,6 +480,11 @@ def format_item(self, node, item_id, props=None, verbose=1):
477480
'''
478481
uid = self.db.getuid()
479482
class_name = node.cl.classname
483+
if self.api_version == None:
484+
version = self.__default_api_version
485+
else:
486+
version = self.api_version
487+
480488
result = {}
481489
try:
482490
# pn = propname
@@ -1329,8 +1337,8 @@ def option_attribute(self, class_name, item_id, attr_name, input):
13291337
def describe(self, input):
13301338
"""Describe the rest endpoint"""
13311339
result = {
1332-
"default_version": "1",
1333-
"supported_versions": [ "1" ],
1340+
"default_version": self.__default_api_version,
1341+
"supported_versions": self.__supported_api_versions,
13341342
"links": [ { "uri": self.base_path +"/summary",
13351343
"rel": "summary"},
13361344
{ "uri": self.base_path,
@@ -1442,12 +1450,52 @@ def dispatch(self, method, uri, input):
14421450
# parse Accept header and get the content type
14431451
accept_header = parse_accept_header(headers.get('Accept'))
14441452
accept_type = "invalid"
1453+
self.api_version = None
14451454
for part in accept_header:
14461455
if part[0] in self.__accepted_content_type:
14471456
accept_type = self.__accepted_content_type[part[0]]
1457+
# Version order:
1458+
# 1) accept header version=X specifier
1459+
# application/vnd.x.y; version=1
1460+
# 2) from type in accept-header type/subtype-vX
1461+
# application/vnd.x.y-v1
1462+
# 3) from @apiver in query string to make browser
1463+
# use easy
1464+
# This code handles 1 and 2. Set api_version to none
1465+
# to trigger @apiver parsing below
1466+
# Places that need the api_version info should
1467+
# use default if version = None
1468+
try:
1469+
self.api_version = int(part[1]['version'])
1470+
except KeyError:
1471+
self.api_version = None
1472+
except ValueError:
1473+
msg=( "Unrecognized version: %s. "
1474+
"See /rest without specifying version "
1475+
"for supported versions."%(
1476+
part[1]['version']))
1477+
output = self.error_obj(400, msg)
1478+
1479+
# check for @apiver in query string
1480+
try:
1481+
if not self.api_version:
1482+
self.api_version = int(input['@apiver'].value)
1483+
except KeyError:
1484+
self.api_version = None
1485+
except ValueError:
1486+
msg=( "Unrecognized version: %s. "
1487+
"See /rest without specifying version "
1488+
"for supported versions."%(
1489+
input['@apiver'].value))
1490+
output = self.error_obj(400, msg)
1491+
1492+
# FIXME: do we need to raise an error if client did not specify
1493+
# version? This may be a good thing to require. Note that:
1494+
# Accept: application/json; version=1 may not be legal but....
1495+
14481496

14491497
# get the request format for response
1450-
# priority : extension from uri (/rest/issue.json),
1498+
# priority : extension from uri (/rest/data/issue.json),
14511499
# header (Accept: application/json, application/xml)
14521500
# default (application/json)
14531501
ext_type = os.path.splitext(urlparse(uri).path)[1][1:]

0 commit comments

Comments
 (0)