lushdigital/microservice-aggregator-transport

一套方便的类和接口,用于简化从多个微服务聚合数据的操作。

1.1.1 2017-12-05 11:14 UTC

This package is not auto-updated.

Last update: 2024-09-23 07:35:24 UTC


README

一套方便的类和接口,用于简化从多个微服务聚合数据的操作。

该包的目的是提供一种可靠、可测试且易于使用的通信方式,用于在面向服务的架构中与微服务进行交互。

包内容

  • 服务接口
  • 服务抽象类
  • 云服务接口
  • 云服务抽象类
  • 请求类

安装

按正常方式安装该包

$ composer require lushdigital/microservice-aggregator-transport

src/config/transport.php 文件复制到您的应用程序根目录下的 config 文件夹中。

最后,将以下行添加到您的 bootstrap/app.php 文件中

$app->configure('transport');

创建服务

要使用此包,您首先需要创建一个与您的服务交互的类。

此类将扩展此包提供的基类之一;您为要访问的服务每个端点添加自己的方法。

本地服务

当您可以通过某种本地DNS与服务通信时,使用“本地”服务。在这种情况下,您不需要调用互联网来访问服务。例如,您可能正在使用 Kubernetes DNS

在您创建云服务之前,您需要确保以下配置选项已设置(显式或通过环境变量)

  • transport.branch - CI分支。例如master。
  • transport.environment - CI环境。例如dev或staging。

然后为每个本地服务,您必须定义

  • transport.services.local.SERVICE_NAME.uri - 本地服务的URI。

您还可以可选地指定服务的版本

  • transport.services.local.SERVICE_NAME.version - 本地服务的版本。

要创建本地服务,您需要扩展 \LushDigital\MicroserviceAggregatorTransport\Service

<?php
/**
 * @file
 * Contains \App\Services\MyAwesomeService.
 */

namespace App\Services;

use LushDigital\MicroserviceAggregatorTransport\Service as BaseService;
use LushDigital\MicroserviceAggregatorTransport\Request;
use App\Models\Thing;

/**
 * Transport layer for my awesome service.
 *
 * @package App\Services
 */
class MyAwesomeService extends BaseService
{
    /**
     * Save a thing.
     *
     * @param Thing $thing
     *     The thing to save.
     *
     * @return array 
     */
    public function saveAThing(Thing $thing)
    {
        // Create the request.
        $request = new Request('things', 'POST', $thing->toArray());

        // Do the request.
        $this->dial($request);
        $response = $this->call();

        return !empty($response->data->things) ? $response->data->things : [];
    }
}

如你所见,在这个服务中我们创建了一个调用 POST 端点来保存某个东西的方法。

云服务

当您需要通过互联网与服务通信时,使用云服务。假设服务是通过某种API网关访问的,并且无法直接访问。

在您创建云服务之前,您需要确保以下配置选项已设置(显式或通过环境变量)

  • transport.branch - CI分支。例如master。
  • transport.domain - 服务环境的顶级域名。
  • transport.gateway_uri - API网关的URI。
  • transport.environment - CI环境。例如dev或staging。

然后为每个云服务,您必须定义

  • transport.services.cloud.SERVICE_NAME.uri - 云服务的URI。
  • transport.auth.SERVICE_NAME.email - 用于访问云服务的服务账户的电子邮件地址。
  • transport.auth.SERVICE_NAME.password - 用于访问云服务的服务账户的密码。

您还可以可选地指定服务的版本

  • transport.services.cloud.SERVICE_NAME.version - 云服务的版本。

然后您可以定义您的服务

<?php
/**
 * @file
 * Contains \App\Services\MyAwesomeService.
 */

namespace App\Services;

use LushDigital\MicroserviceAggregatorTransport\CloudService;
use LushDigital\MicroserviceAggregatorTransport\Request;
use App\Models\Thing;

/**
 * Transport layer for my awesome cloud service.
 *
 * @package App\Services
 */
class MyAwesomeCloudService extends CloudService
{
    /**
     * Save a thing.
     *
     * @param Thing $thing
     *     The thing to save.
     *
     * @return array 
     */
    public function saveAThing(Thing $thing)
    {
        // Create the request.
        $request = new Request('things', 'POST', $thing->toArray());

        // Do the request.
        $this->dial($request);
        $response = $this->call();

        return !empty($response->data->things) ? $response->data->things : [];
    }
}

如您所见,服务看起来与本地服务非常相似。唯一的主要区别是基类。基类处理了认证和API网关路由的重任,因此您不必这样做!

使用服务

一旦您创建了您的服务,就可以像使用任何其他PHP类一样使用它。想想看,就像在数据库环境中使用仓库对象一样。

在控制器中的示例用法

<?php
/**
 * @file
 * Contains \App\Http\Controllers\MyAwesomeController.
 */

namespace App\Http\Controllers;

use App\Models\Thing;
use App\Services\MyAwesomeService;
use App\Services\MyAwesomeCloudService;
use GuzzleHttp\Exception\BadResponseException;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Laravel\Lumen\Routing\Controller as BaseController;
use LushDigital\MicroserviceAggregatorTransport\ServiceInterface;

