Mastodon API を Ruby(Faraday) / Python(Pycurl) / PHP(Curl) で叩いてみた

マストドンをとりあえず叩いてみました。
表題の通り、Ruby は Faraday、Python は Pycurl、PHP は Curl を使っています。
app.xx でアプリ登録を行い、test.xx で認証〜投稿の流れとしました。

# Ruby

```ruby:app.rb
#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-

require 'faraday'
require 'uri'

CALLBACK_URL = 'アプリの URL'
MASTODON_URL = '対象とするインスタンスの URL（例:　https://mstdn.high-low.ml）'
SCOPE = '欲しい権限（例: read write）'

options = {
  client_name: 'アプリの名前',
  redirect_uris: CALLBACK_URL,
  scopes: SCOPE
}

conn = Faraday.new(:url => MASTODON_URL) do |faraday|
  faraday.request :url_encoded
  faraday.response :logger
  faraday.adapter Faraday.default_adapter
end
response = conn.post do |request|
  request.url '/api/v1/apps'
  request.body = URI.encode_www_form(options)
end
print "Content-Type: application/json; charset=UTF-8\n\n"
print response.body
```

出力結果に表示された「client_id」と「client_secret」を保存します。

```ruby:test.rb
#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-

require 'cgi'
require 'uri'

cgi = CGI.new()

CALLBACK_URL = 'アプリの URL'
MASTODON_URL = '対象とするインスタンスの URL'
CLIENT_ID = 'app.rb で取得した CLIENT_ID'
CLIENT_SECRET = 'app.rb で取得した CLIENT_SECRET'
SCOPE = '指定した権限'

if cgi['code'].empty?
  # 認証を取りに行きます
  options = {
    client_id: CLIENT_ID,
    response_type: 'code',
    scope: SCOPE,
    redirect_uri: CALLBACK_URL
  }
  print cgi.header({
    'status' => 'REDIRECT',
    'Location' => "#{MASTODON_URL}/oauth/authorize?#{URI.encode_www_form(options)}"
  })
else
  # 認証されたので access_token を取りにいきます
  require 'faraday'
  require 'json'

  options = {
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    grant_type: 'authorization_code',
    redirect_uri: CALLBACK_URL,
    scope: SCOPE,
    code: cgi['code']
  }

  conn = Faraday.new(:url => MASTODON_URL) do |faraday|
    faraday.request :url_encoded
    faraday.response :logger
    faraday.adapter Faraday.default_adapter
  end
  response = conn.post do |request|
    request.url '/oauth/token'
    request.body = URI.encode_www_form(options)
  end
  access_token = JSON.parse(response.body)['access_token']

  # access_token を取れたついでに、世間の中心でぱおーんと叫びます
  options = {
    mastodon_host: MASTODON_URL,
    status: 'ぱおーん'
  }
  response = conn.post do |request|
    request.url '/api/v1/statuses'
    request.headers = {
      'Authorization' => "Bearer #{access_token}"
    }
    request.body = URI.encode_www_form(options)
  end
  print "Content-Type: application/json; charset=UTF-8\n\n"
  print response.body
end
```

認証画面はこんな感じです。
<img width="432" alt="スクリーンショット 2017-04-19 17.37.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/11026/cc0e78fe-b69d-7dfa-4663-80a63f6db91c.png">

# Python

```py:app.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

import pycurl, urllib
from StringIO import StringIO

CALLBACK_URL = 'アプリの URL'
MASTODON_URL = '対象とするインスタンスの URL'
SCOPE = '欲しい権限（例: read write）'

options = {
	'client_name': 'アプリの名前',
	'redirect_uris': CALLBACK_URL,
	'scopes': SCOPE
}

response = StringIO()
curl = pycurl.Curl()
curl.setopt(pycurl.URL, '%s/api/v1/apps' %(MASTODON_URL))
curl.setopt(pycurl.WRITEFUNCTION, response.write)
curl.setopt(pycurl.POST, 1)
curl.setopt(pycurl.POSTFIELDS, urllib.urlencode(options))
curl.perform()
print "Content-Type: application/json; charset=UTF-8\n\n"
print response.getvalue()
```

