承接 diomac/php-api-rest 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

diomac/php-api-rest

Composer 安装命令:

composer require diomac/php-api-rest

包简介

A PHP API REST Micro-Framework using annotations

README 文档

README

PHP API REST framework using annotations, and Swagger 2.0 support.

Prerequisites

  • PHP >=7.2

Optional (Recommended)

Caching routes

Swagger yaml format

Installing

Use composer to manage your dependencies and download PHP-API-REST:

composer require diomac/php-api-rest

Get Started

API Rest Configuration

  • 1 - Place an .htaccess file in the root folder of your Rest API (base url), to redirect all routes to the API initialization file.

Example API folders:

.htaccess file:

RewriteEngine On
RewriteCond %{REQUEST_URI} !init\.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* init.php [L,QSA]
  • 2 - Use the initialization file to import the dependencies of your project and...
    • Instantiate a Diomac\API\AppConfiguration object;
    • Set the base url of your API;
    • Add the Resources Class Names of your API (See Implementing API Rest Resources);
    • Instantiate a Diomac\API\App object using the configuration object;
    • Finally call exec method.

init.php file:

use Diomac\API\App;
use Diomac\API\AppConfiguration;

/**
 * Initializing API configuration
 */
$config = new AppConfiguration();
$config->setBaseUrl('/php-api-rest/example/v1');

/**
 * Adding resources classes
 */
$config->addResource(\example\v1\ExampleResource::class);
$config->addResource(\example\v1\ExampleSwaggerJson::class);

/**
 * Execute API
 */
try{
    $app = new App($config);
    $app->exec();
}catch (Exception $ex){
    ...
}

Implementing API Rest Resources

  • 3 - In the resource class, enter the inheritance of the Resource class:
namespace example;

use Diomac\API\Resource;
use Diomac\API\Response;
use Diomac\API\UnauthorizedException;

class ExampleResource extends Resource 
{
    ...
}
  • 4 - For each method of the resource class, enter PHP annotation to identify routes (@route), HTTP methods (@method) and if you need a Class implementing Guard Interface to protect the route (@guard - See how implement guards in topic Implementing a Guard Class ):
/**
* @method get
* @route /auth/usr-data/id/{id}
* @guard(
*     className="example\core\secure\ExampleGuard",
*     @parameters(operationId="GETUSERDATA")
* )
*/
function getUsrData()
{
  // ... your code
  $this->response->setCode(Response::OK); // set HTTP response code
  $this->response->setBodyJSON($jsonSerializable); // set responde data
  return $this->response; // return response object
}

Resource Class Inheritance

  • 5 - Whenever a route is executed, the class holding the route will be instantiated and inherit the following attributes:

A Diomac\API\Request object with the methods:

$this->request->getParams() // returns the parameters of the URL and $_GET
$this->request->getData()   // returns an object sent by the front end
$this->request->getRoute()  // returns the executed route
$this->request->getMethod() // returns the executed HTTP method

A Diomac\API\Response object with the methods:

$this->response->setHeader('name', 'value'); // set HTTP header response
$this->response->setCode(Response::BAD_REQUEST); // set HTTP response code
$this->response->setBody('string'); // set response body
$this->response->setBodyJSON(\JsonSerializable object); // set response body to convert in JSON
$this->response->setContentType(''); // set content type response (for setBodyJSON not needed)

And it inherits methods from the Diomac\API\Resource class:

$this->getRoute(); // returns the configured route
$this->getParams(); // returns the parameters of the URL and $_GET
$this->getParam('name'); // returns a parameter by name

Output

  • 6 - For the output simply return the response object:
return $this->response;

Complete Resource example

API get method:

/**
 * @method get
 * @route /example/v1/pet/{petId}
 *
 * @return Response
 * @throws Exception
 */
function getPet(): Response
{
    try {
        $petId = $this->getParam('petId');
        $pet = new Pet($petId);

        /**
         * API Rest best practices - selecting returned fields and aliases
         */
        $fields = $this->getParam('fields');

        if($fields){
            Response::setFields(explode(',', $fields), Pet::class);
        }

        $this->response->setCode(Response::OK);
        $this->response->setBodyJSON($pet);
    } catch (Exception $ex) {
        throw new Exception('Internal Server Error', Response::INTERNAL_SERVER_ERROR);
    }

    return $this->response;
}

Guards

