operations.rst 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. ****************
  2. Named operations
  3. ****************
  4. Entries and collections support named operations: one-off
  5. functionality that's been given a name and a set of parameters.
  6. >>> from lazr.restfulclient.tests.example import CookbookWebServiceClient
  7. >>> service = CookbookWebServiceClient()
  8. Arguments to named operations are automatically converted to JSON for
  9. transmission over the wire. Here's a named operation that takes a
  10. boolean argument.
  11. >>> [recipe for recipe in service.cookbooks.find_recipes(
  12. ... search="Chicken", vegetarian=True)]
  13. []
  14. Strings that happen to be numbers are handled properly. Here, if "1.234"
  15. were converted into a number at any point in the chain, the 'search'
  16. operation on the server wouldn't know how to handle it and the request
  17. would fail.
  18. >>> [people for people in service.cookbooks.find_recipes(search="1.234")]
  19. []
  20. Counts
  21. ------
  22. Named operations that return a collection return either a link that
  23. lazr.restfulclient can follow to get the size of the collection or
  24. (under some circumstances) the length itself. The len() function
  25. hides this indirection from the end-user.
  26. >>> results = service.cookbooks.find_recipes(search="Chicken")
  27. >>> print len(results)
  28. 0
  29. Special data types
  30. ------------------
  31. lazr.restfulclient uses some data types that don't directly correspond
  32. to JSON data types. These data types can be used in named
  33. operations. For instance, a named operation can take a date or
  34. datetime object as one of its arguments.
  35. >>> import datetime
  36. >>> date = datetime.datetime(1994, 1, 1)
  37. >>> cookbook = service.cookbooks.create(
  38. ... name="New cookbook", cuisine="General",
  39. ... copyright_date=date, price=1.23, last_printing=date)
  40. >>> print cookbook.name
  41. New cookbook
  42. A named operation can take an entry as one of its arguments.
  43. lazr.restfulclient lets you pass in the actual entry as the argument
  44. value.
  45. >>> dish = service.recipes[1].dish
  46. >>> cookbook = service.recipes[1].cookbook
  47. >>> print cookbook.find_recipe_for(dish=dish)
  48. http://cookbooks.dev/1.0/recipes/1
  49. A named operation can take binary data as one of its arguments.
  50. >>> cookbook.replace_cover(cover="\x00\xe2\xe3")
  51. >>> cookbook.cover.open().read()
  52. '\x00\xe2\xe3'
  53. A named operation that returns a null value corresponds to a Python
  54. value of None.
  55. >>> dish = service.recipes[4].dish
  56. >>> print cookbook.find_recipe_for(dish=dish)
  57. None
  58. A named operation may change the resource's location so we get a 301 response
  59. with the new URL.
  60. >>> from urllib import quote
  61. >>> from lazr.restful.testing.webservice import WebServiceCaller
  62. >>> webservice = WebServiceCaller(domain='cookbooks.dev')
  63. >>> url = quote("/cookbooks/New cookbook")
  64. >>> print webservice.named_post(url, 'make_more_interesting')
  65. HTTP/1.1 301 Moved Permanently
  66. ...
  67. Location: http://cookbooks.dev/devel/cookbooks/The%20New%20New%20cookbook
  68. ...
  69. JSON-encoding
  70. -------------
  71. lazr.restfulclient encodes most arguments (even string arguments) as
  72. JSON before sending them over the wire. This way, a named operation
  73. that takes a string argument can take a string that looks like a JSON
  74. object without causing confusion.
  75. >>> cookbooks = service.cookbooks.find_for_cuisine(cuisine="General")
  76. >>> len([cookbook for cookbook in cookbooks]) > 0
  77. True
  78. >>> cookbook = service.cookbooks.create(
  79. ... name="null", cuisine="General",
  80. ... copyright_date=date, price=1.23, last_printing=date)
  81. >>> cookbook.name
  82. u'null'
  83. >>> cookbook = service.cookbooks.create(
  84. ... name="4.56", cuisine="General",
  85. ... copyright_date=date, price=1.23, last_printing=date)
  86. >>> cookbook.name
  87. u'4.56'
  88. >>> cookbook = service.cookbooks.create(
  89. ... name='"foo"', cuisine="General",
  90. ... copyright_date=date, price=1.23, last_printing=date)
  91. >>> cookbook.name
  92. u'"foo"'
  93. A named operation that takes a non-string object (such as a float)
  94. will not accept a string that's the JSON representation of the
  95. object.
  96. >>> try:
  97. ... service.cookbooks.create(
  98. ... name="Yet another 1.23 cookbook", cuisine="General",
  99. ... copyright_date=date, last_printing=date, price="1.23")
  100. ... except Exception, e:
  101. ... print e.content
  102. price: got 'unicode', expected float, int: u'1.23'
  103. Named operations on collections don't fetch the collections
  104. -----------------------------------------------------------
  105. If you invoke a named operation on a collection, the only HTTP request
  106. made is the one for the named operation. You don't have to get a
  107. representation of the collection to invoke the operation.
  108. >>> import httplib2
  109. >>> httplib2.debuglevel = 1
  110. >>> service = CookbookWebServiceClient()
  111. send: ...
  112. ...
  113. >>> print service.cookbooks.find_recipes(
  114. ... search="Chicken", vegetarian=True)
  115. send: 'GET /1.0/cookbooks?...vegetarian=true...'
  116. ...
  117. Cleanup.
  118. >>> httplib2.debuglevel = None