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.
|