zemd/micro

此包已被 废弃 并不再维护。未建议替代包。

微服务路由和处理组件

1.0.0 2016-11-21 14:58 UTC

This package is not auto-updated.

Last update: 2023-02-04 10:31:05 UTC


README

轻量级领域驱动REST API架构

安装

composer require zemd/micro

使用

这是一种轻量级方法来管理REST API调用,将它们转换为漂亮的领域对象,并路由到处理器。这种方法可以避免在处理API请求时出现杂乱的样板代码。

因此,您有一些处理“请求”并返回一些数据的特定代码。这是一段独立的代码,可以放置在RabbitMQ消费者或其他网络位置。我们可以称之为 处理器,并定义每个这样的处理器都必须实现简单的方法 handle

由于这样的 处理器 不了解它接收的HTTP请求,因此在其参数中包含一些 命令 对象。它只是一个可序列化对象,可以通过任何传输机制传输而不会丢失数据。

class FeatureHandler implements HandlerInterface {
  public function handle(CommandInterface $command, $context) {
    // do stuff
    return "response";
  }
}

为了让它对某些路由器可访问,需要传递一些关于您的端点和其目标的 元信息。在端点可以物理地放置在不同服务器的系统中,您可以在目标服务中共享元信息,并以 HandlerMetaInterface 接口的实例返回收集到的信息。

class FeatureMetaInformation implements HandlerMetaInterface {
    public function getMethods() {
      return ['GET'];
    }
  
    // Unique string that match handler name, it should be possible to be constructed from request string
    public function getEndpoint() {
      return '/users/search';
    }
    
    public function getCommandGuesser() {
      return false; // If false returns getCommandClass() method will be used.
    }
    
    public function getCommandClass() {
      return 'my.command.as.service'; // or FeatureCommand::class
    }
  
    public function getDescription() {
      return 'Some cool feature';
    }
}

请记住在 services.yml 中标记您的元信息提供者

my.feature.handler.meta.information:
  class: Namespace\To\My\FeatureMetaInformation
  tags:
    - zemd.micro.handler_meta

现在我们有了信息和处理器,我们可以继续构建 命令。命令通过 CommandBuilder 自动构建,因此您只需通过传递使用注解的附加信息来定义它,并将其提供给构建器和处理器。

@RequestParam - 表示属性的值在请求中定义在期望的别名下,可以定义自定义模式进行验证,并设置此参数是否为构建命令所必需。

@Type - 表示属性定义为对象类型

如果您愿意,可以定义自己的注解。

  class FeatureCommand implements CommandInterface {
    /**
     * @RequestParam("mobile", pattern="\+\d{8,13}", required=true)
     * @Type("\My\Project\ValueObjects\MobileObject")
     * @Constraints\NotNull()
     */
    protected $mobile;
    
    /**
     * @RequestParam("country_code", required=false)
     * @Type("\My\Project\ValueObjects\CountryInfoObject")
     */
    protected $countryInfo;
    
    /**
     * @RequestParam("lang", required=false)
     */
    protected $lang;
    
    // ... getters/setters/serialize/unserialize
  }

如您所见,这个类是纯领域对象,没有任何复杂性。

因此,我们现在有了 处理器元信息命令,我们已可以启动我们的命令管道。我们可以定义一个控制器操作,该操作将负责处理所有API调用。

class TestController {
  public function handleAction($param1, $param2, $param3, Request $request) {
    $checkpoint = "$param1/$param2/$param3";
    
    $handlerMetaManager = new HandlerMetaManager();
    $handlerMeta = $handlerMetaManager->getMeta($checkpoint);
    
    $commandBuilder = new CommandBuilder();
    // in case command guesser returns service id, container must be passed to builder
    $commandBuilder->setContainer($container);
    
    $command = $commandBuilder->setRequest($request)
                  ->setMeta($handlerMeta)
                  ->build();
                  
    $handlerDispatcher = new CommandDispatcher($config);
    $result = $handlerDispatcher->dispatch($command);
    
    // now we have $result with response
    // we can serialize it in json/xml/...
    
    return $result;
  }
}

高级使用

到目前为止,我们构建了一个放置在同一台机器上的简单处理器。但如果我们想使其分布式和异步,该怎么办呢。您可以通过实现 CommandDispatcherInterface 来实现这一点。默认情况下,CommandDispatcher 通过 old_sound_rabbit_mq 包支持 rabbitmq。这要求您实现 Consumer,在它内部,您应将命令传递给处理器,并使用 rabbitmq xml/rpc 机制返回响应。在这种架构中,您可以实现简单的 map/reduce 处理器或异步地在处理器中运行几个重量级计算,然后返回结果。

许可证

Micro 在 MIT 许可证下发布。

捐赠