Trying to use Conduit API via HTTPoison

Hey everyone,

I’ve been lurking for a while on this forum. You all seem super nice and helpful! I started using elixir a few months ago and I am still far from being a proficient user.

Currently, I’m trying to write an API client for the Phabricator - Conduit API ( API docs ). I am trying to generate a ticket by calling the maniphest.edit method. maniphest.edit accepts a list of transactions and an optional id to update an existing ticket. Conduit has a console which lets you make API calls and returns the result and the request in cURL or php.

This is the request in cURL:

curl phabricator.example.com/api/maniphest.edit -d api.token="api-..." -d transactions[0][type]=title -d transactions[0][value]=new

And in php:

    <?php

require_once 'path/to/libphutil/src/__phutil_library_init__.php';

$api_token = "<api-token>";
$api_parameters = array(
  'transactions' => array(
    array(
      'type' => 'title',
      'value' => 'new',
    ),
  ),
);

$client = new ConduitClient('http://phabricator.localhost/');
$client->setConduitToken($api_token);

$result = $client->callMethodSynchronous('maniphest.edit', $api_parameters);
print_r($result);

This is what I am trying in Elixir using HTTPOISON:

    enc_body =
      Poison.encode!(
        %{
          "api.token": "api-token",
          transactions: [%{type: "title", value: "new"}]
        },
        []
      )

    headers = [{"Content-Type", "application/json"}]
    url = "phabricator.example.com/api/maniphest.edit"

    HTTPoison.post(url, enc_body, headers)

It gives me the following response when I try it in iex:

{:ok,
 %HTTPoison.Response{
   body: "{\"result\":null,\"error_code\":\"ERR-CONDUIT-CALL\",\"error_info\":\"API Method \\\"maniphest.edit\\\" does not define these parameters: '{\\\"transactions\\\":[{\\\"value\\\":\\\"new\\\",\\\"type\\\":\\\"title\\\"}],\\\"api.token\\\":\\\"api-token\\\"}'.\"}",
   headers: [
     {"Date", "Sat, 15 Sep 2018 11:48:01 GMT"},
     {"Server", "Apache/2.4.18 (Unix) PHP/5.5.36"},
     {"X-Powered-By", "PHP/5.5.36"},
     {"Set-Cookie",
      "phsid=A%2Fxqv2oicp3gvcq2qnce5mbo4kblmmijpsbqm4fzc6; expires=Thu, 14-Sep-2023 11:48:01 GMT; Max-Age=157680000; path=/; domain=127.0.0.1; httponly"},
     {"X-Frame-Options", "Deny"},
     {"Content-Security-Policy",
      "default-src 'self' http://127.0.0.1; img-src 'self' http://127.0.0.1 data:; style-src 'self' http://127.0.0.1 'unsafe-inline'; script-src 'self' http://127.0.0.1; connect-src 'self'; frame-src 'self'; frame-ancestors 'none'; object-src 'none'; form-action 'self'; base-uri 'none'"},
     {"Referrer-Policy", "no-referrer"},
     {"Cache-Control", "no-store"},
     {"Expires", "Sat, 01 Jan 2000 00:00:00 GMT"},
     {"X-Content-Type-Options", "nosniff"},
     {"Content-Length", "240"},
     {"Content-Type", "application/json"}
   ],
   request_url: "phabricator.example.com/api/maniphest.edit",
   status_code: 200
 }}

Maybe anyone knows what I’m doing wrong here? I tried so many things but I can’t get it to work.

Currently, I’m trying to write an API client for the Phabricator - Conduit API ( API docs ). I am trying to generate a ticket by calling the maniphest.edit method. maniphest.edit accepts a list of transactions and an optional id to update an existing ticket. Conduit has a console which lets you make API calls and returns the result and the request in cURL or php.

This is the request in cURL:

curl phabricator.example.com/api/maniphest.edit -d api.token=“api-…” -d transactions[0][type]=title -d transactions[0][value]=new

What happens if you use curl to send the Poison-generated JSON instead
of the raw post data above? Do you get the same error as below?

It returns the same error as with trying it from elixir. I figured something out though: curl sends it as application/x-www-form-urlencoded and not as application/json. This seems confusing to me as they state in the conduit docs:

Conduit is the HTTP API for Phabricator. It is roughly JSON-RPC: you usually pass a JSON blob, and usually get a JSON blob back, although both call and result formats are flexible in some cases.

So to me it seems like it should definitely still work with the JSON…

When you tried passing the JSON string with curl you set the proper
content-type on the command line, right?

If that didn’t work, then it appears there’s some parameter mismatch
but I don’t know anything about Conduit/Phabricator.

Good luck!

Yes, I did set the proper content-type.

For future reference, I figured it out:

Conduit API does not accept JSON in the request body. As per this thread https://secure.phabricator.com/T12447 the API only accepts x-www-form-urlencoded as content-type. A bit misleading in the documentation…

Anyway, time to find out how to convert my json to x-www-form-urlencoded :slight_smile: