Improve the documentation

--HG--
extra : rebase_source : 24b7ddcbfb6fb739787292db49148d3234d6f67a
This commit is contained in:
Christophe de Vienne 2013-04-08 23:27:15 +02:00
parent f9c262758e
commit 6b8349696d
7 changed files with 218 additions and 9 deletions

View File

@ -9,11 +9,7 @@ Public API
.. module:: wsme
.. autoclass:: WSRoot
:members:
.. autoclass:: expose
.. autoclass:: validate
.. autoclass:: signature([return_type, [arg0_type, [arg1_type, ... ] ] ], body=None, status=None)
.. autoclass:: wsproperty
.. autoclass:: wsattr
@ -22,6 +18,9 @@ Public API
Default value of the complex type attributes.
.. autoclass:: WSRoot
:members:
Internals
---------

View File

@ -7,7 +7,9 @@ next
* Add a special type 'HostRequest' that allow a function to ask for the host
framework request object in its arguments.
* New Flask adapter: wsmeext.flask
* New adapter: wsmeext.flask, for the Flask_ framework.
.. _Flask: http://flask.pocoo.org/
* Fix: the cornice adapter was not usable.

182
doc/functions.rst Normal file
View File

@ -0,0 +1,182 @@
Functions
=========
WSME is based on the idea that most of the time the input and output of web
services are actually stricly typed. It uses this fact to ease the
implementation of the actual functions by handling those input/output.
It also uses these informations to propose alternate protocols on top of a
proper REST api.
This chapter explains in details how to 'sign' a function with WSME.
The decorators
--------------
Depending on the framework you are using, you will have to use either a
@signature decorator, either a @wsexpose decorator.
@signature
~~~~~~~~~~
The base @\ :class:`wsme.signature` decorator defines the return and argument types
of the function, and if needed a few more options.
The Flask and Cornice adapters both propose a specific version of it, which
also wrap the function so that it becomes suitable for the host framework.
In any case, the use of @signature has the same meaning: tell WSME what is the
signature of the function.
@wsexpose
~~~~~~~~~
The native Rest implementation, and the TG and Pecan adapters add a @wsexpose
decorator.
It does what @signature does, *and* expose the function in the routing system
of the host framework.
This decorator is generally used in object-dispatch routing context.
.. note::
Since both decorators plays the same role function-wise, the rest of this
document will alway use @signature.
Signing a function
------------------
Signing a function is just a matter of decorating it with @signature:
.. code-block:: python
@signature(int, int, int)
def multiply(a, b):
return a * b
In this trivial example, we tell WSME that the 'multiply' function returns an
integer, and takes two integer parameters.
WSME will match the argument types by order, and know the exact type of each
named argument. This is important since most of the web service protocols don't
provide strict argument ordering but only named parameters.
Optional arguments
~~~~~~~~~~~~~~~~~~
Defining an argument as optional is done by providing a default value:
.. code-block:: python
@signature(int, int, int):
def increment(value, delta=1):
return value + delta
In this example, the caller may omit the 'delta' argument, and no
'MissingArgument' error will be raised.
Additionally this argument will be documented as optional by the sphinx
extension.
Body argument
~~~~~~~~~~~~~
When defining a Rest CRUD api, we generally have a URL on which we POST datas.
For example:
.. code-block:: python
@signature(Author, Author)
def update_author(data):
# ...
return data
Such a function will take at least one parameter 'data' that is a structured
type. With the default way of handling parameters, the body of the request
would be like this:
.. code-block:: javascript
{
"data":
{
"id": 1,
"name": "Pierre-Joseph"
}
}
If you think (and you should) that it has one extra nest level, the 'body'
argument is here for you::
@signature(Author, body=Author)
def update_author(data):
# ...
return data
With this syntax, we can now post a simpler body:
.. code-block:: javascript
{
"id": 1,
"name": "Pierre-Joseph"
}
Note that it does not prevent from having multiple parameters, it just requires
the body argument to be the last:
.. code-block:: python
@signature(Author, bool, body=Author)
def update_author(force_update=False, data=None):
# ...
return data
In this case, the other arguments can be passed in the URL, in addition to the
body parameter. For example, a POST on ``/author/SOMEID?force_update=true``.
Status code
~~~~~~~~~~~
The default status code returned by WSME are 200, 400 (if the client send wrong
inputs) and 500 (for server-side errors).
Since a proper Rest API should use different return codes (201, etc), one can
use the 'status=' option of @signature to do so.
.. code-block:: python
@signature(Author, body=Author, status=201)
def create_author(data):
# ...
return data
Of course this code will only be used if no error occur.
In case the function needs to change the status code on a per-request base, it
can return a :class:`wsme.Response` object, that allow to override the status
code:
.. code-block:: python
@signature(Author, body=Author, status=202)
def update_author(data):
# ...
response = Response(data)
if transaction_finished_and_successful:
response.status_code = 200
return response
Extra arguments
~~~~~~~~~~~~~~~
The default behavior of WSME is to reject requests that gives extra/unknown
arguments. In some (rare) cases, it can be unwanted.
Adding 'ignore_extra_args=True' to @signature changes this behavior.
.. note::
If using this option seems to solution to your problem, please think twice
before using it !

View File

@ -10,6 +10,7 @@ Contents
gettingstarted
api
types
functions
protocols
integrate
document

View File

@ -24,11 +24,13 @@ This decorator can have two different names depending on the adapter.
Generally this decorator is provided for frameworks that expects functions
taking a request object as a single parameter and returning a response
object. This is the case of :ref:`adapter-cornice`.
object. This is the case of :ref:`adapter-cornice` and
:ref:`adapter-flask`.
Additionnaly, if you want to enable additionnal protocols, you will need to
mount a :class:`WSRoot` instance somewhere in the application, generally
``/ws``. This subpath will then handle the additional protocols.
``/ws``. This subpath will then handle the additional protocols. In a future
version, a wsgi middleware will probably play this role.
.. note::
@ -115,7 +117,8 @@ Example
Flask
-----
*"Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions. And before you ask: It's BSD licensed! "*
*"Flask is a microframework for Python based on Werkzeug, Jinja 2 and good
intentions. And before you ask: It's BSD licensed! "*
.. warning::

View File

@ -8,6 +8,11 @@ last chapter (:ref:`protocols-the-example`).
REST
----
.. note::
This chapter applies also for the different adapters, not only the native
REST implementation.
The two REST protocols share common characterics.
Each function corresponds to distinct webpath that starts with the

View File

@ -136,6 +136,23 @@ class FunctionDefinition(object):
class signature(object):
"""
Decorator that specify the argument types of an exposed function.
:param return_type: Type of the value returned by the function
:param argN: Type of the Nth argument
:param body: If the function takes a final argument that is supposed to be
the request body by itself, its type.
:param status: HTTP return status code of the function.
:param ignore_extra_args: Allow extra/unknow arguments (default to False)
Most of the time this decorator is not supposed to be used directly,
unless you are not using WSME on top of another framework.
If an adapter is used, it will provide either a specialised version of this
decororator, either a new decorator named @wsexpose that takes the same
parameters (it will in addition expose the function, hence its name).
"""
def __init__(self, *types, **options):
self.return_type = types[0] if types else None
self.arg_types = []