I was trying to use the conduit API to create a task, using the Requests python library (python 2.7 on debian jessie); I suppose this is the simplest script that anybody would write:
import requests s = requests.Session() projectPHIDs = ["PHID-PROJ-cve7ps3jhhf5e2k4modo"] data = {'api.token': '...', 'projectPHIDs': projectPHIDs, 'title': 'aaa', 'description': 'bbb'} url1 = 'https://phabricator.example.com/api/maniphest.createtask' r1 = s.post(url1, data=data) r1.raise_for_status() results1 = r1.json() print results1
but this results in:
{"error_code": "ERR-CONDUIT-CORE", "result": None, "error_info": "Argument 1 passed to ManiphestConduitAPIMethod::validatePHIDList() must be of the type array, string given, called in /opt/phabricator/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php on line 141 and defined"}
to see what Requests sends, I switched to a more verbose synthax:
req = requests.Request('POST', url, data=data) prepped = req.prepare() print 'body = ' + prepped.body
and here is the body:
title=aaa&api.token=...&description=bbb&projectPHIDs=%5B%27PHID-PROJ-cve7ps3jhhf5e2k4modo%27%5D
according to urlparse.parse_qs this decodes back to:
{"projectPHIDs": ["['PHID-PROJ-cve7ps3jhhf5e2k4modo']"], "api.token": ["..."], "description": ["bbb"], "title": ["aaa"]}
so actually it's sending a string indeed !
I then tested the same API endpoint using the conduit webconsole, intercepted the request and found this:
325\r\n\r\n__csrf__=B%40n2t2voygdd0372992a31838c&__form__=1¶ms%5Btitle%5D=%5B%22bbb%22%5D¶ms%5Bdescription%5D=¶ms%5BownerPHID%5D=¶ms%5BviewPolicy%5D=¶ms%5BeditPolicy%5D=¶ms%5BccPHIDs%5D=¶ms%5Bpriority%5D=¶ms%5BprojectPHIDs%5D=%5B%22PHID-PROJ-cve7ps3jhhf5e2k4modo%22%5D¶ms%5Bauxiliary%5D=&output=human"
this is what I see when I decode that with urlparse.parse_qs:
{'325\r\n\r\n__csrf__': ['B@n2t2voygdd0372992a31838c'], '__form__': ['1'], 'params[projectPHIDs]': ['["PHID-PROJ-cve7ps3jhhf5e2k4modo"]'], 'output': ['human"'], 'params[title]': ['["bbb"]']}
now this seems to me a non-standard way to send the parameters !
after some more tests, I just wanted to find a way to create the one task, so here is the solution:
import requests s = requests.Session() projectPHID = "PHID-PROJ-cve7ps3jhhf5e2k4modo" data = {'api.token': '...', 'title': 'aaa', 'description': 'bbb'} url = 'https://phabricator.example.com/api/maniphest.createtask' req = requests.Request('POST', url, data=data) prepped = s.prepare_request(req) prepped.body = prepped.body + '&projectPHIDs=%5B%22' + projectPHID + '%22%5D' print 'body = ' + prepped.body resp = s.send(prepped) resp.raise_for_status() results = resp.json() print results
this bug report is only to point out that the conduit API is awkward to use when one must send arrays; it should really be way less painful that that !