File: webhooks.rst

package info (click to toggle)
errbot 6.2.0%2Bds-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,796 kB
  • sloc: python: 11,557; makefile: 164; sh: 97
file content (176 lines) | stat: -rw-r--r-- 7,691 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
Webhooks
========

Errbot has a small integrated webserver that is capable of hooking up
endpoints to methods inside your plugins.

You must configure the *Webserver* plugin before this functionality
can be used. You can get the configuration template using `!plugin config
Webserver`, from where it's just a simple matter of plugging in the
desired settings.

.. note::
    There is a `!generate certificate` command to generate a
    self-signed certificate in case you want to enable SSL
    connections and do not have a certificate.

.. warning::
    It is not recommended to expose Errbot's webserver directly to the
    network. Instead, we recommend placing it behind a webserver
    such as `nginx <http://nginx.org/>`_ or `Apache <https://httpd.apache.org/>`_.


Simple webhooks
---------------

All you need to do for a plugin of yours to listen to a specific URI
is to apply the :func:`~errbot.webhook` decorator to your method.
Whatever it returns will be returned in response to the request:

.. code-block:: python

    from errbot import BotPlugin, webhook

    class PluginExample(BotPlugin):
        @webhook
        def test(self, request):
            self.log.debug(repr(request))
            return "OK"

This will listen for POST requests on
http://yourserver.tld:yourport/test/, and return *"OK"* as the
response body.

.. note::
    If you return `None`, an empty 200 response will be sent.


You can also set a custom URI pattern by providing the `uri_rule`
parameter:

.. code-block:: python

    from errbot import BotPlugin, webhook

    class PluginExample(BotPlugin):
        @webhook('/example/<name>/<action>/')
        def test(self, request, name, action):
            return "User %s is performing %s" % (name, action)

Refer to the documentation on Flask's
`route <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.route>`_
for details on the supported syntax
(Errbot uses Flask internally).


Handling JSON request
---------------------

If an incoming request has the MIME media type set to `application/json`
the request will automatically be decoded as JSON.
You will receive the result of calling `json.loads()` on `request` automatically
so that you won't have to do this yourself.


Handling form-encoded requests
------------------------------

Form-encoded requests (those with an
*application/x-www-form-urlencoded* mimetype) are very simple to
handle as well, you just need to specify the `form_param` parameter.

A good example for this is the GitHub format which posts a form with
a *payload* parameter:

.. code-block:: python

    from errbot import BotPlugin, webhook

    class Github(BotPlugin):
        @webhook('/github/', form_param = 'payload')
        def notification(self, payload):
            for room in self.bot_config.CHATROOM_PRESENCE:
                self.send(
                    self.build_identifier(room),
                    'Commit on %s!' % payload['repository']['name'],
                )


The raw request
---------------

The above webhooks are convenient for simple tasks, but sometimes
you might wish to have more power and have access to the actual
request itself. By setting the `raw` parameter of the
:func:`~errbot.decorators.webhook` decorator to `True`, you will
be able to get the
`flask.Request <http://flask.pocoo.org/docs/1.0/api/#flask.Request>`_
which contains all the details about the actual request:

.. code-block:: python

    from errbot import BotPlugin, webhook

    class PluginExample(BotPlugin):
        @webhook(raw=True)
        def test(self, request):
            user_agent = request.headers.get("user-agent", "Unknown")
            return f"Your user-agent is {user_agent}"


Returning custom headers and status codes
-----------------------------------------

Adjusting the response headers, setting cookies or returning a
different status code can all be done by manipulating the
`flask response <http://flask.pocoo.org/docs/1.0/patterns/deferredcallbacks/>`_
object. The Flask docs on `the response object
<http://flask.pocoo.org/docs/1.0/api/#response-objects>`_
explain this in more detail. Here's an example of setting a
custom header:

.. code-block:: python

    from errbot import BotPlugin, webhook
    from flask import after_this_request

    class PluginExample(BotPlugin):
        @webhook
        def example(self, incoming_request):
            @after_this_request
            def add_header(response):
                response.headers['X-Powered-By'] = 'Errbot'
            return "OK"

Flask also has various helpers such as the `abort()` method.
Using this method we could, for example, return a 403 forbidden
response like so:

.. code-block:: python

    from errbot import BotPlugin, webhook
    from flask import abort

    class PluginExample(BotPlugin):
        @webhook
        def example(self, incoming_request):
            abort(403, "Forbidden")


Testing a webhook through chat
------------------------------

You can use the `!webhook` command to test webhooks without making
an actual HTTP request, using the following format::

    !webhook test /[endpoint] [post_content]

For example::

    !webhook test /test

    !webhook test /github payload=%7B%22pusher%22%3A%7B%22name%22%3A%22gbin%22%2C%22email%22%3A%22gbin%40gootz.net%22%7D%2C%22repository%22%3A%7B%22name%22%3A%22test%22%2C%22created_at%22%3A%222012-08-12T16%3A09%3A43-07%3A00%22%2C%22has_wiki%22%3Atrue%2C%22size%22%3A128%2C%22private%22%3Afalse%2C%22watchers%22%3A0%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Fgbin%2Ftest%22%2C%22fork%22%3Afalse%2C%22pushed_at%22%3A%222012-08-12T16%3A26%3A35-07%3A00%22%2C%22has_downloads%22%3Atrue%2C%22open_issues%22%3A0%2C%22has_issues%22%3Atrue%2C%22stargazers%22%3A0%2C%22forks%22%3A0%2C%22description%22%3A%22ignore%20this%2C%20this%20is%20for%20testing%20the%20new%20err%20github%20integration%22%2C%22owner%22%3A%7B%22name%22%3A%22gbin%22%2C%22email%22%3A%22gbin%40gootz.net%22%7D%7D%2C%22forced%22%3Afalse%2C%22after%22%3A%22b3cd9e66e52e4783c1a0b98fbaaad6258669275f%22%2C%22head_commit%22%3A%7B%22added%22%3A%5B%5D%2C%22modified%22%3A%5B%22README.md%22%5D%2C%22timestamp%22%3A%222012-08-12T16%3A24%3A25-07%3A00%22%2C%22removed%22%3A%5B%5D%2C%22author%22%3A%7B%22name%22%3A%22Guillaume%20BINET%22%2C%22username%22%3A%22gbin%22%2C%22email%22%3A%22gbin%40gootz.net%22%7D%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Fgbin%2Ftest%2Fcommit%2Fb3cd9e66e52e4783c1a0b98fbaaad6258669275f%22%2C%22id%22%3A%22b3cd9e66e52e4783c1a0b98fbaaad6258669275f%22%2C%22distinct%22%3Atrue%2C%22message%22%3A%22voila%22%2C%22committer%22%3A%7B%22name%22%3A%22Guillaume%20BINET%22%2C%22username%22%3A%22gbin%22%2C%22email%22%3A%22gbin%40gootz.net%22%7D%7D%2C%22deleted%22%3Afalse%2C%22commits%22%3A%5B%7B%22added%22%3A%5B%5D%2C%22modified%22%3A%5B%22README.md%22%5D%2C%22timestamp%22%3A%222012-08-12T16%3A24%3A25-07%3A00%22%2C%22removed%22%3A%5B%5D%2C%22author%22%3A%7B%22name%22%3A%22Guillaume%20BINET%22%2C%22username%22%3A%22gbin%22%2C%22email%22%3A%22gbin%40gootz.net%22%7D%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Fgbin%2Ftest%2Fcommit%2Fb3cd9e66e52e4783c1a0b98fbaaad6258669275f%22%2C%22id%22%3A%22b3cd9e66e52e4783c1a0b98fbaaad6258669275f%22%2C%22distinct%22%3Atrue%2C%22message%22%3A%22voila%22%2C%22committer%22%3A%7B%22name%22%3A%22Guillaume%20BINET%22%2C%22username%22%3A%22gbin%22%2C%22email%22%3A%22gbin%40gootz.net%22%7D%7D%5D%2C%22ref%22%3A%22refs%2Fheads%2Fmaster%22%2C%22before%22%3A%2229b1f5e59b7799073b6d792ce76076c200987265%22%2C%22compare%22%3A%22https%3A%2F%2Fgithub.com%2Fgbin%2Ftest%2Fcompare%2F29b1f5e59b77...b3cd9e66e52e%22%2C%22created%22%3Afalse%7D

.. note::
    You can get a list of all the endpoints with the `!webstatus`
    command.