iOS(Swift)から3ステップでMastodonに投稿を行う


## 前置き
・流行りのMastodonへiOSアプリから投稿してみようと思い立つ
・登録、ログイン、投稿の3ステップを記載
・今回はmastdn.jpを使用しています。適宜変更してください。

## 共通

```swift
// Mastodonのインスタンスから返ってくるjson格納用
var responseJson = Dictionary<String, AnyObject>()

let session = URLSession.shared

// POST METHOD
func post(url: URL, body: Dictionary<String, String>, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) throws {
    var request: URLRequest = URLRequest(url: url)

    request.httpMethod = "POST"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)

    session.dataTask(with: request, completionHandler: completionHandler).resume()
}
```


## Step.1 アプリの認証登録

```swift
// 登録URL
let registUrl = URL(string: "https://mastdn.jp/api/v1/apps")!

// client_name: アプリ名とかどこからの投稿かわかるための名前
// redirect_uris: おまじない(公式で"urn:ietf:wg:oauth:2.0:oob"を書く様に記載)
// scopes: 権限。今回に関してはwriteだけで足りるが、必要に応じてスペース区切りで追加 例→ "write read follow"
// website: アプリのURLやWebsite。client_nameにこのリンクがつく(省略可能)
let body: [String: String] = ["client_name": "TestApp", "redirect_uris": "urn:ietf:wg:oauth:2.0:oob", "scopes": "write"]

// 登録POST
do {
    try post(url: registUrl, body: body) { data, response, error in
        do {
            self.responseJson = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! Dictionary<String, AnyObject>
        } catch {
        }
    }
} catch {
}
```

```json
// responseJsonの中身
{
    "client_id": "abcdef123456789abcdef123456789abcdef123456789abcdef123456789abcd",
    "client_secret": "123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
    "id": 9999,
    "redirect_uri": "urn:ietf:wg:oauth:2.0:oob"
}
```


## Step.2 ログイン

```swift
// ログインURL
let loginUrl = URL(string: "https://mastdn.jp/oauth/token")!

// scope: 権限。指定しないと返ってくるaccess_tokenはreadだけしか使えない。複数指定可能。
// client_id: Step.1のresponseで取得したもの
// client_secret:  Step.1のresponseで取得したもの
// grant_type: ログインする方式(で合っているのかな？)
// username: 登録したメールアドレス (アカウント名ではない)
// password: 登録したパスワード
let body: [String: String] = ["scope": "write", "client_id": responseJson["client_id"] as! String, "client_secret": responseJson["client_secret"] as! String, "grant_type": "password", "username": "hogefuga@gmail.com", "password": "hogefuga"]

// ログインPOST
do {
    try post(url: loginUrl, body: body) { data, response, error in
        do {
            self.responseJson = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! Dictionary<String, AnyObject>
        } catch {
        }
    }
} catch {
}
```

```json
// responseJsonの中身
{
    "access_token": "abcdef123456789abcdef123456789abcdef123456789abcdef123456789abcd",
    "created_at": 1234567890,
    "scope": "write",
    "token_type": "bearer"
}
```


## Step.3 Tootの投稿

```swift
// TootURL
let tootUrl = URL(string: "https://mastdn.jp/api/v1/statuses")!

// access_token: Step.2で取得しているもの
// status: Tootの内容
// visibility: 公開範囲。public, unlisted, private, directとあるが違いは試していないので不明(省略可能)
let body: [String: String] = ["access_token": responseJson["access_token"] as! String, "status": "開発アプリからのテスト投稿", "visibility": "public"]

// Toot POST
do {
    try post(url: tootUrl, body: body) { data, response, error in
        // dataは返ってくるが、投稿できるまでの処理を書くだけなので省略
    }
} catch {
}
```

## 参考にしたURL
1. https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#apps
2. [Twitter の投稿を IFTTT で Mastodon へ転送する。 - Qiita](http://qiita.com/yukimochi/items/f80a50a4486d0cb770dc)
3. [HTTP Request in Swift 3.0 - Qiita](http://qiita.com/Shirade/items/086be09376b9cbbe7bc8)