[Checkins] SVN: grokapps/gbepastebin/ rest apis must be hypertext driven

Michael Haubenwallner michael at d2m.at
Sun Oct 26 04:27:48 EDT 2008


Log message for revision 92578:
  rest apis must be hypertext driven

Changed:
  A   grokapps/gbepastebin/CHANGES.txt
  U   grokapps/gbepastebin/setup.py
  U   grokapps/gbepastebin/src/gbepastebin/app.py
  U   grokapps/gbepastebin/src/gbepastebin/app.txt
  U   grokapps/gbepastebin/src/gbepastebin/rest.py
  A   grokapps/gbepastebin/src/gbepastebin/rest.txt

-=-
Added: grokapps/gbepastebin/CHANGES.txt
===================================================================
--- grokapps/gbepastebin/CHANGES.txt	                        (rev 0)
+++ grokapps/gbepastebin/CHANGES.txt	2008-10-26 08:27:46 UTC (rev 92578)
@@ -0,0 +1,9 @@
+CHANGES
+-------
+
+0.1.1   split tests (app.txt, rest.txt)
+        switch to absolute urls for pasteids (rest)
+        see: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
+        remove the delete_pastes method from the rest module
+
+0.1     initial release
\ No newline at end of file

Modified: grokapps/gbepastebin/setup.py
===================================================================
--- grokapps/gbepastebin/setup.py	2008-10-26 05:59:00 UTC (rev 92577)
+++ grokapps/gbepastebin/setup.py	2008-10-26 08:27:46 UTC (rev 92578)
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-version = '0.1'
+version = '0.1.1'
 
 setup(name='gbepastebin',
       version=version,

Modified: grokapps/gbepastebin/src/gbepastebin/app.py
===================================================================
--- grokapps/gbepastebin/src/gbepastebin/app.py	2008-10-26 05:59:00 UTC (rev 92577)
+++ grokapps/gbepastebin/src/gbepastebin/app.py	2008-10-26 08:27:46 UTC (rev 92578)
@@ -7,40 +7,40 @@
 class Application(grok.Application, grok.Container):
     
     display_limit=10
-    version=0.1
+    version='0.1.1'
     
     def next_id(self):
         keys=[0]
-        keylist=self.store.keys()
+        keylist=self['store'].keys()
         if keylist:
             keys=[int(key) for key in keylist]
         keys.sort()
         return str(int(keys[-1])+1)
 
     def get_paste(self, pasteid):
-        return self.store.get(pasteid)
+        return self['store'].get(pasteid)
     
     def add_paste(self, paste):
         pasteid=self.next_id()
         paste.pasteid=pasteid
-        self.store[pasteid]=paste
+        self['store'][pasteid]=paste
         return pasteid
     
     def delete_paste(self, pasteid):
         if self.get_paste(pasteid):
-            del self.store[pasteid]
+            del self['store'][pasteid]
             return True
         return False
         
     def list_pastes(self, max=display_limit):
-        keylist=self.store.keys()
+        keylist=self['store'].keys()
         keys=[int(key) for key in keylist]
         keys.sort()
         keys.reverse()
         return [self.get_paste(str(key)) for key in keys[:max]]
     
     def list_pasteids(self):
-        return list(self.store.keys())
+        return list(self['store'].keys())
         
     def delete_pastes(self, pastelist):
         success=True
@@ -51,5 +51,5 @@
 
 @grok.subscribe(Application, grok.IObjectAddedEvent)
 def handle(obj, event):
-    #obj.store=volatile_pastebin()
-    obj.store=pastebin()
+    #obj['store']=volatile_pastebin()
+    obj['store']=pastebin()

Modified: grokapps/gbepastebin/src/gbepastebin/app.txt
===================================================================
--- grokapps/gbepastebin/src/gbepastebin/app.txt	2008-10-26 05:59:00 UTC (rev 92577)
+++ grokapps/gbepastebin/src/gbepastebin/app.txt	2008-10-26 08:27:46 UTC (rev 92578)
@@ -91,55 +91,3 @@
    True
    >>> show_pastebin()
    []
-   
-   
-
-Test the REST views
--------------------
-
-Add a few pastes and list the Pastebin contents:
-
-   >>> import simplejson
-   >>> for paste in range(3):
-   ...     browser.open('http://localhost/++rest++json/app/', 'author_name=name&paste=text&language=python')
-   >>> browser.open('http://localhost/++rest++json/app/')
-   >>> simplejson.loads(browser.contents)
-   [u'1', u'2', u'3']
-   
-Delete Paste #2 (Deletions must be authenticated):
-
-   >>> from grok.ftests.test_grok_functional import http_call
-   >>> response = http_call('DELETE', 'http://localhost/++rest++json/app/2')
-   Traceback (most recent call last):
-   ...
-   Unauthorized: (<grok.meta.JSONPaste ...>, '__call__', 'gbepastebin.manage')
-   >>> response = http_call('DELETE', 'http://localhost/++rest++json/app/2',Authorization='Basic mgr:mgrpw')
-   >>> simplejson.loads(response.getBody())
-   True
-   
-Delete it again:
-
-   >>> response = http_call('DELETE', 'http://localhost/++rest++json/app/2',Authorization='Basic mgr:mgrpw')
-   Traceback (most recent call last):
-   ...
-   NotFound: Object: <gbepastebin.app.Application object at ...>, name: u'2'
-    
-Delete all Pastes:
-
-   >>> response = http_call('DELETE', 'http://localhost/++rest++json/app/',Authorization='Basic mgr:mgrpw')
-   >>> simplejson.loads(response.getBody())
-   True
-   
-Show the Pastebin contents.
-
-   >>> browser.open('http://localhost/++rest++json/app/')
-   >>> simplejson.loads(browser.contents)
-   []
-   
-Test the 'languages' command:
-
-   >>> browser.open('http://localhost/++rest++json/app/languages')
-   >>> ['python', 'Python'] in simplejson.loads(browser.contents)
-   True
-   
-   
\ No newline at end of file

Modified: grokapps/gbepastebin/src/gbepastebin/rest.py
===================================================================
--- grokapps/gbepastebin/src/gbepastebin/rest.py	2008-10-26 05:59:00 UTC (rev 92577)
+++ grokapps/gbepastebin/src/gbepastebin/rest.py	2008-10-26 08:27:46 UTC (rev 92578)
@@ -14,7 +14,6 @@
 ----------- ------- ----------------------- ------------------------ ---------            
 /           GET     list all pastes         ['pasteid', ...]         Anonymous
 /           POST    add new paste           'pasteid'                Anonymous
-/           DELETE  delete all pastes       Boolean                  Manager
 /<id>       GET     return paste (id)       Paste                    Anonymous
 /<id>       DELETE  delete paste (id)       Boolean                  Manager
 /languages  GET     list languages          [('alias', 'name'), ...] Anonymous
@@ -31,7 +30,10 @@
 class BaseApplication(object):
     
     def list_pastes(self):
-        return self.context.list_pasteids()
+        pasteids=self.context.list_pasteids()
+        site=grok.getSite()
+        site_url=grok.url(self.request,site)
+        return ['%s/%s' % (site_url, pasteid) for pasteid in pasteids]
     
     def add_paste(self):
         author_name=self.request.get('author_name')
@@ -41,7 +43,7 @@
         return self.context.add_paste(paste_obj)
     
     def delete_pastes(self):
-        pastelist=self.list_pastes()
+        pastelist=self.list_pasts()
         return self.context.delete_pastes(pastelist)
         
 class JSONApplication(grok.REST, BaseApplication):
@@ -54,10 +56,6 @@
     def POST(self):
         return simplejson.dumps(self.add_paste())
 
-    @grok.require('gbepastebin.manage')
-    def DELETE(self):
-        return simplejson.dumps(self.delete_pastes())
-
 class Utils(grok.Model):
     
     def list_languages(self):

Added: grokapps/gbepastebin/src/gbepastebin/rest.txt
===================================================================
--- grokapps/gbepastebin/src/gbepastebin/rest.txt	                        (rev 0)
+++ grokapps/gbepastebin/src/gbepastebin/rest.txt	2008-10-26 08:27:46 UTC (rev 92578)
@@ -0,0 +1,73 @@
+Do a functional doctest test on the app.
+========================================
+
+:Test-Layer: functional
+
+
+Test the REST views
+-------------------
+
+Let's first create an instance of gbepastebin at the top level:
+
+   >>> from gbepastebin.app import Application
+   >>> from gbepastebin.paste import Paste
+   >>> root = getRootFolder()
+   >>> root['app'] = app = Application()
+
+Create a browser and visit the instance you just created:
+
+   >>> from zope.testbrowser.testing import Browser
+   >>> browser = Browser()
+
+
+Add a few pastes and list the Pastebin contents:
+
+   >>> import simplejson
+   >>> for paste in range(3):
+   ...     browser.open('http://localhost/++rest++json/app/', 'author_name=name&paste=text&language=python')
+   >>> browser.open('http://localhost/++rest++json/app/')
+   >>> sorted(simplejson.loads(browser.contents))
+   [u'http://localhost/++rest++json/app/1', u'http://localhost/++rest++json/app/2', u'http://localhost/++rest++json/app/3']
+   
+Delete Paste #2 (Deletions must be authenticated):
+
+   >>> from grok.ftests.test_grok_functional import http_call
+   >>> response = http_call('DELETE', 'http://localhost/++rest++json/app/2')
+   Traceback (most recent call last):
+   ...
+   Unauthorized: (<grok.meta.JSONPaste ...>, '__call__', 'gbepastebin.manage')
+   >>> response = http_call('DELETE', 'http://localhost/++rest++json/app/2',Authorization='Basic mgr:mgrpw')
+   >>> simplejson.loads(response.getBody())
+   True
+   
+Delete it again:
+
+   >>> response = http_call('DELETE', 'http://localhost/++rest++json/app/2',Authorization='Basic mgr:mgrpw')
+   Traceback (most recent call last):
+   ...
+   NotFound: Object: <gbepastebin.app.Application object at ...>, name: u'2'
+    
+Delete all Pastes:
+
+   >>> browser.open('http://localhost/++rest++json/app/')
+   >>> pastes = simplejson.loads(browser.contents)
+   >>> response = True
+   >>> for paste in pastes:
+   ...    res = http_call('DELETE', paste, Authorization='Basic mgr:mgrpw')
+   ...    response = response and simplejson.loads(res.getBody())
+   >>> response
+   True
+   
+Show the Pastebin contents.
+
+   >>> browser.open('http://localhost/++rest++json/app/')
+   >>> simplejson.loads(browser.contents)
+   []
+   
+Test the 'languages' command:
+
+   >>> browser.open('http://localhost/++rest++json/app/languages')
+   >>> ['python', 'Python'] in simplejson.loads(browser.contents)
+   True
+   
+   
\ No newline at end of file



More information about the Checkins mailing list