Invokable > 戻る
2024-07-04
Laravel

Threads APIの使い方

いつものように通知を使いたいのがメインなので最低限のクライアント(機能を増やしたいならmacroで拡張)。
Socialiteも入れたけど公式が対応した場合は削除する。
https://github.com/invokable/laravel-threads

  1. ドキュメント
  2. Meta for Developersで「アプリ」を作るまで
  3. ユースケースのカスタマイズ
  4. Socialite用のClient IDとClient Secret
  5. Threadsのトークン
  6. トークンの使用
  7. Threadsテスターに追加した自分のアカウントに投稿
  8. 自分の投稿を取得
  9. Socialiteで認証
  10. 長期トークンの更新
  11. 更新

ドキュメント

https://developers.facebook.com/docs/threads

Meta for Developersで「アプリ」を作るまで

https://developers.facebook.com/

  • Facebookアカウントが必要なはず
  • 「アプリを作成」
  • 「ビジネスポートフォリオをリンクしない」
  • ユースケースでThreads APIを選択

ユースケースのカスタマイズ

アプリのダッシュボードまで進んだら、ユースケースからThreads APIの設定をカスタマイズ。

アクセス許可

threads_basicは必須なので最初から有効。投稿のためにthreads_content_publish、削除用にthreads_delete、検索用にthreads_keyword_searchも有効化する。

設定

Threadsテスターに自分のThreadsアカウントを追加。Threadsのウェブサイトで許可。トークンを生成。自分のアカウントに投稿するだけならこのトークンだけでいい。

Socialite/OAuthで認証してトークンを取得するならコールバックURLの設定も必要。これは後からでいい。

Socialite用のClient IDとClient Secret

アプリ設定→ベーシックの「ThreadsアプリID」と「Threads App Secret」を使う。

上側に「アプリID」と「app secret」があるけどこっちは違う。

Threadsのトークン

短期トークンと長期トークンがある。

Socialiteで取得できるのは短期トークン。短期トークンを長期トークンに変換すれば60日か90日間有効なトークンを得られる。長期トークンを更新すれば有効期限が伸びた新しい長期トークンを得られるので更新しながら使えばずっと使える。

Threadsテスターで生成されるのは最初から長期トークンなのでSocialiteは不要。

長期トークンの更新が必要なので.envに書いたままずっと使うことはできない。一人分だとしてもDBかキャッシュに保存して更新できるようにしておく。

APIの利用に必須なのは長期トークンだけなのでトークンについて理解できれば十分。

トークンの使用

ドキュメントではクエリパラメータで使用しているけど

&access_token=<ACCESS_TOKEN>

AuthorizationヘッダーでもいいのでLaravelのHttpクライアントならwithToken()が使える。ちょっと投稿するだけならパッケージ使う必要はなくHttpクライアントでいい。

Http::withToken('')->post();

Threadsテスターに追加した自分のアカウントに投稿

トークンはプロフィールページに入力欄作ってusersテーブルに保存して$user->threads_tokenで使える、と仮定。この辺は好きなように。

Threadsへの投稿は「text, image, videoを投稿する」と「publishで公開する」の2段階の工程が必要。

use Revolution\Threads\Facades\Threads;

Threads::token($user->threads_token);

$id = Threads::createText('test');
Threads::publish($id)

imageやvideoは公開されてるURLが必要。直接アップロードはできない。
Storage内のファイルを使うならurlで指定する。

use Revolution\Threads\Facades\Threads;
use Illuminate\Support\Facades\Storage;

Threads::token($user->threads_token);

$id = Threads::createImage(url: Storage::url('cat.png'), text: 'test');
Threads::publish($id)

動画の場合は30秒待ったほうがいいらしいのでpublish時に何秒sleepを入れるか指定できる。publish時に待ってもいいし、Threads::status()でチェックしてもいいし、キューで30秒遅らせてもいい。

use Revolution\Threads\Facades\Threads;
use Illuminate\Support\Facades\Storage;

Threads::token($user->threads_token);

$id = Threads::createVideo(url: Storage::url('dog.mov'), text: 'test');
Threads::publish($id, sleep: 30)

2段階に分かれてるのは複数のimage, videoをまとめて投稿できるカルーセル機能のためと予想。

use Revolution\Threads\Facades\Threads;
use Illuminate\Support\Facades\Storage;

Threads::token($user->threads_token);

$id1 = Threads::createImage(url: Storage::url('cat1.png'), is_carousel: true);
$id2 = Threads::createImage(url: Storage::url('cat2.png'), is_carousel: true);
$id = Threads::createCarousel(children: [$id1, $id2], text: 'test');
Threads::publish($id)

一時変数を使うのはLaravelらしくない使い方になるけどカルーセルのことを考えるとこれが無難。

自分の投稿を取得

use Revolution\Threads\Facades\Threads;

$posts = Threads::token($user->threads_token)->posts()->json('data');

v0.3以降、posts()の返り値はIlluminate\Http\Client\Responseに変更。

        $posts->each(function (array $post) {
            //dump($post);
            // $post['text'] ?? '';
            // Arr::get($post, 'text');
        });

投稿データは「画像だけの投稿にはtextがない」とか意外と項目の抜けがあるので注意が必要。

取得件数のデフォルトは25。上限は100。limitで指定できる。

use Revolution\Threads\Facades\Threads;

$posts = Threads::token($user->threads_token)->posts(limit: 50);

全部省略できるけどposts()は引数が多くなった。
名前付き引数が登場してから「配列で渡す」や「専用のクラスを渡す」よりも「省略すればいいだけなので引数を増やす」傾向が強くなった。

Socialiteで認証

configと.envに追加。

config/services.php

    'threads' => [
        // Threads App ID
        'client_id' => env('THREADS_CLIENT_ID'),
        // Threads App Secret
        'client_secret' => env('THREADS_CLIENT_SECRET'),
        'redirect' => env('THREADS_REDIRECT_URL', '/threads/callback'),
    ],

.env

THREADS_CLIENT_ID=
THREADS_CLIENT_SECRET=
THREADS_REDIRECT_URL=/threads/callback

ユースケースのコールバックURLのリダイレクト先を設定。
httpsが必須。localhostでも保存はできるけど実際には動かないかもしれない。
面倒なので最初からサーバーに公開して動かすのが早い。

コールバックURLリダイレクト:https://example.com/threads/callback
他2つは同じでもhttps://example.com/でもいい。必要なら後で設定。

routes/web.phpでの例。

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Laravel\Socialite\Facades\Socialite;
use Revolution\Threads\Facades\Threads;

Route::get('threads/redirect', function () {
    return Socialite::driver('threads')->redirect();
})->middleware('auth');

Route::get('threads/callback', function (Request $request) {
    if ($request->missing('code')) {
        dd($request);
    }

    /** @var \Laravel\Socialite\Two\User $user */
    $user = Socialite::driver('threads')->user();

    dump($user);

    $long_token = Threads::exchangeToken($user->token, config('services.threads.client_secret'))['access_token'];
    dump($long_token);

    $request->user()->fill(['threads_token' => $long_token])->save();

})->middleware('auth');

いつものSocialiteだけどThreads::exchangeToken()で短期トークンから長期トークンへの変換が必要。
長期トークンさえ取得できれば後はThreadsテスターと同じ。

長期トークンの更新

ここまでは省略してるけど使う時に毎回更新するか、タスクスケジュールで定期的に更新する。

use Revolution\Threads\Facades\Threads;

$token = Threads::token($user->threads_token)->refreshToken()['access_token'] ?? null;
$user->fill(['threads_token' => $token])->save();

更新

  • 2025/06 v0.3以降のパッケージでは返り値をarrayからIlluminate\Http\Client\Responseに変更しているので記事内のコードは古いかもしれない。
投稿者 Invokable
1件のコメントを読むにはログインしてください。
登録 ログイン