diff roundup/rest.py @ 5685:4b4885f0c6ad

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
author John Rouillard <rouilj@ieee.org>
date Sun, 31 Mar 2019 21:23:33 -0400
parents e8ac82b8d074
children eb51c0d9c9bf
line wrap: on
line diff
--- a/roundup/rest.py	Sat Mar 30 21:15:33 2019 -0400
+++ b/roundup/rest.py	Sun Mar 31 21:23:33 2019 -0400
@@ -209,7 +209,7 @@
                         # add the version as a media param
                         try:
                             version = media_params.append(('version',
-                                                           float(rest)))
+                                                           rest))
                         except ValueError:
                             version = 1.0  # could not be parsed
                 # add the vendor code as a media param
@@ -324,6 +324,9 @@
     }
     __default_accept_type = "json"
 
+    __default_api_version = 1
+    __supported_api_versions = [ 1 ]
+
     def __init__(self, client, db):
         self.client = client
         self.db = db
@@ -477,6 +480,11 @@
         '''
         uid = self.db.getuid()
         class_name = node.cl.classname
+        if self.api_version == None:
+            version = self.__default_api_version
+        else:
+            version = self.api_version
+
         result = {}
         try:
             # pn = propname
@@ -1329,8 +1337,8 @@
     def describe(self, input):
         """Describe the rest endpoint"""
         result = {
-            "default_version": "1",
-            "supported_versions": [ "1" ],
+            "default_version": self.__default_api_version,
+            "supported_versions": self.__supported_api_versions,
             "links": [ { "uri": self.base_path +"/summary",
                         "rel": "summary"},
                        { "uri": self.base_path,
@@ -1442,12 +1450,52 @@
         # parse Accept header and get the content type
         accept_header = parse_accept_header(headers.get('Accept'))
         accept_type = "invalid"
+        self.api_version = None
         for part in accept_header:
             if part[0] in self.__accepted_content_type:
                 accept_type = self.__accepted_content_type[part[0]]
+                # 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
+                # This code handles 1 and 2. Set api_version to none
+                # to trigger @apiver parsing below
+                # Places that need the api_version info should
+                # use default if version = None
+                try:
+                    self.api_version = int(part[1]['version'])
+                except KeyError:
+                    self.api_version = None
+                except ValueError:
+                    msg=( "Unrecognized version: %s. "
+                          "See /rest without specifying version "
+                          "for supported versions."%(
+                              part[1]['version']))
+                    output = self.error_obj(400, msg)
+
+        # check for @apiver in query string
+        try:
+            if not self.api_version:
+                self.api_version = int(input['@apiver'].value)
+        except KeyError:
+            self.api_version = None
+        except ValueError:
+            msg=( "Unrecognized version: %s. "
+                  "See /rest without specifying version "
+                  "for supported versions."%(
+                      input['@apiver'].value))
+            output = self.error_obj(400, msg)
+
+        # FIXME: do we need to raise an error if client did not specify
+        # version? This may be a good thing to require. Note that:
+        # Accept: application/json; version=1 may not be legal but....
+        
 
         # get the request format for response
-        # priority : extension from uri (/rest/issue.json),
+        # priority : extension from uri (/rest/data/issue.json),
         #            header (Accept: application/json, application/xml)
         #            default (application/json)
         ext_type = os.path.splitext(urlparse(uri).path)[1][1:]

Roundup Issue Tracker: http://roundup-tracker.org/