iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
Modern Web

30 天上手! PHP 微服務入門與開發系列 第 5

第五章、Anser-Service:Action 微服務溝通的最小單位 - PHP 微服務入門與開發

  • 分享至 

  • xImage
  •  

如同第三章所介紹的,Anser 分為三大部分。在這個單元中,將會聚焦在「Service」的設計理念與各類別的使用方式。

上圖顯示的是一個簡單的 Service 子系統元件或類別的相依關係圖。

  1. Action:
    Anser 是一款以 HTTP 連線為核心的程式庫,在 Anser 中所有的連線都是由 Action 物件負責,Action 物件掌管所有 HTTP 連線請求與回應的過程。除此之外,並行連線和過濾器都與 Action 物件有密不可分的關係。
  2. Service List:
    Service List 允許開發人員在使用 Action 前預先定義所有所需的服務連線內容,藉由統一的類別管理整個系統中可能需要溝通的微服務連線資訊。
  3. Simple Service:
    開發人員可以繼承程式庫內的 SimpleService 類別進行微服務 API 抽象化的作業,透過繼承這個基本類別,能夠統一管理連線至相同服務且具有內聚性的 Action 物件。
  4. Filter:
    開發人員能夠藉由實作 Filter Interface ,定義在 Action 對微服務發出請求前,或是接受到回應後自動執行的程式邏輯。
  5. Concurrent Action Class:
    若是需要以並行請求(Concurrent Request)執行 HTTP 連線,需要將此類別實體化並傳入所需並行連線的 Action 實體。

Anser-Action

在這篇文章中我們會使用到 Production Service 與 Main App,請參考第四章節所提到的內容建立你的本地開發環境。

你可以透過 Command Line 介面 cd 至專案根目錄,使用 docker compose up -d 分別打開你的本地範例微服務與開發環境。

安裝

首先,先將 Command Line 定位至 Main Service 專案根目錄,並透過 docker compose exec app bash 進入到專案的 docker 容器之中。

接著,使用以下指令安裝 anser-action 程式庫。

composer require sdpmlab/anser-action

順利的話,你會看到以下畫面響應,等待它們安裝完畢即可。

當安裝完畢後,你的 Main Service 目錄可能會長得像是這個樣子:

直接服務連線

我們建立一個名為 action_test.php 的 PHP 檔案,並貼上以下內容:

<?php
require_once './vendor/autoload.php';

use \SDPMlab\Anser\Service\Action;
use \Psr\Http\Message\ResponseInterface;

$action = (new Action(
    serviceName: "https://httpbin.org",
    method: "GET",
    path: "/get"
))->doneHandler(static function(
    ResponseInterface $response,
    Action $runtimeAction
){
    $body = $response->getBody()->getContents();
    $data = json_decode($body, true);
    $runtimeAction->setMeaningData($data);
});

$data = $action->do()->getMeaningData();

header("Content-Type: application/json");
echo json_encode($data);

這是一個 httpbin.org 的測試連線。首先我們透過 new Action() 定義一個 Action 物件,在建構 Action 物件時你需要傳入三個參數,分別是:

  1. string $serviceName:服務名稱或端點網址(Endpoint URL)
  2. string $method:本次連線的 HTTP 動詞
  3. string $path:資源的路徑

接著,我們透過設定 doneHandler 去定義當 http 連線執行成功時的處理行為,這裡是透過 json_decode 的方式解析 HTTP Response Body 。

最後關注第 19 行。執行 Action 的 do() 方法即可發出 HTTP 請求,再以 getMeaningData() 取得在 doneHandler 中解析完畢的資料。

你可以透過 Command Line 介面在容器內執行:

php action_test.php

順利的話你會看見下述響應畫面:

或者是透過 postman 以 HTTP 連線執行你的測試用 PHP,像這樣:

當看到上述畫面,代表你成功地在你的環境中透過 Action 物件進行了一個 HTTP Get 請求,並成功處理響應後的 Response Body ,經過解析後再轉由 PHP 進行結果輸出。

Service List

