ingenerator/microframework

超轻量级的用于 Cloud Run / Lambda 等的服务器框架

v1.0.1 2024-07-22 13:35 UTC

This package is auto-updated.

Last update: 2024-09-22 14:01:30 UTC


README

microframework 提供了一个极其轻量级、具有偏见的框架,用于简单的 HTTP 请求处理器(例如 Cloud Run / Lambda / Cloud Functions 风格的端点)。

它提供

  • 基本引导,包括设置时区和区域设置。
  • 错误/异常处理,包括记录和渲染通用错误响应。
  • 检测执行过程中/早期发送头部的意外输出。
  • 请求记录(包括高精度延迟)。
  • 将 PSR ResponseInterface 对象渲染回客户端(包括状态码、头和主体)。

它设计并测试过,可以在 apache v2.4 下使用 mod_php、mod_prefork 和 mod_rewrite 运行。其他运行时配置可能也可以工作,但不是官方支持。

它不提供,也不会提供路由、运行时配置管理、依赖注入、HTML 模板、中间件、事件调度或更多功能齐全框架的类似功能。

入门

composer require ingenerator/microframework

处理请求

提供一个 PHP 文件作为您的入口点。这可以是 {Apache DocumentRoot}/index.php 或其他任何位置(例如,您可以将它放在一个更大的/更复杂的项目子目录中,其中包含使用不同框架的代码)。

<?php
// index.php
require_once(__DIR__.'/../vendor/autoload.php');

// *NO CODE HERE*
// You should ideally not have any code that runs outside the functions passed into execute() below. This makes sure
// that all code is wrapped in the output detection, error handling, and logging provided by microframework. 

(new Ingenerator\MicroFramework\MicroFramework)->execute(
    /*
     * --- REQUIRED CODE ---
     */
    // You must provide a callable that returns a `LoggerProvider`
    //
    // The DefaultStackdriverLoggerProvider returns a logger that will log requests and custom entries to STDOUT in a
    // format suitable for ingestion into Google Stackdriver (including tagging exceptions for Google Error Reporting).
    //
    // You can alternatively provide a custom LoggerProvider that returns any PSR\Log\LoggerInterface along with a thin
    // RequestLogger class that will be called automatically to log the request itself.
    logger_provider_factory: fn () => new \Ingenerator\MicroFramework\DefaultStackdriverLoggerProvider(
        service_name: 'my-function',
        // For the DefaultStackdriverLoggerProvider, you need to give a path to a file that will return the current 
        // version of your service - e.g. `<?php return 'ab9237723'` which you would usually write during docker build.
        // This will be included in the metadata for all log entries.
        version_file_path: __DIR__.'/../version.php' 
    ),
    // Your actual implementation sits within a RequestHandler class.
    // - For the simplest functions, you can define this inline as an anonymous class - as in the example below.
    // - For more complex functions, you will probably want to define a normal PHP class in a separate file (e.g.
    //   autoloadable by composer) and potentially a factory function to create it with any services / config it
    //   requires.
    //
    // The only service / dependency that microframework provides to your code is the Logger - this is passed to
    // your factory function for you to use as required.
    handler_factory: fn(\Psr\Log\LoggerInterface $logger) => new class implements Ingenerator\MicroFramework\RequestHandler {
        
        // If you wish to write log entries from your own code, capture the logger as a constructor argument.
        public function __construct(private readonly $logger) {}
        
        public function handle(\Psr\Http\Message\ServerRequestInterface $request): \Psr\Http\Message\ResponseInterface {
            // Do whatever you want with the request here.
            // Microframework does not provide any routing - if you need to handle different requests with different
            // code, it is up to you to dispatch them appropriately.           
            // When you are finished, return a PSR ResponseInterface.
            $this->logger->info('Got a request');
            return new Response(200, headers: ['Content-Type'=> 'application/json'], body: '{"ok": true}');
        }
    },
    /*
     * 
     * --- OPTIONAL CODE ---
     * 
     */
     // For ultra-precise latency measurement, you could capture start_hr_time as the very first line of PHP in the file
     // e.g. before requiring the composer autoloader. If not provided, it will default to when ->execute() is called.
     start_hr_time: hrtime(as_number: true),
     // Set a custom locale, if required (defaults to en_UK.utf-8)
     locale: 'en_US.utf-8',
     // Set a custom timezone (defaults to Europe/London)
     default_timezone: 'Europe/Paris',
     // Customise how the incoming request is parsed - e.g. if your runtime environment does not provide the request
     // in a structure that the default GuzzleHttp\Psr7\ServerRequest::fromGlobals() can understand. Provide a factory
     // function that returns a ServerRequestInterface
     request_factory: fn() => new \GuzzleHttp\Psr7\ServerRequest(/*request values from somewhere*/)
);

// *NO CODE HERE*
// Again, you should not have code that runs outside the `execute` call above.
// If absolutely required and you e.g. need to run cleanup after the response has been sent / streamed to the client,
// you could do that here - but be aware that it will not be covered by error handling or logging & will not be able to
// modify response headers or output.

版本政策

该软件包遵循 semver。为了便于维护,任何给定的软件包版本将只支持单个 PHP 版本以及(数量很少的)composer 依赖项的每个小版本。

预计您可能需要更新您的函数代码到最新的支持的 PHP / composer 依赖项版本,才能升级到该软件包的较新小版本。

我们可能会偶尔针对旧版本的软件包发布错误修复版本,以解决安全问题或严重错误,但大部分更改将只应用于当前的小版本。

运行测试

该软件包有一些单元测试和集成测试,可以像往常一样使用 phpunit 运行。

我们还提供了一套黑盒测试,通过在支持的运行时环境中对软件包的发行版本进行 HTTP 请求,以验证软件包的整体行为。该测试环境相当具体,并使用 docker compose 和一些自定义脚本来确保测试的系统具有(仅)生产代码的确切副本。有关详细信息,请参阅 test/blackbox/README.md

贡献

欢迎贡献,但在开始任何工作之前请与我们联系:这是一个具有偏见的软件包,我们可能有特定的要求/意见与您不同。

贡献者

此软件包由 inGenerator Ltd 赞助。

许可证

许可协议为 BSD-3-Clause-Licence