REST API violates principle of least surprise: JSON out, but not in & other divots
I have yet to find documentation on the REST API (other than, read the client code & some hints by example).
But by experimentation, have made some progress:
Divot 1: The REST API returns JSON, as expected, for GET requests.
However, contrary to my expectations, it does NOT accept JSON in PUT, PATCH, or POST requests.
Those are accepted as uri-encoded
query parameters and as x-www-form-urlencoded
form data.
If the client supplies Content-Type: application/json
, the REST API ought to accept it. Instead, it returns a 404(!) Very few client APIs like split personality servers.
POST /3.1/http://overkiller.v4.sb.litts.net:8001/3.1/lists HTTP/1.1
TE: deflate,gzip;q=0.3
Keep-Alive: 300
Connection: Keep-Alive, TE
Accept: application/json
Authorization: Basic redacted
Host: overkiller.v4.sb.litts.net:8001
User-Agent: vth-mailman/1.000
Content-Type: application/json
Content-Length: 44
{"fqdn_listname":"scorecard_json@litts.net"}HTTP/1.0 404 Not Found
Date: Sat, 24 Jun 2017 18:26:09 GMT
Server: WSGIServer/0.2 CPython/3.5.3
content-length: 0
content-type: application/json; charset=UTF-8
Response codes discovered so far are: 201 (created), 204 (no content success), 405 (method not allowed), 400 (bad request) 404 (Not found - including as above for "I don't like your request")
Divot 2:
Omitting the fqdn_listname
on a list create causes a 500 error w/traceback. Maybe this is a development mode issue. I expect the error in the 500 body - as JSON, not a traceback on the console.
Jun 24 14:04:03 2017 (31943) REST request handler error:
Traceback (most recent call last):
File "/usr/lib64/python3.5/wsgiref/handlers.py", line 137, in run
self.result = application(self.environ, self.start_response)
File "/usr/lib/python3.5/site-packages/mailman/database/transaction.py", line 50, in wrapper
rtn = function(*args, **kws)
File "/usr/lib/python3.5/site-packages/mailman/rest/wsgiapp.py", line 214, in __call__
return super().__call__(environ, start_response)
File "/usr/lib/python3.5/site-packages/falcon/api.py", line 227, in __call__
responder(req, resp, **params)
File "/usr/lib/python3.5/site-packages/mailman/rest/lists.py", line 245, in on_post
mlist = create_list(**validator(request))
File "/usr/lib/python3.5/site-packages/mailman/rest/validator.py", line 152, in __call__
raise ValueError('Missing parameters: {}'.format(missing))
ValueError: Missing parameters: fqdn_listname
Jun 24 14:04:03 2017 (31943) 192.168.148.22 - - "POST /3.1/lists HTTP/1.1" 500 59
Divot 3: It doesn't seem to be possible to atomically create a list & set its configuration. Instead, another server crash/500 response when I try to include description, reply_to_address, subject_prefix. Apparently one must create the list, then PATCH it with the desired parameters and add initial subscribers.
On http://www.pythonhosted.org/mailman/src/mailman/rest/docs/listconf.html, there is a cryptic reference to "transaction.commit()", but it's not clear how to start/end a transaction via the API.. Is this possible?
Jun 24 14:08:58 2017 (31943) REST request handler error:
Traceback (most recent call last):
File "/usr/lib64/python3.5/wsgiref/handlers.py", line 137, in run
self.result = application(self.environ, self.start_response)
File "/usr/lib/python3.5/site-packages/mailman/database/transaction.py", line 50, in wrapper
rtn = function(*args, **kws)
File "/usr/lib/python3.5/site-packages/mailman/rest/wsgiapp.py", line 214, in __call__
return super().__call__(environ, start_response)
File "/usr/lib/python3.5/site-packages/falcon/api.py", line 227, in __call__
responder(req, resp, **params)
File "/usr/lib/python3.5/site-packages/mailman/rest/lists.py", line 245, in on_post
mlist = create_list(**validator(request))
File "/usr/lib/python3.5/site-packages/mailman/rest/validator.py", line 142, in __call__
raise ValueError('Unexpected parameters: {}'.format(extras))
ValueError: Unexpected parameters: description, reply_to_address, subject_prefix
Jun 24 14:08:58 2017 (31943) 192.168.148.22 - - "POST /3.1/lists HTTP/1.1" 500 59
Divot 4:
The same page says:
Not all of the readable attributes can be set through the web interface. The ones that can, can either be set via PUT or PATCH. PUT changes all the writable attributes in one request.
When using PUT, all writable attributes must be included.
But there doesn't seem to be an API call that returns the (current) list of writable attributes
. So how does a generic client clone a list? One would think GET + modify + POST (or POST/PUT). But this will fail unless the non-writable attributes are somehow filtered out...