/**
* @method get
* @route /auth/usr-data/id/{id}
* @guard(
*     className="example\core\secure\ExampleGuard"
* )
* @guard(
*     className="example\core\secure\ExampleGuardWithParams",
*     @parameters(operationId="GETUSERDATA", operationName="GETUSERDATA")
* )
*/
function getUsrData()
{
  // ... your code
  $this->response->setCode(Response::OK); // set HTTP response code
  $this->response->setBodyJSON($ this->request->getData()); // set responde data
  return $this->response; // return response object
}

Implementing a Guard Class

namespace api\secure;

use Diomac\API\Exception;
use Diomac\API\ForbiddenException;
use Diomac\API\UnauthorizedException;
use Diomac\API\Response;
use Diomac\API\Guard;

/**
 * Class AuthGuard
 * @package api\secure
 */
class AuthGuard implements Guard
{
    /**
     * @param object|null $guardParams
     * @return bool
     * @throws Exception
     * @throws ForbiddenException
     * @throws UnauthorizedException
     */
    public function guard(object $guardParams = null) : bool
    {
        $func = $guardParams->func;
        $access = checkAccess($func);
        switch ($access) {
            case Response::OK:
                return true;
                break;
            case Response::UNAUTHORIZED:                
                throw new UnauthorizedException();
                break;
            case Response::FORBIDDEN:                
                throw new ForbiddenException();
                break;
            default:               
                throw new Exception('Server Error!', Response::INTERNAL_SERVER_ERROR);
        }
    }
}

Cache

Cache settings save the mapped routes into a list, and when used (set to true), skip the route mapping step for better performance.

Cache with APC - Alternative PHP Cache

**
 * Setting use cache for caching of annotations mapping
 */
$config->setUseCache(true);

/**
 * Execute API
 */
try{
    $app = new App($config);
    $app->exec();
}catch (Exception $ex){
    ...
}

Cache with Redis

/**
 * Set Redis for cache
 */
$redis = new RedisConfig();
$redis->setScheme('tcp');
$redis->setHost('redis');
$redis->setPort(6379);

**
 * Setting use cache for caching of annotations mapping
 */
$config->setUseCache(true, $redis);

Swagger 2.0 support

swagger.json or swagger.yaml

Create a route in a resource like the example below:

PHP Class:

use Diomac\API\Resource;
use Diomac\API\Response;
use example\v1\doc\ExampleSwaggerDoc;

class ExampleSwaggerJson extends Resource
{
    /**
     * @method get
     * @route /swagger.json
     */
    function swaggerJson()
    {
        $this->response->setCode(Response::OK);
        $swagger = new ExampleSwaggerDoc();

        /**
         * JSON
         */
        $this->response->setBodySwaggerJSON($swagger);
        /**
         * Or YAML
         */
        //$this->response->setBodySwaggerYAML($swagger);
        return $this->response;
    }
}

Route result:

{
  "swagger": "2.0",
  "info": {
    "version": "1.0.0",
    "title": "Swagger Sample App",
    "description": "This is a sample server Petstore server.",
    "termsOfService": "http:\/\/swagger.io\/terms\/",
    "contact": {
      "name": "API Support",
      "email": "support@swagger.io",
      "url": "http:\/\/swagger.io"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "http:\/\/www.apache.org\/licenses\/LICENSE-2.0.html"
    }
  },
  "host": "localhost",
  "basePath": "\/php-api-rest\/vendor\/example\/v1",
  "schemes": [
    "http",
    "https"
  ],
  "consumes": [
    "text\/plain; charset=utf-8"
  ],
  "produces": [
    "application\/json",
    "text\/html"
  ],
  "tags": [
    {
      "name": "ExampleAPIDocSwagger",
      "description": "ExampleAPIDocSwagger",
      "externalDocs": {
        "description": "Externaldocsexample",
        "url": "http:\/\/example_php_api_rest.com"
      }
    }
  ],
  "paths": {
    ...

Swagger Info

To document the information (Swagger Info) of your API, you can use Swagger and SwaggerInfo classes. Just implement an "ExampleSwaggerDoc" class that inherits from Swagger as in the example below:

PHP Class:

use Diomac\API\swagger\Swagger;
use Diomac\API\swagger\SwaggerInfo;

class ExampleSwaggerDoc extends Swagger
{
    public function info(): SwaggerInfo
    {
        $this->setInfo(new SwaggerInfo());
        $this->info->setVersion('1.0.0');
        $this->info->setTitle('Swagger Sample App');
        $this->info->setDescription('This is a sample server Petstore server.');
        $this->info->setTermsOfService('http://swagger.io/terms/');

        $this->info->getContact()->setName('API Support');
        $this->info->getContact()->setEmail('support@swagger.io');
        $this->info->getContact()->setUrl('http://swagger.io');

        $this->info->getLicense()->setName('Apache 2.0');
        $this->info->getLicense()->setUrl('http://www.apache.org/licenses/LICENSE-2.0.html');

        return $this->getInfo();
    }
    ...
}

@tag

Use @tag in PHPDoc Class to document Resources's routes with Swagger Tag Object.

PHPDoc:

/**
 * Class ExampleResource
 * @package example\v1
 * @tag(
 *     name="Example API Doc Swagger",
 *     description="Example API Doc Swagger",
 *     @externalDocs(description="External docs example", url="http://example_php_api_rest.com")
 * )
 */
class ExampleResource extends Resource
{
    ...
}

Swagger json result:

...
"tags": [
    {
      "name": "ExampleAPIDocSwagger",
      "description": "ExampleAPIDocSwagger",
      "externalDocs": {
        "description": "Externaldocsexample",
        "url": "http:\/\/example_php_api_rest.com"
      }
    }
  ],
...

@tag (string)

Use @tag in PHPDoc function to document your route with a additional tag.

PHPDoc:

    /**
     * @method get
     * @route /example/api/value1/{value1}/value2/{value2}
     * @tag More one tag
     */
    function getUsrData(): Response
    {
        ...
    }

Swagger json result:

...
"tags": [
          "More one tag",
          "ExampleAPIDocSwagger"
        ],
...

@contentType

Use @contentType in PHPDoc function to document your route with Swagger produces [string].

PHPDoc:

    /**
     * @method get
     * @route /example/api/value1/{value1}/value2/{value2}
     * @contentType application/json
     * @contentType text/html
     */
    function getUsrData(): Response
    {
        ...
    }

Swagger json result:

...
"produces": [
    "application\/json",
    "text\/html"
  ],
...

@summary

Use @summary in PHPDoc function to document your route with Swagger summary string.

PHPDoc:

    /**
     * @method get
     * @route /example/api/value1/{value1}/value2/{value2}
     * @summary Example api rest php
     */
    function getUsrData(): Response
    {
        ...
    }

Swagger json result:

...
"get": {
        "summary": "Example api rest php",
...

@description

Use @description in PHPDoc function to document your route with Swagger description string.

PHPDoc:

    /**
     * @method get
     * @route /example/api/value1/{value1}/value2/{value2}
     * @description A example api rest php
     */
    function getUsrData(): Response
    {
        ...
    }

Swagger json result:

...
"get": {
        "description": "A example api rest php",
...

@operationId

Use @operationId in PHPDoc function to document your route with Swagger operationId string.

PHPDoc:

    /**
     * @method get
     * @route /example/api/value1/{value1}/value2/{value2}
     * @operationId GETUSERDATA
     */
    function getUsrData(): Response
    {
        ...
    }

Swagger json result:

...
"get": {
        "operationId": "GETUSERDATA",
...

@consumeType

Use @consumeType in PHPDoc function to document your route with Swagger consumes [string].

PHPDoc:

    /**
     * @method get
     * @route /example/api/value1/{value1}/value2/{value2}
     * @consumeType text/plain; charset=utf-8
     */
    function getUsrData(): Response
    {
        ...
    }

Swagger json result:

...
"post": {
       "consumes": [
                 "text\/plain; charset=utf-8"
               ],
...

@response(...)

Use @response(...) in PHPDoc function to document your route with Swagger response object.

PHPDoc:

    /**
     * @method get
     * @route /example/api/value1/{value1}/value2/{value2}
     * @response(
     *     code=200,
     *     description="Success",
     *     @schema(
     *     type="object",
     *     @items($ref="#/definitions/sucess")
     * )
     * )
     */ 
    function getUsrData(): Response
    {
        ...
    }

Swagger json result:

...
"responses": {
          "200": {
            "description": "Success",
            "schema": {
              "type": "object",
              "items": {
                "$ref": "#\/definitions\/sucess"
              }
            }
          },
...

License

This project is licensed under the MIT License - see the LICENSE file for details

diomac/php-api-rest 适用场景与选型建议

diomac/php-api-rest 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 67 次下载、GitHub Stars 达 9, 最近一次更新时间为 2018 年 07 月 30 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「rest」 「api」 「micro-framework」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 diomac/php-api-rest 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 diomac/php-api-rest 我们能提供哪些服务?
定制开发 / 二次开发

基于 diomac/php-api-rest 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 67
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 10
  • 点击次数: 0
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 9
  • Watchers: 5
  • Forks: 3
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-07-30