def testUsageRequestPayloadMandatory1(self): # f = HTTPTopLevel('users', 'PUT') usage = HTTPUsage('/dummy', 'Bee-bop') payload = Payload() usage.addRequestPayload(payload) field = PayloadField('f1', 'type', 'desc', mandatory=False) payload.addField(field) self.assertFalse(usage.requestPayloadMandatory()) field = PayloadField('f2', 'type', 'desc', mandatory=True) payload.addField(field) self.assertTrue(usage.requestPayloadMandatory())
def TestUsageExamples(self): """ Rather un-exciting test but at least the code is exercised and expected behaviour checked. """ u = HTTPUsage('/dummy', 'an example of great profundity') request = 'foo' response = 'bar' description = 'baz' example = HTTPExample(request, response, description) u.addExample(example) self.assertEqual(1, len(u.examples)) self.assertEqual('foo', u.examples[0].request) self.assertEqual('bar', u.examples[0].response) self.assertEqual('baz', u.examples[0].description)
def testUsageRequestPayloadMandatory2(self): # f = HTTPTopLevel('users', 'PUT') usage = HTTPUsage('/dummy', 'Bee-bop') payload = Payload() usage.addRequestPayload(payload) field = PayloadField('f1', 'type', 'desc', mandatory=False) payload.addField(field) payload = Payload() payload.format = 'blah' usage.addRequestPayload(payload) field = PayloadField('f1', 'type', 'desc', mandatory=False) payload.addField(field) self.assertFalse(usage.requestPayloadMandatory()) payload = JSONPayload() usage.addRequestPayload(payload) field = PayloadField('f1', 'type', 'desc', mandatory=True) payload.addField(field) self.assertTrue(usage.requestPayloadMandatory())
def testNotes(self): f = HTTPTopLevel('users', 'PUT') usage = HTTPUsage('/dummy', 'an example of great profundity') f.addUsage(usage) note = Note('hey') usage.addNote(note) note = Note('hey') usage.addNote(note) self.assertEqual(len(usage.notes), 2) self.reg.register(f) apis = self.reg.get('users', 'PUT') self.assertEqual(apis, [['users', [('PUT', f)]]]) f = apis[0][1][0][1] self.assertEqual(len(f.usages), 1) self.assertEqual(len(f.usages[0].notes), 2)
def testFindUsage(self): class Dummy1(object): pass class Dummy2(object): pass class Dummy3(object): pass f = HTTPTopLevel('users', 'PUT') self.reg.register(f) usage1 = HTTPUsage('', "Return a list of all users.") usage1.resourceClass = Dummy1 f.addUsage(usage1) f = HTTPTopLevel('dummy', 'GET') self.reg.register(f) usage2 = HTTPUsage('', "Return a list of all dummies.") usage2.resourceClass = Dummy2 f.addUsage(usage2) # Find the usage with class Dummy1. u = self.reg.findUsage('users', 'PUT', usageResourceClass=Dummy1) self.assertTrue(u.resourceClass is usage1.resourceClass) # Find the usage with class Dummy2. u = self.reg.findUsage('dummy', 'GET', usageResourceClass=Dummy2) self.assertTrue(u.resourceClass is usage2.resourceClass) # Ask for a non-existent usage class. self.assertRaises(error.NoSuchUsage, self.reg.findUsage, 'dummy', 'GET', usageResourceClass=Dummy3) # Ask for a non-existent toplevel. self.assertRaises(error.NoSuchToplevel, self.reg.findUsage, 'sunny', 'PUT', usageResourceClass=Dummy2) # Ask for a non-existent verb. self.assertRaises(error.NoSuchVerb, self.reg.findUsage, 'dummy', 'PUT', usageResourceClass=Dummy2)
def deferred_render_DELETE(self, request): usage = registry.findUsage(httpTagCategoryName, 'DELETE', TagsResource) registry.checkRequest(usage, request) yield self.facadeClient.deleteTag(self.session, sep.join(request.postpath)) request.setResponseCode(usage.successCode) # ------------------------------ Tags POST -------------------------- topLevel = HTTPTopLevel(httpTagCategoryName, 'POST') registry.register(topLevel) # --- POST /tags/NAMESPACE1/NAMESPACE2 ------------------------ usage = HTTPUsage( apiDoc.NS_NS, 'Add a tag name to a namespace. Intermediate namespaces ' "are created automatically if they don't already exist.") topLevel.addUsage(usage) usage.resourceClass = TagsResource usage.successCode = http.CREATED requestPayload = JSONPayload() requestPayload.addField( PayloadField('name', unicode, 'The name of the new tag.')) requestPayload.addField( PayloadField('description', unicode, 'A description of the tag.', mayBeNone=True)) requestPayload.addField( PayloadField('indexed', bool,
return AboutObjectResource(self.facadeClient, self.session, about) # ------------------------------ About POST ----------------------------- topLevel = HTTPTopLevel(httpAboutCategoryName, 'POST') topLevel.description = "Create a new object." registry.register(topLevel) # --- POST /about ------------------------------------------------------- usage = HTTPUsage('/' + apiDoc.ABOUTSTR, ('''Create a new object with the given about value. If there is already a Fluidinfo object whose ''' + apiDoc.ABOUT_TAG + ''' tag has the given value, the returned object id will be that of the pre-existing object. In this call, and all others with an about value in the URI, you must convert your about value to UTF-8 and then <a href="http://en.wikipedia.org/wiki/Percent-encoding"> percent-encode</a> it before adding it to the request URI. You must provide valid credentials for this call to succeed. For an example see the PUT request, below.''')) topLevel.addUsage(usage) usage.resourceClass = AboutObjectResource usage.successCode = http.CREATED usage.addReturn( Return(apiDoc.BAD_REQUEST, 'The ' + apiDoc.ABOUTSTR + ' argument was not valid UTF-8.')) apiDoc.addBadRequestPayload(usage)
request.setHeader('Content-type', 'application/json') request.setResponseCode(http.OK) returnValue(body) # API DOCUMENTATION # GET on /recent topLevel = HTTPTopLevel('recent', 'GET') topLevel.description = dedent(""" The GET method on recent is used to retrieve information about the latest updated tag values on a given object or user.""") registry.register(topLevel) # GET on /recent/objects usage = HTTPUsage('/objects', dedent(""" To request information on the latest tag values on the objects returned by a given query""")) usage.resourceClass = RecentObjectsActivityResource usage.addArgument(Argument( 'query', dedent(""" A query string specifying what sorts of objects to get recent activity for. The query language is described <a href="http://doc.fluidinfo.com/fluidDB/queries.html">here</a>. You must convert your query to UTF-8 and then <a href="http://en.wikipedia.org/wiki /Percent-encoding"> percent-encode</a> it before adding it to the request URI """), 'string', default=None, mandatory=True))
body = payloads.buildPayload(responseType, responseDict) request.setHeader('Content-length', str(len(body))) request.setHeader('Content-type', responseType) request.setHeader('Location', location) request.setResponseCode(usage.successCode) defer.returnValue(body) # ------------------------------ Users POST ------------------------------- topLevel = HTTPTopLevel(httpUserCategoryName, 'POST') topLevel.adminOnly = True registry.register(topLevel) # --- POST /users --------------------------------------------------------- usage = HTTPUsage('', 'Create a new user.') usage.adminOnly = True usage.resourceClass = UsersResource usage.successCode = http.CREATED topLevel.addUsage(usage) apiDoc.addNeedAdmin(usage, apiDoc.CREATE) usage.addReturn(Return( apiDoc.PRECONDITION_FAILED, 'If the user already exists.')) usage.addReturn(Return( apiDoc.BAD_REQUEST, """If the username is unacceptable due to syntax. Usernames may contain only letters (according to the Unicode standard), digits,
# ------------------------------ Values GET ----------------------------- topLevel = HTTPTopLevel(httpValueCategoryName, 'GET') topLevel.description = """The GET method on values is used to retrieve tag values from objects matching a query.""" # We could here mention # href="http://doc.fluidinfo.com/fluidDB/api/draft-values-spec.html"> # /values draft spec</a>. registry.register(topLevel) # --- GET /values -------------------------------------------------------- usage = HTTPUsage( '', """Search for objects matching a Fluidinfo query, and return the value of the requested tags on the matching objects.""") usage.resourceClass = ValuesResource topLevel.addUsage(usage) usage.addArgument( Argument(queryArg, '''A query string specifying what objects to match. The Fluidinfo query language is described <a href="http://doc.fluidinfo.com/fluidDB/queries.html">here</a>.''', 'string', None, mandatory=True)) usage.addArgument( Argument(tagArg,
registry.checkResponse(responseType, responseDict, usage, request) body = payloads.buildPayload(responseType, responseDict) request.setHeader('Content-length', str(len(body))) request.setHeader('Content-type', responseType) request.setResponseCode(usage.successCode) defer.returnValue(body) # ------------------------------ Objects POST ----------------------------- topLevel = HTTPTopLevel(httpObjectCategoryName, 'POST') topLevel.description = "Create a new Fluidinfo object." registry.register(topLevel) # --- POST /objects ------------------------------------------------------- usage = HTTPUsage('', 'Create a new object. You must provide credentials for ' 'this call to succeed.') topLevel.addUsage(usage) usage.resourceClass = ObjectsResource usage.successCode = http.CREATED apiDoc.addBadRequestPayload(usage) apiDoc.addCannotRespondWithPayload(usage) usage.addReturn(Return(apiDoc.UNAUTHORIZED, 'If valid credentials are not provided.')) usage.addReturn(Return( apiDoc.httpCode(usage.successCode), 'A new object was created without error.'))
body = payloads.buildPayload(responseType, responseDict) request.setHeader('Content-length', str(len(body))) request.setHeader('Content-type', responseType) request.setResponseCode(usage.successCode) defer.returnValue(body) # ------------------------------ Objects POST ----------------------------- topLevel = HTTPTopLevel(httpObjectCategoryName, 'POST') topLevel.description = "Create a new Fluidinfo object." registry.register(topLevel) # --- POST /objects ------------------------------------------------------- usage = HTTPUsage( '', 'Create a new object. You must provide credentials for ' 'this call to succeed.') topLevel.addUsage(usage) usage.resourceClass = ObjectsResource usage.successCode = http.CREATED apiDoc.addBadRequestPayload(usage) apiDoc.addCannotRespondWithPayload(usage) usage.addReturn( Return(apiDoc.UNAUTHORIZED, 'If valid credentials are not provided.')) usage.addReturn( Return(apiDoc.httpCode(usage.successCode), 'A new object was created without error.'))
NamespacesResource) registry.checkRequest(usage, request) yield self.facadeClient.deleteNamespace(self.session, sep.join(request.postpath)) request.setResponseCode(usage.successCode) # ------------------------------ Namespaces POST -------------------------- topLevel = HTTPTopLevel(httpNamespaceCategoryName, 'POST') registry.register(topLevel) # --- POST /namespaces/NAMESPACE1/NAMESPACE2 ------------------------------ usage = HTTPUsage(apiDoc.NS_NS, 'Create a new namespace. Intermediate ' "namespaces are created automatically if they don't already " 'exist.') topLevel.addUsage(usage) usage.resourceClass = NamespacesResource usage.successCode = http.CREATED usage.addNote(Note("""The new namespace will have permissions set according to the user's defaults. There is no permission inheritance in Fluidinfo.""")) usage.addReturn(Return( apiDoc.PRECONDITION_FAILED, 'If the namespace already exists.')) usage.addReturn(Return( apiDoc.NOT_FOUND,
topLevel = HTTPTopLevel(httpValueCategoryName, 'GET') topLevel.description = """The GET method on values is used to retrieve tag values from objects matching a query.""" # We could here mention # href="http://doc.fluidinfo.com/fluidDB/api/draft-values-spec.html"> # /values draft spec</a>. registry.register(topLevel) # --- GET /values -------------------------------------------------------- usage = HTTPUsage( '', """Search for objects matching a Fluidinfo query, and return the value of the requested tags on the matching objects.""") usage.resourceClass = ValuesResource topLevel.addUsage(usage) usage.addArgument(Argument( queryArg, '''A query string specifying what objects to match. The Fluidinfo query language is described <a href="http://doc.fluidinfo.com/fluidDB/queries.html">here</a>.''', 'string', None, mandatory=True)) usage.addArgument(Argument( tagArg,
return AboutObjectResource( self.facadeClient, self.session, about) # ------------------------------ About POST ----------------------------- topLevel = HTTPTopLevel(httpAboutCategoryName, 'POST') topLevel.description = "Create a new object." registry.register(topLevel) # --- POST /about ------------------------------------------------------- usage = HTTPUsage('/' + apiDoc.ABOUTSTR, ('''Create a new object with the given about value. If there is already a Fluidinfo object whose ''' + apiDoc.ABOUT_TAG + ''' tag has the given value, the returned object id will be that of the pre-existing object. In this call, and all others with an about value in the URI, you must convert your about value to UTF-8 and then <a href="http://en.wikipedia.org/wiki/Percent-encoding"> percent-encode</a> it before adding it to the request URI. You must provide valid credentials for this call to succeed. For an example see the PUT request, below.''')) topLevel.addUsage(usage) usage.resourceClass = AboutObjectResource usage.successCode = http.CREATED usage.addReturn(Return( apiDoc.BAD_REQUEST, 'The ' + apiDoc.ABOUTSTR + ' argument was not valid UTF-8.')) apiDoc.addBadRequestPayload(usage)
returnValue(body) # API DOCUMENTATION # GET on /recent topLevel = HTTPTopLevel('recent', 'GET') topLevel.description = dedent(""" The GET method on recent is used to retrieve information about the latest updated tag values on a given object or user.""") registry.register(topLevel) # GET on /recent/objects usage = HTTPUsage( '/objects', dedent(""" To request information on the latest tag values on the objects returned by a given query""")) usage.resourceClass = RecentObjectsActivityResource usage.addArgument( Argument('query', dedent(""" A query string specifying what sorts of objects to get recent activity for. The query language is described <a href="http://doc.fluidinfo.com/fluidDB/queries.html">here</a>. You must convert your query to UTF-8 and then <a href="http://en.wikipedia.org/wiki /Percent-encoding"> percent-encode</a> it before adding it to the request URI """), 'string', default=None,
tag is first created. Use PUT to adjust the permissions on a given namespace or tag. """ # TODO: Finish this sentence and add it to the description: # To change a user's defaults, do a PUT on.... what exactly? registry.register(topLevel) # ------------------------------ Permissions GET -------------------------- topLevel = HTTPTopLevel('permissions', 'GET') registry.register(topLevel) # --- GET /permissions/namespaces/NAMESPACE1/NAMESPACE2 ------------ usage = HTTPUsage( '/' + httpNamespaceCategoryName + apiDoc.NS_NS, """Get the permissions on a namespace: the open/closed policy, and the set of exceptions to the policy.""") usage.resourceClass = ConcreteNamespacePermissionResource topLevel.addUsage(usage) possibleActions = ', '.join(permissions.actionsByCategory[ namespaceCategoryName]) usage.addArgument(Argument( actionArg, """The action whose permissions information is sought. Possible values are: """ + possibleActions + '.', 'string', mandatory=True)) apiDoc.addMissingIntermediateNs(usage)
usage = registry.findUsage(httpTagCategoryName, 'DELETE', TagsResource) registry.checkRequest(usage, request) yield self.facadeClient.deleteTag(self.session, sep.join(request.postpath)) request.setResponseCode(usage.successCode) # ------------------------------ Tags POST -------------------------- topLevel = HTTPTopLevel(httpTagCategoryName, 'POST') registry.register(topLevel) # --- POST /tags/NAMESPACE1/NAMESPACE2 ------------------------ usage = HTTPUsage(apiDoc.NS_NS, 'Add a tag name to a namespace. Intermediate namespaces ' "are created automatically if they don't already exist.") topLevel.addUsage(usage) usage.resourceClass = TagsResource usage.successCode = http.CREATED requestPayload = JSONPayload() requestPayload.addField(PayloadField( 'name', unicode, 'The name of the new tag.')) requestPayload.addField(PayloadField( 'description', unicode, 'A description of the tag.', mayBeNone=True)) requestPayload.addField(PayloadField( 'indexed', bool, 'Whether or not tag values should be indexed.')) usage.addRequestPayload(requestPayload)
usage = registry.findUsage(httpNamespaceCategoryName, 'DELETE', NamespacesResource) registry.checkRequest(usage, request) yield self.facadeClient.deleteNamespace(self.session, sep.join(request.postpath)) request.setResponseCode(usage.successCode) # ------------------------------ Namespaces POST -------------------------- topLevel = HTTPTopLevel(httpNamespaceCategoryName, 'POST') registry.register(topLevel) # --- POST /namespaces/NAMESPACE1/NAMESPACE2 ------------------------------ usage = HTTPUsage( apiDoc.NS_NS, 'Create a new namespace. Intermediate ' "namespaces are created automatically if they don't already " 'exist.') topLevel.addUsage(usage) usage.resourceClass = NamespacesResource usage.successCode = http.CREATED usage.addNote( Note("""The new namespace will have permissions set according to the user's defaults. There is no permission inheritance in Fluidinfo.""")) usage.addReturn( Return(apiDoc.PRECONDITION_FAILED, 'If the namespace already exists.')) usage.addReturn( Return(
POST is not supported on permissions, because permissions are automatically set from a user's default permissions when a namespace or tag is first created. Use PUT to adjust the permissions on a given namespace or tag. """ # TODO: Finish this sentence and add it to the description: # To change a user's defaults, do a PUT on.... what exactly? registry.register(topLevel) # ------------------------------ Permissions GET -------------------------- topLevel = HTTPTopLevel('permissions', 'GET') registry.register(topLevel) # --- GET /permissions/namespaces/NAMESPACE1/NAMESPACE2 ------------ usage = HTTPUsage( '/' + httpNamespaceCategoryName + apiDoc.NS_NS, """Get the permissions on a namespace: the open/closed policy, and the set of exceptions to the policy.""") usage.resourceClass = ConcreteNamespacePermissionResource topLevel.addUsage(usage) possibleActions = ', '.join( permissions.actionsByCategory[namespaceCategoryName]) usage.addArgument( Argument(actionArg, """The action whose permissions information is sought. Possible values are: """ + possibleActions + '.', 'string', mandatory=True)) apiDoc.addMissingIntermediateNs(usage)