class MyAwesomeController extends BaseController
{
    /**
     * Transport layer for my awesome service.
     *
     * @var ServiceInterface
     */
    protected $myAwesomeService;
    
    /**
     * Transport layer for my awesome cloud service.
     *
     * @var ServiceInterface
     */
    protected $myAwesomeCloudService;
    
    /**
     * MyAwesomeController constructor.
     */
    public function __construct()
    {
        $this->myAwesomeService = new MyAwesomeService();
        $this->myAwesomeCloudService = new MyAwesomeCloudService();
    }
    
    /**
     * Create a new thing.
     *
     * @param Request $request
     * @return Response
     */
    public function storeThing(Request $request)
    {
        // Validate the request.
        $this->validate($request, ['name' => 'required|string']);
        
        try {
            // Prepare a thing.
            $thing = new Thing;
            $thing->fill($request->input());
               
            // Save a thing.
            $newThing = $this->myAwesomeService->saveAThing($thing);
            
            return response()->json($newThing, 200);
        } catch (BadResponseException $e) {
            return response()->json(null, 500);
        }
    }
    
    /**
     * Create a new thing.
     *
     * @param Request $request
     * @return Response
     */
    public function storeCloudThing(Request $request)
    {
        // Validate the request.
        $this->validate($request, ['name' => 'required|string']);
        
        try {
            // Prepare a thing.
            $thing = new Thing;
            $thing->fill($request->input());
               
            // Save a thing.
            $newThing = $this->myAwesomeCloudService->saveAThing($thing);
            
            return response()->json($newThing, 200);
        } catch (BadResponseException $e) {
            return response()->json(null, 500);
        }
    }
}

异步请求

在某些情况下,您可能需要快速连续地发出多个请求。这通常可以通过并发运行请求来改进。该包利用Guzzle的承诺来实现这一点。首先,您需要定义一个具有异步调用的服务

<?php
/**
 * @file
 * Contains \App\Services\MyAwesomeService.
 */

namespace App\Services;

use LushDigital\MicroserviceAggregatorTransport\Service as BaseService;
use LushDigital\MicroserviceAggregatorTransport\Request;
use GuzzleHttp\Promise\PromiseInterface;
use App\Models\Thing;

/**
 * Transport layer for my awesome service.
 *
 * @package App\Services
 */
class MyAwesomeService extends BaseService
{
    /**
     * Save a thing.
     *
     * @param Thing $thing
     *     The thing to save.
     * @param callable|null $onFulfilled
     *     Function to run on a successful call.
     * @param callable|null $onRejected
     *     Function to run on a rejected call. 
     *
     * @return PromiseInterface 
     */
    public function saveAsyncThing(Thing $thing, callable $onFulfilled = null, callable $onRejected = null)
    {
        // Create the request.
        $request = new Request('things', 'POST', $thing->toArray());

        // Do the request.
        $this->dial($request);
        
        return $this->callAsync($onFulfilled, $onRejected);
    }
}

然后您可以在您的控制器中使用这个服务

<?php
/**
 * @file
 * Contains \App\Http\Controllers\MyAwesomeController.
 */

namespace App\Http\Controllers;

use App\Models\Thing;
use App\Services\MyAwesomeService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Laravel\Lumen\Routing\Controller as BaseController;
use LushDigital\MicroserviceAggregatorTransport\ServiceInterface;
use GuzzleHttp\Exception\RequestException;
use Psr\Http\Message\ResponseInterface;

class MyAwesomeController extends BaseController
{
    /**
     * Transport layer for my awesome service.
     *
     * @var ServiceInterface
     */
    protected $myAwesomeService;
    
    /**
     * Transport layer for my awesome cloud service.
     *
     * @var ServiceInterface
     */
    protected $myAwesomeCloudService;
    
    /**
     * MyAwesomeController constructor.
     */
    public function __construct()
    {
        $this->myAwesomeService = new MyAwesomeService();
    }
    
    /**
     * Create a new thing.
     *
     * @param Request $request
     * @return Response
     */
    public function storeThing(Request $request)
    {
        // Validate the request.
        $this->validate($request, ['things.*.name' => 'required|string']);
        
        $promises = [];
        $things = [];
        foreach ($request->input('things') as $thingData) {
            // Prepare a thing.
            $thing = new Thing;
            $thing->fill($thingData);
            
            // Save a thing.
            $promises[] = $this->myAwesomeService->saveAsyncThing(
                $thing, 
                function (ResponseInterface $res) use (&$things) {
                    // Get the JSON response or exit if none.
                    $serviceResponse = json_decode($res->getBody());
                    if (empty($serviceResponse->data)) {
                        return null;
                    }
                
                    $things[] = $serviceResponse->data->things[0];
                },
                function (RequestException $e) {
                    Log::error(sprintf('Could not get thing. Reason: %s', $e->getMessage()));
                    return null;
                }
            );
        }
            
        return response()->json($things, 200);
    }
}