Laravel中怎麼用Saloon進行API整合?以下這篇文章為大家介紹一下在Laravel中使用Saloon進行API整合的方法,希望對大家有幫助!
我們都去過那裡,我們想與 Laravel 中的第三方 API 集成,我們問自己「我應該怎麼做?」。談到 API 集成,我並不陌生,但每次我都想知道什麼是最好的方法。 Sam Carré 於 2022 年初建立了一個 package,名為 Saloon,這可以讓我們的 API 整合令人驚嘆。然而,這篇文章將會非常不同,這將是一個關於如何使用它從頭開始建立整合的演練。
就像所有很棒的事情一樣,它以laravel new
開始並從那裡開始,所以讓我們開始吧。現在在安裝 Laravel 時,你可以使用 laravel installer
或 composer
——這部分由你決定。如果可以的話,我會推薦安裝程序,因為它提供了簡單的選項來做更多的事情,而不僅僅是創建一個專案。建立一個新專案並在您選擇的程式碼編輯器中開啟它。一旦我們在那裡,我們就可以開始了。
我們要建造什麼?我很高回答這個提問!我們將建立與 GitHub API 的集成,以取得可用於 repo 的工作流程清單。現在,如果你像我一樣在命令列上花費大量時間,這可能會非常有用。你正在開發一個應用程序,將更改推送到一個分支或創建一個 PR - 它通過一個可能正在運行許多其他事情之一的工作流程。了解此工作流程的狀態有時會對您接下來的工作產生巨大影響。功能齊全嗎?我們的工作流程運作是否有問題?我們的測試或靜態分析是否通過了?所有這些你通常會等待並檢查 GitHub 上的 repo 以查看狀態。此整合將允許您運行 artisan 命令,獲取 repo 的可用工作流程列表,並允許您觸發新的工作流程運行。
所以到目前為止,composer 應該已經完成了它的工作並安裝了一個完美的起點,一個 Laravel 應用程式。接下來我們需要安裝 Saloon - 但我們要確保安裝 laravel 版本,所以在終端中運行以下命令:
composer require sammyjo20/saloon-laravel
就像這樣,我們已經離更容易的整合更近了一步。如果你在這個階段有任何問題,請確保檢查您正在使用的 Laravel 和 PHP 版本,因為 Saloon 至少需要 Laravel 8 和 PHP 8!
所以,現在我們已經安裝了 Saloon,我們需要建立一個新類別。在 Saloons 術語中,這些是“連接器”,連接器所做的一切就是創建一種以物件為中心的方式來表達 - 此 API 透過此類連接。有一個方便的artisan 命令允許您創建這些,因此運行以下artisan 命令來創建GitHub 連接器:
php artisan saloon:connector GitHub GitHubConnector
該命令分為兩部分,第一個參數是您正在創建的集成,第二個參數是要建立的連接器的名稱。這意味著你可以為整合創建多個連接器 - 如果需要的話可以透過多種不同方式進行連接。
這將在 app/Http/Integrations/GitHub/GitHubConnector.php
下為你建立一個新類,讓我們看一下,了解發生了什麼。
我們看到的第一件事是我們的連接器擴展了“SaloonConnector”,這將使我們能夠讓我們的連接器在沒有大量樣板程式碼的情況下工作。然後我們繼承了一個名為「AcceptsJson」的特徵。現在,如果我們查看 Saloon 文檔,我們知道這是一個插件。這基本上為我們的請求添加了一個標頭,告訴第 3 方 API 我們想要接受 JSON 回應。接下來我們看到的是我們有一個方法來定義我們的連接器的基本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'); }
如你所見,我們現在從配置中獲取新添加的記錄- 並將其轉換為字串以確保類型安全- 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怎麼用Saloon進行API集成的詳細內容。更多資訊請關注PHP中文網其他相關文章!