Anser 提供能夠被全域呼叫的物件 ServiceList,這個物件採用單例設計模式(Singleton Pattern)實作,它包含了服務的連線清單以及唯一且共用的 HTTP-Client 物件。

開發人 員能夠依據應用的框架或軟體架構的不同,在任何合適的執行期間(Runtime)透過 ServiceList 提供的靜態方法定義服務的名稱、IP 位置、連接埠以及 SSL 相關設定:

  • setLocalServices():傳入 key/value 陣列,在一次的呼叫中設定所有的參與的微服務。
  • addLocalService():僅設定一組微服務資訊,並將此資訊加入到全域的 localServiceList

無論你採用哪種方式宣告你的服務,它們都需要傳入下列參數進行設定:

  • string $name:服務名稱,在 Action 物件中能夠以這個名稱代表現在所設定的這個服務
  • string $address:服務連線位置,可以是 IP、Domain 或是本系列文章所使用範例 Docker Compose Service Name
  • int $port:填入目標服務的 HTTP 服務 Port
  • bool $isHttps:是否採用加密連線

讓我們來試試看吧!

在你的開發環境中建立一個 init.php 並鍵入下列內容:

<?php

require_once './vendor/autoload.php';

use SDPMlab\Anser\Service\ServiceList;

ServiceList::addLocalService(
    name: "ProductionService",
    address: "production-service",
    port: 8080,
    isHttps: false
);

//等同於
// ServiceList::setLocalServices([
//     [
//         "name" => "ProductionService",
//         "address" => "production-service",
//         "port" => 8080,
//         "isHttps" => false
//     ],
// ]);

在上述檔案中,在第 2 行處理了 Composer 自動載入,接著從第 6 行開始設定第一個服務連線資訊。

無論是第 8 行的 setLocalServices() 或是第 16 行的 setLocalServices() ,他們的效果都是一樣的,你可以依照你的開發喜好選擇你想要的方式宣告。

而當你做完了服務宣告後, Anser 內的所有類別將會依照 ServiceList 中的成員變數 localServiceList 來取得微服務的連線資訊。

在你的開發環境中再建立一個新檔案 get_product.php ,貼上以下內容:

<?php

require_once './init.php';

use SDPMlab\Anser\Service\Action;
use Psr\Http\Message\ResponseInterface;

$action = (new Action(
    serviceName: "ProductionService",
    method: "GET",
    path: "/api/v1/products"
))->doneHandler(static function(
    ResponseInterface $response,
    Action $runtimeAction
){
    $body = $response->getBody()->getContents();
    $data = json_decode($body, true);
    $runtimeAction->setMeaningData($data);
});

$data = $action->do()->getMeaningData();

header("Content-Type: application/json");
echo json_encode($data) . PHP_EOL;

你依舊可以選擇使用 Command 介面或 Postman 執行你的程式碼,順利的話你會看見來自於 Production Service 的響應結果,我們將可以獲得產品清單:

由於我們在 init.php 中已經進行了 require_once './vendor/autoload.php'; ,所以在 get_product.php 中我們只需要 require_once './init.php'。同時,init.php 也替我們宣告了所需的 Service。

你可以關注第 8 行,我們只需要傳入正確的 Service Name ,即可以透過在 ServiceList 中宣告的連線資訊驅動 Action 往目標 Service 發出請求。

結語

透過本章的介紹,讀者應能大抵理解 Anser 的 Service 子系統如何運作,以及其所包含的核心元件如 Action、Service List 的基本使用方法,以及其他元件的粗略介紹。

透過 Action 物件,我們希望 HTTP 連線變得簡單,還可以透過各種 Handler 與 Filter 定義出極具彈性的連線行為。加上 Service List 的協助,開發者能統一管理所有的微服務連線資訊,大大提高開發效率及維護性。


上一篇
第四章、開發環境設定與部署範例微服務 - PHP 微服務入門與開發
下一篇
第六章、Anser-Service:並行處理連線請求 - PHP 微服務入門與開發
系列文
30 天上手! PHP 微服務入門與開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言