PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/docs/customizing.rst

https://bitbucket.org/jonasteuwen/flask-restless
ReStructuredText | 281 lines | 198 code | 83 blank | 0 comment | 0 complexity | 07a634e1a1ba63284a03a375ef5569ee MD5 | raw file
  1. .. _customizing:
  2. .. currentmodule:: flask.ext.restless
  3. Customizing the ReSTful interface
  4. =================================
  5. HTTP methods
  6. ~~~~~~~~~~~~
  7. By default, the :meth:`APIManager.create_api` method creates a read-only
  8. interface; requests with HTTP methods other than :http:method:`GET` will cause
  9. a response with :http:statuscode:`405`. To explicitly specify which methods
  10. should be allowed for the endpoint, pass a list as the value of keyword
  11. argument ``methods``::
  12. apimanager.create_api(Person, methods=['GET', 'POST', 'DELETE'])
  13. This creates an endpoint at ``/api/person`` which responds to
  14. :http:method:`get`, :http:method:`post`, and :http:method:`delete` methods, but
  15. not to other ones like :http:method:`put` or :http:method:`patch`.
  16. The recognized HTTP methods and their semantics are described below (assuming
  17. you have created an API for an entity ``Person``). All endpoints which respond
  18. with data respond with serialized JSON strings.
  19. .. http:get:: /api/person
  20. Returns a list of all ``Person`` instances.
  21. .. http:get:: /api/person/(int:id)
  22. Returns a single ``Person`` instance with the given ``id``.
  23. .. http:get:: /api/person?q=<searchjson>
  24. Returns a list of all ``Person`` instances which match the search query
  25. specified in the query parameter ``q``. For more information on searching,
  26. see :ref:`searchformat`.
  27. .. http:delete:: /api/person/(int:id)
  28. Deletes the person with the given ``id`` and returns :http:statuscode:`204`.
  29. .. http:post:: /api/person
  30. Creates a new person in the database and returns its ``id``. The initial
  31. attributes of the ``Person`` are read as JSON from the body of the
  32. request. For information about the format of this request, see
  33. :ref:`requestformat`.
  34. .. http:patch:: /api/person/(int:id)
  35. Updates the attributes of the ``Person`` with the given ``id``. The
  36. attributes are read as JSON from the body of the request. For information
  37. about the format of this request, see :ref:`requestformat`.
  38. .. http:patch:: /api/person
  39. This is only available if the ``allow_patch_many`` keyword argument is set
  40. to ``True`` when calling the :meth:`~APIManager.create_api` method. For more
  41. information, see :ref:`allowpatchmany`.
  42. Updates the attributes of all ``Person`` instances. The attributes are read
  43. as JSON from the body of the request. For information about the format of
  44. this request, see :ref:`requestformat`.
  45. .. http:put:: /api/person
  46. .. http:put:: /api/person/(int:id)
  47. Aliases for :http:patch:`/api/person` and
  48. :http:patch:`/api/person/(int:id)`.
  49. API prefix
  50. ~~~~~~~~~~
  51. To create an API at a different prefix, use the ``url_prefix`` keyword
  52. argument::
  53. apimanager.create_api(Person, url_prefix='/api/v2')
  54. Then your API for ``Person`` will be available at ``/api/v2/person``.
  55. Collection name
  56. ~~~~~~~~~~~~~~~
  57. By default, the name of the collection which appears in the URLs of the API
  58. will be the name of the table which backs your model. If your model is a
  59. SQLAlchemy model, this will be the value of ``__tablename__``. If your model is
  60. a Flask-SQLAlchemy model, this will be the lowercase name of the model with
  61. ``CamelCase`` changed to ``camel_case``.
  62. To provide a different name for the model, provide a string to the
  63. `collection_name` keyword argument of the :meth:`APIManager.create_api`
  64. method::
  65. apimanager.create_api(Person, collection_name='people')
  66. Then the API will be exposed at ``/api/people`` instead of ``/api/person``.
  67. .. _allowpatchmany:
  68. Enable patching all instances
  69. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  70. By default, a :http:patch:`/api/person` request (note the missing ID) will
  71. cause a :http:statuscode:`405` response. By setting the ``allow_patch_many``
  72. keyword argument of the :meth:`APIManager.create_api` method to be ``True``,
  73. :http:patch:`/api/person` requests will patch the provided attributes on all
  74. instances of ``Person``::
  75. apimanager.create_api(Person, allow_patch_many=True)
  76. .. _validation:
  77. Capturing validation errors
  78. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  79. By default, no validation is performed by Flask-Restless; if you want
  80. validation, implement it yourself in your database models. However, by
  81. specifying a list of exceptions raised by your backend on validation errors,
  82. Flask-Restless will forward messages from raised exceptions to the client in an
  83. error response.
  84. A reasonable validation framework you might use for this purpose is `SQLAlchemy
  85. Validation <https://bitbucket.org/rsyring/sqlalchemy-validation>`_. You can
  86. also use the :func:`~sqlalchemy.orm.validates` decorator that comes with
  87. SQLAlchemy.
  88. For example, if your validation framework includes an exception called
  89. ``ValidationError``, then call the :meth:`APIManager.create_api` method with
  90. the ``validation_exceptions`` keyword argument::
  91. from cool_validation_framework import ValidationError
  92. apimanager.create_api(Person, validation_exceptions=[ValidationError])
  93. .. note::
  94. Currently, Flask-Restless expects that an instance of a specified validation
  95. error will have a ``errors`` attribute, which is a dictionary mapping field
  96. name to error description (note: one error per field). If you have a better,
  97. more general solution to this problem, please visit `our issue tracker
  98. <https://github.com/jfinkels/flask-restless/issues>`_.
  99. Now when you make :http:method:`post` and :http:method:`patch` requests with
  100. invalid fields, the JSON response will look like this:
  101. .. sourcecode:: http
  102. HTTP/1.1 400 Bad Request
  103. { "validation_errors":
  104. {
  105. "age": "Must be an integer",
  106. }
  107. }
  108. Currently, Flask-Restless can only forward one exception at a time to the
  109. client.
  110. Exposing evaluation of SQL functions
  111. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  112. If the ``allow_functions`` keyword argument is set to ``True`` when creating an
  113. API for a model using :meth:`APIManager.create_api`, then an endpoint will be
  114. made available for :http:get:`/api/eval/person` which responds to requests for
  115. evaluation of functions on all instances the model.
  116. For information about the request and response formats for this endpoint, see
  117. :ref:`functionevaluation`.
  118. .. _authentication:
  119. Specifying which columns are provided in responses
  120. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  121. By default, all columns of your model will be exposed by the API. If the
  122. ``include_columns`` keyword argument is an iterable of strings, *only* columns
  123. with those names (that is, the strings represent the names of attributes of the
  124. model which are ``Column`` objects) will be provided in JSON responses for
  125. :http:method:`get` requests.
  126. For example, if your model is defined like this (using Flask-SQLAlchemy)::
  127. class Person(db.Model):
  128. id = db.Column(db.Integer, primary_key=True)
  129. name = db.Column(db.Unicode, unique=True)
  130. birth_date = db.Column(db.Date)
  131. computers = db.relationship('Computer')
  132. and you want your JSON responses to include only the values of the ``name`` and
  133. ``birth_date`` columns, create your API with the following arguments::
  134. apimanager.create_api(Person, include_columns=['name', 'birth_date'])
  135. Now requests like :http:get:`/api/person/1` will return JSON objects which look
  136. like this:
  137. .. sourcecode:: javascript
  138. {"name": "Jeffrey", "birth_date": "1999-12-31"}
  139. Requiring authentication for some methods
  140. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  141. .. note::
  142. The authentication system in Flask-Restless is relatively simple, but since
  143. I suspect it is a common requirement for ReSTful APIs, suggestions,
  144. comments, and pull requests are much appreciated. Please visit `our issue
  145. tracker <https://github.com/jfinkels/flask-restless/issues>`_.
  146. If you want certain HTTP methods to require authentication, use the
  147. ``authentication_required_for`` and ``authentication_function`` keyword
  148. arguments to the :meth:`APIManager.create_api` method. If you specify the
  149. former, you must also specify the latter.
  150. ``authentication_required_for`` is the list of HTTP method names which will
  151. require authentication and ``authentication_function`` is a function with zero
  152. arguments which returns ``True`` if and only if the client making the request
  153. has been authenticated. This function can really be anything you like, but
  154. presumably it will have something to do with your authentication framework.
  155. For an example using `Flask-Login <packages.python.org/Flask-Login/>`_, see the
  156. :file:`examples/authentication` directory in the source distribution, or view
  157. it online at `GitHub
  158. <https://github.com/jfinkels/flask-restless/tree/master/examples/authentication>`_.
  159. Pagination
  160. ~~~~~~~~~~
  161. To set the number of results returned per page, use the ``results_per_page``
  162. keyword arguments to the :meth:`APIManager.create_api` method. The default
  163. number of results per page is ten. If this is set to anything except a positive
  164. integer, pagination will be disabled and all results will be returned on each
  165. :http:method:`get` request.
  166. .. attention::
  167. Disabling pagination can result in large responses!
  168. For example, to set each page to include only two results::
  169. apimanager.create_api(Person, results_per_page=2)
  170. Then a request to :http:get:`/api/person` will return a JSON object which looks
  171. like this:
  172. .. sourcecode:: javascript
  173. {
  174. "page": 1,
  175. "objects": [
  176. {"name": "Jeffrey", "id": 1},
  177. {"name": "John", "id": 2}
  178. ]
  179. }
  180. For more information on using pagination, see :ref:`pagination`.
  181. Updating POST parameters before committing
  182. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  183. To apply some function to the :http:method:`post` form parameters before the
  184. database model is created, specify the ``post_form_preprocessor`` keyword. The
  185. value of ``post_form_preprocessor`` must be a function which accepts a single
  186. dictionary as input and outputs a dictionary. The input dictionary is the
  187. dictionary mapping names of columns of the model to values to assign to that
  188. column, as specified by the JSON provided in the body of the
  189. :http:method:`post` request. The output dictionary should be the same, but with
  190. whatever additions, deletions, or modifications you wish.
  191. For example, if the client is making a :http:method:`post` request to a model
  192. which which has an ``owner`` field which should contain the ID of the currently
  193. logged in user, you may wish for the server to append the mapping ``('owner',
  194. current_user.id)`` to the form parameters. In this case, you would set the
  195. value of ``post_form_processor`` to be the function defined below::
  196. def add_user_id(dictionary):
  197. dictionary['owner'] = current_user.id
  198. return dictionary