```py:test.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

import urllib, cgi
from StringIO import StringIO

form = cgi.FieldStorage()

CALLBACK_URL = 'アプリの URL'
MASTODON_URL = '対象とするインスタンスの URL'
CLIENT_ID = 'app.py で取得した CLIENT_ID'
CLIENT_SECRET = 'app.py で取得した CLIENT_SECRET'
SCOPE = '指定した権限'

if not form.has_key('code'):
	# 認証を取りにいきます
	options = {
		'client_id': CLIENT_ID,
		'response_type': 'code',
		'scope': SCOPE,
		'redirect_uri': CALLBACK_URL
	}
	print "Content-Type: text/html\n\n"
	print '<meta http-equiv=\"refresh\" content=\"0; URL=%s/oauth/authorize?%s\">' %(MASTODON_URL, urllib.urlencode(options))
else:
	# access_token を取りにいきます
	import pycurl, json

	options = {
		'client_id': CLIENT_ID,
		'client_secret': CLIENT_SECRET,
		'grant_type': 'authorization_code',
		'redirect_uri': CALLBACK_URL,
		'scope': SCOPE,
		'code': form['code'].value
	}

	response = StringIO()
	curl = pycurl.Curl()
	curl.setopt(pycurl.URL, '%s/oauth/token' %(MASTODON_URL))
	curl.setopt(pycurl.WRITEFUNCTION, response.write)
	curl.setopt(pycurl.POST, 1)
	curl.setopt(pycurl.POSTFIELDS, urllib.urlencode(options))
	curl.perform()
	access_token = str(json.loads(response.getvalue())['access_token'])

	# ぱおーんと叫びます
	options = {
		'mastodon_host': MASTODON_URL,
		'status': 'ぱおーん'
	}

	curl.setopt(pycurl.URL, '%s/api/v1/statuses' %(MASTODON_URL))
	curl.setopt(pycurl.HTTPHEADER, ['Authorization: Bearer %s' %(access_token)])
	curl.setopt(pycurl.POSTFIELDS, urllib.urlencode(options))
	curl.perform()

	print "Content-Type: application/json; charset=UTF-8\n\n"
	print response.getvalue()
```

# PHP

```php:app.php
<?php
define('CALLBACK_URL', 'アプリの URL');
define('MASTODON_URL', '対象とするインスタンスの URL（例:　https://mstdn.high-low.ml）');
define('SCOPE', '欲しい権限（例: read write）');

$options = array(
	'client_name' => 'アプリの名前',
	'redirect_uris' => CALLBACK_URL,
	'scopes' => SCOPE
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, MASTODON_URL. '/api/v1/apps');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $options);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$response = curl_exec($ch);
curl_close($ch);

header('Content-type: application/json; charset=utf-8');
echo $response;
```

```php:test.php
<?php
define('CALLBACK_URL', 'アプリの URL');
define('MASTODON_URL', '対象とするインスタンスの URL');
define('CLIENT_ID', 'app.php で取得した CLIENT_ID');
define('CLIENT_SECRET', 'app.php で取得した CLIENT_SECRET');
define('SCOPE', '指定した権限');

if (!isset($_GET['code'])) {
	# 認証
	$options = array(
		'client_id' => CLIENT_ID,
		'response_type' => 'code',
		'scope' => SCOPE,
		'redirect_uri' => CALLBACK_URL
	);
	header('Location: '. MASTODON_URL. '/oauth/authorize?'. http_build_query($options, '', '&'));
} else {
	# access_token 取得
	$options = array(
		'client_id' => CLIENT_ID,
		'client_secret' => CLIENT_SECRET,
		'grant_type' => 'authorization_code',
		'redirect_uri' => CALLBACK_URL,
		'scope' => SCOPE,
		'code' => $_GET['code']
	);

	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, MASTODON_URL. '/oauth/token');
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $options);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	$response = curl_exec($ch);
	$data = json_decode($response);
	$access_token = $data->access_token;

	# ぱおーん
	$options = array(
		'mastodon_host' => MASTODON_URL,
		'status' => 'ぱおーん'
	);

	curl_setopt($ch, CURLOPT_URL, MASTODON_URL. '/api/v1/statuses');
	curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$access_token}"));
	curl_setopt($ch, CURLOPT_POSTFIELDS, $options);
	$response = curl_exec($ch);
	curl_close($ch);
	header('Content-type: application/json; charset=utf-8');
	echo $response;
}
```

# 参考
[tootsuite/mastodon-api: A ruby interface for the Mastodon API](https://github.com/tootsuite/mastodon-api)
[MastodonのAPIをcurlで叩いてみるサンプル - Qiita](http://qiita.com/shindyu/items/6a1f0c567774516f07da)
[Mastodon API の叩き方](https://gist.github.com/okapies/eab5c6fc217e914ed0cac6c944384e4d)