ホームページ  >  記事  >  PHPフレームワーク  >  Laravel で API 統合に Saloon を使用する方法について話しましょう

Laravel で API 統合に Saloon を使用する方法について話しましょう

青灯夜游
青灯夜游転載
2022-10-27 19:28:341164ブラウズ

Laravel で API 統合に Saloon を使用するにはどうすればよいですか?以下の記事では、Saloonを使ってLaravelでAPI連携を行う方法を紹介しますので、ご参考になれば幸いです。

Laravel で API 統合に Saloon を使用する方法について話しましょう

#私たちは皆、Laravel でサードパーティ API と統合したいと考え、「どうすればよいでしょうか?」と自問したことがあります。私は API 統合に関してはよく知っていますが、毎回、最善のアプローチは何だろうと考えます。 Sam Carré は、2022 年初頭に Saloon と呼ばれる パッケージ を構築し、API 統合を素晴らしいものにしました。ただし、この投稿は大きく異なり、それを使用して統合を最初から構築する方法についてのチュートリアルになります。

すべての優れたものと同様、laravel new から始まり、そこから始まります。それでは、始めましょう。 Laravel をインストールするときに、laravel installer または composer を使用できます。この部分はあなた次第です。可能であれば、インストーラーを使用することをお勧めします。インストーラーには、プロジェクトを作成するだけではない簡単なオプションが用意されています。新しいプロジェクトを作成し、選択したコード エディターで開きます。到着したら準備完了です。

何を構築するのでしょうか?この質問に答えられることをとても嬉しく思います! GitHub API との統合を構築して、リポジトリで利用可能なワークフローのリストを取得します。あなたが私と同じで、コマンド ラインに多くの時間を費やしている場合、これは非常に便利です。アプリケーションを開発し、変更をブランチにプッシュしたり PR を作成したりすると、他の多くの作業の 1 つを実行している可能性があるワークフローが実行されます。このワークフローのステータスを把握すると、次に行う作業に大きな影響を与える場合があります。完全に機能しますか?ワークフローの実行方法に問題はありますか?テストや静的分析は合格しますか?通常、これらすべてを待って、GitHub 上のリポジトリをチェックしてステータスを確認します。この統合により、artisan コマンドを実行し、リポジトリで使用可能なワークフローのリストを取得し、新しいワークフローの実行をトリガーできるようになります。

つまり、composer はその仕事を完了し、完璧な出発点である Laravel アプリケーションをインストールしているはずです。次に、Saloon をインストールする必要がありますが、laravel バージョンを確実にインストールしたいので、ターミナルで次のコマンドを実行します。

composer require sammyjo20/saloon-laravel

このようにして、より簡単な統合に一歩近づきました。この段階で質問がある場合は、Saloon には少なくとも Laravel 8 と PHP 8 が必要であるため、使用している Laravel と PHP のバージョンを必ず確認してください。

Saloon をインストールしたので、新しいクラスを作成する必要があります。サルーンの用語では、これらは「コネクタ」であり、コネクタが行うことは、そのような接続を通じてこの API を表現するためのオブジェクト中心の方法を作成することだけです。これらを作成できる便利な職人コマンドがあるため、次の職人コマンドを実行して GitHub コネクタを作成します。

php artisan saloon:connector GitHub GitHubConnector

コマンドは 2 つの部分に分かれており、最初のパラメータは作成している統合です。 2 番目のパラメータは、作成するコネクタの名前です。これは、統合用に複数のコネクタを作成し、必要に応じてさまざまな方法で接続できることを意味します。

これにより、app/Http/Integrations/GitHub/GitHubConnector.php に新しいクラスが作成されます。何が起こっているのかを理解するために見てみましょう。

最初にわかるのは、コネクタが「SaloonConnector」を拡張していることです。これにより、多くの定型コードなしでコネクタを機能させることができます。次に、「AcceptsJson」という機能を継承します。 Saloon のドキュメントを見ると、これがプラグインであることがわかります。これは基本的に、リクエストにヘッダーを追加して、JSON レスポンスを受け入れたいことをサードパーティ API に伝えます。次に表示されるのは、コネクタのベース URL を定義するメソッドがあることです。次のコードを追加しましょう:

public function defineBaseUrl(): string
{
    return 'https://api.github.com';
}

すっきりしています。さらに一歩進めて、ルーズな処理を減らすこともできます。アプリケーション内の文字列 - それでは、これを行う方法を見てみましょう。 config/services.php ファイルに新しいサービス レコードを追加します:

'github' => [
    'url' => env('GITHUB_API_URL', 'https://api.github.com'),
]

これにより、さまざまな環境でサービス レコードを上書きできるようになり、ソリューションがより適切かつテストしやすくなります。ローカルでは、OpenAPI 仕様を使用して GitHub API をモックし、それが適切に動作することを確認するためにテストすることもできます。ただし、このチュートリアルは Saloon に関するものなので、話は逸れます... 次に、構成を使用するために基本的な URL メソッドをリファクタリングしましょう:

public function defineBaseUrl(): string
{
    return (string) config('services.github.url');
}

ご覧のとおり、新しく追加されたものを構成 Logging - から取得します。型安全性を確保するためにそれを文字列に変換します - config() はいくつかの異なるタイプの結果を返す場合があります。できればこれについては厳しくしたいと思っています。

接下来我们有默认 header 和默认配置,无须担心默认 header 的内容,因为我们将在一段时间内自行处理身份验证。但配置部分是我们可以为集成定义 guzzle 选项的地方,因为 Saloon 在服务引擎下使用了 Guzzle。现在让我们设置超时并继续,我们需要花一些时间配置它:

public function defaultConfig(): array
{
    return [
        'timeout' => 30,
    ];
}

我们现在已经按照我们的需要配置了我们的连接器,如果我们有需要添加的配置,可以稍后再添加。下一步是开始考虑我们要发送的请求。如果我们查看 GitHub Actions API 的 API 文档,我们有很多选择,我们将从列出特定存储库的工作流开始:/repos/{owner}/{repo}/actions/workflows。运行以下 artisan 命令创建一个新请求:

php artisan saloon:request GitHub ListRepositoryWorkflowsRequest

同样,第一个参数是集成,第二个参数是我们要创建的请求的名称。我们需要确保为我们正在创建的请求命名集成,以便它存在于正确的位置,然后我们需要给它一个名称。我将我的命名为 ListRepositoryWorkflowsRequest,因为我喜欢描述性的命名方法 - 但是,你可以随意调整以适应你喜欢的命名方式。这将创建一个新文件供我们查看:app/Http/Integrations/GitHub/Requests/ListRepositoryWorkflowsRequest.php - 现在让我们看一下。

我们再次在这里扩展了一个库类,这次是预期的 SaloonRequest。这里会包含一个连接器属性和一个方法。如果需要,我们可以修改这个方法 - 但默认的 GET 是我们现在需要的。然后我们有一个定义端点的方法。重构你的请求类,使其类似于以下示例:

 class ListRepositoryWorkflowsRequest extends SaloonRequest
{
    protected ?string $connector = GitHubConnector::class;

    protected ?string $method = Saloon::GET;

    public function __construct(
        public string $owner,
        public string $repo,
    ) {}

    public function defineEndpoint(): string
    {
        return "/repos/{$this->owner}/{$this->repo}/actions/workflows";
    }
}

我们所做的是添加一个构造函数,它接受 repo 和 owner 作为参数,然后我们可以在端点定义方法中使用它们。我们还将连接器设置为我们之前创建的 GitHubConnector。所以我们有一个我们知道可以发送的请求,我们可以从集成中走一小步,转而考虑控制台命令。

如果你之前没有在 Laravel 中创建过控制台命令,请务必查看 文档。运行以下 artisan 命令来为此集成创建第一个命令:

php artisan make:command GitHub/ListRepositoryWorkflows

这将创建以下文件:app/Console/Commands/GitHub/ListRespositoryWorkflows.php。我们现在可以开始使用命令来发送请求并获取我们关心的数据。当谈到控制台命令时,我总是做的第一件事就是考虑签名。我希望如何调用它?它需要能够解释它正在做什么,同时具备一定的辨识度。我将会用 github:workflows 作为签名,因为这很好地解释了我想做的事情。我们还可以向控制台命令添加描述,以便在浏览可用命令时更好地解释目的:「通过存储库名称从 GitHub 获取工作流列表」。

最后,我们到了命令的 handle 方法,这部分是我们实际需要做的事情。在我们的例子中,我们将发送一个请求,获取一些数据并以某种方式显示这些数据。然而,在我们能够做到这一点之前,我们还没有完成一件事。那就是身份验证。

对于每一个 API 集成,身份验证都是关键方面之一——我们需要 API 不仅知道我们是谁,而且知道我们实际上被允许发出这个请求。如果你转到 你的 GitHub 设置 并点击进入开发人员设置和个人访问令牌,在此你可以生成自己的设置。我建议使用这种方法,而不是为此使用完整的 OAuth 应用程序。我们不需要 OAuth,我们只需要用户能够访问他们需要的内容。

获得访问令牌后,我们需要将其添加到我们的 .env 文件中,并确保我们可以通过配置提取它。

GITHUB_API_TOKEN=ghp_loads-of-letters-and-numbers-here

我们现在可以在 github 下的 config/services.php 中扩展我们的服务,添加这个令牌:

'github' => [
    'url' => env('GITHUB_API_URL', 'https://api.github.com'),
    'token' => env('GITHUB_API_TOKEN'),
]

现在我们有了一个加载这个令牌的好方法,我们可以回到我们的控制台命令!我们需要修改我们的签名以允许我们接受所有者和存储库作为参数:

 class ListRepositoryWorkflows extends Command
{
    protected $signature = 'github:workflows
        {owner : The owner or organisation.}
        {repo : The repository we are looking at.}
    ';

    protected $description = 'Fetch a list of workflows from GitHub by the repository name.';

    public function handle(): int
    {
        return 0;
    }
}

现在我们可以将注意力转移到 handle 方法上:

public function handle(): int
{
    $request = new ListRepositoryWorkflowsRequest(
        owner: $this->argument('owner'),
        repo: $this->argument('repo'),
    );

    return self::SUCCESS;
}

在这里,我们开始通过将参数直接传递到请求本身来构建我们的请求,但是我们可能想要做的是创建一些局部变量来提供一些控制台反馈:

 public function handle(): int
{
    $owner = (string) $this->argument('owner');
    $repo = (string) $this->argument('repo');

    $request = new ListRepositoryWorkflowsRequest(
        owner: $owner,
        repo: $repo,
    );

    $this->info(
        string: "Fetching workflows for {$owner}/{$repo}",
    );

    return self::SUCCESS;
}

所以我们有一些反馈给用户,这对于控制台命令来说总是很重要的。现在我们需要添加我们的身份验证令牌并实际发送请求:

 public function handle(): int
{
    $owner = (string) $this->argument('owner');
    $repo = (string) $this->argument('repo');

    $request = new ListRepositoryWorkflowsRequest(
        owner: $owner,
        repo: $repo,
    );

    $request->withTokenAuth(
        token: (string) config('services.github.token'),
    );

    $this->info(
        string: "Fetching workflows for {$owner}/{$repo}",
    );

    $response = $request->send();

    return self::SUCCESS;
}

如果你修改上述内容并在 $response->json() 上执行 dd(),然后运行命令:

php artisan github:workflows laravel laravel

这将获得 laravel/laravel repo 的工作流列表。我们的命令将允许你使用任何公共存储库,如果你希望它更具体,你可以建立一个要检查的存储库选项列表,而不是接受参数 —— 但这部分取决于你个人。对于本教程,我将重点关注更广泛更开放的用例。

现在,我们从 GitHub API 得到的响应非常好且信息丰富,但它需要转换才能显示,如果我们孤立地查看它,则没有上下文。相反,我们将在我们的请求中添加另一个插件,这将允许我们将响应转换为 DTO(域传输对象),这是处理此问题的好方法。它将允许我们放松我们习惯于从 API 获取的灵活数组,并获得更具上下文感知的东西。让我们为工作流创建一个 DTO,创建一个新文件:app/Http/Integrations/GitHub/DataObjects/Workflow.php 并向其中添加以下代码:

 class Workflow
{
    public function __construct(
        public int $id,
        public string $name,
        public string $state,
    ) {}

    public static function fromSaloon(array $workflow): static
    {
        return new static(
            id: intval(data_get($workflow, 'id')),
            name: strval(data_get($workflow, 'name')),
            state: strval(data_get($workflow, 'state')),
        );
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'state' => $this->state,
        ];
    }
}

我们有一个构造函数,其中包含我们要显示的工作流的重要部分,一个 fromSaloon 方法,它将一个数组从一个 saloon 转换为一个新的 DTO,以及一个用于将 DTO 显示回数组的数组方法当我们需要它时。在我们的ListRepositoryWorkflowsRequest 中,我们需要继承一个新特征并添加一个新方法:

 class ListRepositoryWorkflowsRequest extends SaloonRequest
{
    use CastsToDto;

    protected ?string $connector = GitHubConnector::class;

    protected ?string $method = Saloon::GET;

    public function __construct(
        public string $owner,
        public string $repo,
    ) {}

    public function defineEndpoint(): string
    {
        return "/repos/{$this->owner}/{$this->repo}/actions/workflows";
    }

    protected function castToDto(SaloonResponse $response): Collection
    {
        return (new Collection(
            items: $response->json('workflows'),
        ))->map(function ($workflow): Workflow {
            return Workflow::fromSaloon(
                workflow: $workflow,
            );
        });
    }
}

我们继承了 CastsToDto trait,它允许这个请求在响应中调用 dto 方法,然后我们添加一个 castToDto 方法,我们可以控制它的转换方式。我们希望它返回一个新的集合,因为有多个工作流,使用响应正文的工作流部分。然后我们映射集合中的每个项目 - 并将其转换为 DTO。现在我们既可以这样做,也可以使用 DTO 构建集合:

protected function castToDto(SaloonResponse $response): Collection
{
    return new Collection(
        items: $response->collect('workflows')->map(fn ($workflow) =>
            Workflow::fromSaloon(
                workflow: $workflow
            ),
        )
    );
}

你可以在这里选择最适合你的方式。我个人更喜欢第一种方法,因为我喜欢逐步了解逻辑,但是这两种方法都没有错——选择权在你。现在回到命令,我们现在需要考虑我们希望如何显示这些信息:

public function handle(): int
{
    $owner = (string) $this->argument('owner');
    $repo = (string) $this->argument('repo');

    $request = new ListRepositoryWorkflowsRequest(
        owner: $owner,
        repo: $repo,
    );

    $request->withTokenAuth(
        token: (string) config('services.github.token'),
    );

    $this->info(
        string: "Fetching workflows for {$owner}/{$repo}",
    );

    $response = $request->send();

    if ($response->failed()) {
        throw $response->toException();
    }

    $this->table(
        headers: ['ID', 'Name', 'State'],
        rows: $response
            ->dto()
            ->map(fn (Workflow $workflow) =>
                  $workflow->toArray()
            )->toArray(),
    );

    return self::SUCCESS;
}

因此,我们创建一个带有标题的表,然后对于我们想要响应 DTO 的行,我们将映射返回的集合,将每个 DTO 转换回要显示的数组。从响应数组转换为 DTO 再转换回数组,这似乎违反直觉,但这会强制执行类型,以便 ID、名称和状态在预期时始终存在,并且不会给出任何有趣的结果.它允许正常响应数组可能没有它的一致性,如果我们愿意,我们可以将它转换为一个值对象,我们可以在其中附加行为。如果我们现在运行我们的命令,我们现在应该会看到一个漂亮的表格输出,它比几行字符串更容易阅读:

php artisan github:workflows laravel laravel
Fetching workflows for laravel/laravel
+----------+------------------+--------+
| ID       | Name             | State  |
+----------+------------------+--------+
| 12345678 | pull requests    | active |
| 87654321 | Tests            | active |
| 18273645 | update changelog | active |
+----------+------------------+--------+

最后,仅仅列出这些工作流程是很棒的——但让我们以科学的名义更进一步。假设你正在针对你的一个存储库运行此命令,并且想手动运行更新更改日志?或者,也许你希望使用你的实时生产服务器或你可能想到的任何事件在 cron 上触发它?我们可以将变更日志设置为每天午夜运行一次,这样我们就可以在变更日志中获得每日回顾或任何我们可能想要的内容。让我们创建另一个控制台命令来创建一个新的工作流调度事件:

php artisan saloon:request GitHub CreateWorkflowDispatchEventRequest

在这个新文件 app/Http/Integrations/GitHub/Requests/CreateWorkflowDispatchEventRequest.php 中添加以下代码,以便我们浏览它:

class CreateWorkflowDispatchEventRequest extends SaloonRequest
{
    use HasJsonBody;

    protected ?string $connector = GitHubConnector::class;

    public function defaultData(): array
    {
        return [
            'ref' => 'main',
        ];
    }

    protected ?string $method = Saloon::POST;

    public function __construct(
        public string $owner,
        public string $repo,
        public string $workflow,
    ) {}

    public function defineEndpoint(): string
    {
        return "/repos/{$this->owner}/{$this->repo}/actions/workflows/{$this->workflow}/dispatches";
    }
}

通过设置连接器,并继承 HasJsonBody 特征以允许我们发送数据。该方法已设置为 POST 请求,因为我们要发送数据。然后我们有一个构造函数,它接受构建端点的 URL 部分。

最后,我们在 defaultData 中有圆顶默认数据,我们可以使用它来设置此发布请求的默认值。与 repo 一样,我们可以在此处传递提交哈希或分支名称 - 所以我将默认设置为 main,因为这就是我通常所说的生产分支。

我们现在可以触发这个端点来调度一个新的工作流事件,所以让我们创建一个控制台命令来控制它,这样我们就可以从我们的 CLI 运行它:

php artisan make:command GitHub/CreateWorkflowDispatchEvent

现在让我们编写具体的逻辑,我们可以了解正在发生的事情:

class CreateWorkflowDispatchEvent extends Command
{
    protected $signature = 'github:dispatch
        {owner : The owner or organisation.}
        {repo : The repository we are looking at.}
        {workflow : The ID of the workflow we want to dispatch.}
        {branch? : Optional: The branch name to run the workflow against.}
    ';

    protected $description = 'Create a new workflow dispatch event for a repository.';

    public function handle(): int
    {
        $owner = (string) $this->argument('owner');
        $repo = (string) $this->argument('repo');
        $workflow = (string) $this->argument('workflow');

        $request = new CreateWorkflowDispatchEventRequest(
            owner: $owner,
            repo: $repo,
            workflow: $workflow,
        );

        $request->withTokenAuth(
            token: (string) config('services.github.token'),
        );

        if ($this->hasArgument('branch')) {
            $request->setData(
                data: ['ref' => $this->argument('branch')],
            );
        }

        $this->info(
            string: "Requesting a new workflow dispatch for {$owner}/{$repo} using workflow: {$workflow}",
        );

        $response = $request->send();

        if ($response->failed()) {
            throw $response->toException();
        }

        $this->info(
            string: 'Request was accepted by GitHub',
        );

        return self::SUCCESS;
    }
}

就像在我们有签名和描述之前一样,这次我们的签名有一个可选的分支,以防我们想要覆盖请求中的默认值。所以在我们的处理方法中,我们可以简单地检查输入是否有参数 branch,如果有,我们可以解析它并为请求设置数据。然后我们向 CLI 提供一些反馈,让用户知道我们在做什么 - 并发送请求。如果此时一切顺利,我们可以简单地输出一条消息,通知用户 GitHub 接受了请求。但是,如果出现问题,我们希望抛出特定的异常,至少在开发过程中是这样。

最后一个请求的主要警告是,我们的工作流程设置为通过在工作流程中添加一个新的 on 项目来由 webhook 触发:

on: workflow_dispatch

这就对了!我们使用 Saloon 和 Laravel 不仅列出存储库工作流程,而且如果配置正确,我们还可以触发它们按需运行:muscle:

正如我在本教程开始时所说的,有很多方法可以实现 API 集成,但有一点是肯定的 - 使用 Saloon 使它变得干净和简单,而且使用起来也非常愉快。

原文地址:https://laravel-news.com/api-integrations-using-saloon-in-laravel

译文地址:https://learnku.com/laravel/t/69007

【相关推荐:laravel视频教程

以上がLaravel で API 統合に Saloon を使用する方法について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。