Giter Site home page Giter Site logo

api-docs's Introduction

PHP Swagger Api Docs

Latest Stable Version Total Downloads License

基于 Hyperf 框架的 swagger 文档生成组件,支持swoole/swow驱动

优点

  • 声明参数类型完成自动注入,参数映射到PHP类,根据类和注解自动生成Swagger文档
  • 代码DTO模式,可维护性好,扩展性好
  • 支持数组(类/简单类型),递归,嵌套
  • 支持注解数据校验
  • 支持api token
  • 支持PHP8原生注解,PHP8.1枚举
  • 支持openapi 3.0

使用须知

  • php版本 >= 8.1,参数映射到PHP类不支持联合类型
  • 控制器中方法尽可能返回类(包含简单类型),这样会更好的生成文档
  • 当返回类的结果满足不了时,可以使用 #[ApiResponse] 注解

例子

请参考example目录

安装

composer require tangwei/apidocs

默认使用swagger-ui,可使用knife4j-ui(功能更强大)

composer require tangwei/knife4j-ui

使用

1. 发布配置文件

php bin/hyperf.php vendor:publish tangwei/apidocs

1.1 配置信息

config/autoload/api_docs.php

<?php

declare(strict_types=1);

use Hyperf\ApiDocs\DTO\GlobalResponse;
use function Hyperf\Support\env;

return [
    /*
    |--------------------------------------------------------------------------
    | 启动 swagger 服务
    |--------------------------------------------------------------------------
    |
    | false 将不会启动 swagger 服务
    |
    */
    'enable' => env('APP_ENV') !== 'prod',

    /*
    |--------------------------------------------------------------------------
    | 生成swagger文件格式
    |--------------------------------------------------------------------------
    |
    | 支持json和yaml
    |
    */
    'format' => 'json',

    /*
    |--------------------------------------------------------------------------
    | 生成swagger文件路径
    |--------------------------------------------------------------------------
    */
    'output_dir' => BASE_PATH . '/runtime/container',

    /*
    |--------------------------------------------------------------------------
    | 生成代理类路径
    |--------------------------------------------------------------------------
    */
    'proxy_dir' => BASE_PATH . '/runtime/container/proxy',

    /*
    |--------------------------------------------------------------------------
    | 设置路由前缀
    |--------------------------------------------------------------------------
    */
    'prefix_url' => env('API_DOCS_PREFIX_URL', '/swagger'),

    /*
    |--------------------------------------------------------------------------
    | 设置swagger资源路径,cdn资源
    |--------------------------------------------------------------------------
    */
    'prefix_swagger_resources' => 'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.5.0',

    /*
    |--------------------------------------------------------------------------
    | 设置全局返回的代理类
    |--------------------------------------------------------------------------
    |
    | 全局返回 如:[code=>200,data=>null] 格式,设置会后会全局生成对应文档
    | 配合ApiVariable注解使用,示例参考GlobalResponse类
    | 返回数据格式可以利用AOP统一返回
    |
    */
    // 'global_return_responses_class' => GlobalResponse::class,

    /*
    |--------------------------------------------------------------------------
    | 替换验证属性
    |--------------------------------------------------------------------------
    |
    | 通过获取注解ApiModelProperty的值,来提供数据验证的提示信息
    |
    */
    'validation_custom_attributes' => true,

    /*
    |--------------------------------------------------------------------------
    | 设置DTO类默认值等级
    |--------------------------------------------------------------------------
    |
    | 设置:0 默认(不设置默认值)
    | 设置:1 简单类型会为设置默认值,复杂类型(带?)会设置null
    |        - 简单类型默认值: int:0  float:0  string:''  bool:false  array:[]  mixed:null
    | 设置:2 (慎用)包含等级1且复杂类型(联合类型除外)会设置null
    |
    */
    'dto_default_value_level' => 0,

    /*
    |--------------------------------------------------------------------------
    | 全局responses,映射到ApiResponse注解对象
    |--------------------------------------------------------------------------
    */
    'responses' => [
        ['response' => 401, 'description' => 'Unauthorized'],
        ['response' => 500, 'description' => 'System error'],
    ],
    /*
    |--------------------------------------------------------------------------
    | swagger 的基础配置
    |--------------------------------------------------------------------------
    |
    | 该属性会映射到OpenAPI对象
    |
    */
    'swagger' => [
        'info' => [
            'title' => 'API DOC',
            'version' => '0.1',
            'description' => 'swagger api desc',
        ],
        'servers' => [
            [
                'url' => 'http://127.0.0.1:9501',
                'description' => 'OpenApi host',
            ],
        ],
        'components' => [
            'securitySchemes' => [
                [
                    'securityScheme' => 'Authorization',
                    'type' => 'apiKey',
                    'in' => 'header',
                    'name' => 'Authorization',
                ],
            ],
        ],
        'security' => [
            ['Authorization' => []],
        ],
        'externalDocs' => [
            'description' => 'Find out more about Swagger',
            'url' => 'https://github.com/tw2066/api-docs',
        ],
    ],
];

2. 直接启动框架(需要有http服务)

php bin/hyperf.php start

[INFO] Swagger docs url at http://0.0.0.0:9501/swagger
[INFO] TaskWorker#1 started.
[INFO] Worker#0 started.
[INFO] HTTP Server listening at 0.0.0.0:9501

看到Swagger docs url显示,表示文档生成成功,访问/swagger即可以看到swagger页面 安装knife4j-ui,访问/swagger/doc即可以看到knife4j页面 访问/swagger/redoc,可以看到redoc页面

3. 使用

注解

命名空间:Hyperf\DTO\Annotation\Contracts

#[RequestBody] 注解

  • 获取Body参数
public function add(#[RequestBody] DemoBodyRequest $request){}

#[RequestQuery] 注解

  • 获取GET参数
public function add(#[RequestQuery] DemoQuery $request){}

#[RequestFormData] 注解

  • 获取表单请求
public function fromData(#[RequestFormData] DemoFormData $formData){}
  • 获取文件(和表单一起使用)
#[ApiFormData(name: 'photo', format: 'binary')]
  • 获取Body参数和GET参数
public function add(#[RequestBody] DemoBodyRequest $request, #[RequestQuery] DemoQuery $query){}

#[ApiSecurity] 注解

  • 优先级: 方法 > 类 > 全局
#[ApiSecurity('Authorization')]
public function getUserInfo(DemoToken $header){}

注意: 一个方法,不能同时注入RequestBody和RequestFormData

#[ApiResponse] 注解

  • php暂不能定义数组类型,返回的数据类型不能完全满足

    当不能满足时,可以通过ApiResponse注解来解决

    use Hyperf\ApiDocs\Annotation\ApiResponse; 
    use Hyperf\DTO\Type\PhpType;
    
    #[ApiResponse([PhpType::BOOL], 201)]
    #[ApiResponse([PhpType::INT], 202)]
    #[ApiResponse([PhpType::FLOAT], 203)]
    #[ApiResponse([PhpType::ARRAY], 204)]
    #[ApiResponse([PhpType::OBJECT], 205)]
    #[ApiResponse([PhpType::STRING], 206)]
    #[ApiResponse([Address::class], 207)]
    #[ApiResponse([PhpType::INT], 208)]
    #[ApiResponse([PhpType::BOOL])]
    public function test(){}
  • php暂不支持泛型,当返回存在相同结构时候,需要写很多类来返回

    例: 分页只有content结构是可变,可以通过#[ApiVariable]配合使用

    use Hyperf\ApiDocs\Annotation\ApiVariable;
    
    class Page
    {
        public int $total;
    
        #[ApiVariable]
        public array $content;
    
        public function __construct(array $content, int $total = 0)
        {
            $this->content = $content;
            $this->total = $total;
        }
    }

    控制器

        #[ApiOperation('分页')]
        #[GetMapping(path: 'activityPage')]
        #[ApiResponse(new Page([ActivityResponse::class]))]
        public function activityPage(#[RequestQuery] PageQuery $pageQuery): Page
        {
            $activityPage = Activity::paginate($pageQuery->getSize());
            $arr = [];
            foreach ($activityPage as $activity) {
                $arr[] = ActivityResponse::from($activity);
            }
            return new Page($arr, $activityPage->total());
        }

    通过#[ApiResponse(new Page([ActivityResponse::class]))]会生成相应的文档

示例

控制器

#[Controller(prefix: '/demo')]
#[Api(tags: 'demo管理', position: 1)]
class DemoController extends AbstractController
{
    #[ApiOperation(summary: '查询')]
    #[PostMapping(path: 'index')]
    public function index(#[RequestQuery] #[Valid] DemoQuery $request): Contact
    {
        $contact = new Contact();
        $contact->name = $request->name;
        var_dump($request);
        return $contact;
    }

    #[PutMapping(path: 'add')]
    #[ApiOperation(summary: '提交body数据和get参数')]
    public function add(#[RequestBody] DemoBodyRequest $request, #[RequestQuery] DemoQuery $query)
    {
        var_dump($query);
        return json_encode($request, JSON_UNESCAPED_UNICODE);
    }

    #[PostMapping(path: 'fromData')]
    #[ApiOperation(summary: '表单提交')]
    #[ApiFormData(name: 'photo', type: 'file')]
    public function fromData(#[RequestFormData] DemoFormData $formData): bool
    {
        $file = $this->request->file('photo');
        var_dump($file);
        var_dump($formData);
        return true;
    }

    #[GetMapping(path: 'find/{id}/and/{in}')]
    #[ApiOperation('查询单体记录')]
    #[ApiHeader(name: 'test')]
    public function find(int $id, float $in): array
    {
        return ['$id' => $id, '$in' => $in];
    }
}

验证器

基于框架的验证

安装hyperf框架验证器hyperf/validation, 并配置(已安装忽略)

  • 注解 Required Between Date Email Image Integer Nullable Numeric Url Validation ...
  • 校验生效

只需在控制器方法中加上 #[Valid] 注解

public function index(#[RequestQuery] #[Valid] DemoQuery $request){}
class DemoQuery
{
    #[ApiModelProperty('名称')]
    #[Required]
    #[Max(5)]
    #[In(['qq','aa'])]
    public string $name;

    #[ApiModelProperty('正则')]
    #[Str]
    #[Regex('/^.+@.+$/i')]
    #[StartsWith('aa,bb')]
    #[Max(10)]
    public string $email;

    #[ApiModelProperty('数量')]
    #[Required]
    #[Integer]
    #[Between(1,5)]
    public int $num;
}

自定义注解验证

注解的验证支持框架所有验证, 组件提供了常用的注解用于验证

  1. 使用自定义验证注解, 创建注解类继承Hyperf\DTO\Annotation\Validation\BaseValidation
  2. 重写$rule属性或getRule方法
//示例
#[Attribute(Attribute::TARGET_PROPERTY)]
class Image extends BaseValidation
{
    protected $rule = 'image';
}

验证器Validation

  1. 大家都习惯了框架的required|date|after:start_date写法
//可以通过Validation实现
#[Validation('required|date|after:start_date')]
  1. 需要支持数组里面是int数据情况 'intArr.*' => 'integer'的情况
//可以通过Validation中customKey来自定义key实现
#[Validation('integer', customKey: 'intArr.*')]
public array $intArr;

注意

数组类型的问题

PHP原生暂不支持int[]Class[]类型, 使用示例

    /**
     * class类型映射数组.
     * @var \App\DTO\Address[]
     */
    #[ApiModelProperty('地址')]
    public array $addressArr;

    /**
     * 简单类型映射数组.
     * @var int[]
     */
    #[ApiModelProperty('int类型的数组')]
    public array $intArr;

    /**
     * 通过注解映射数组.
     */
    #[ApiModelProperty('string类型的数组')]
    #[ArrayType('string')]
    public array $stringArr;

AutoController注解

控制器中使用AutoController注解,只收集了POST方法

DTO数据映射

api-docs引入到dto组件

注解

Dto注解

标记为dto类

use Hyperf\DTO\Annotation\Dto;

#[Dto]
class DemoQuery
{
}
  • 可以设置返回枚举#[Dto(Convert::SNAKE)], 批量转换下划线返回的key
  • Dto注解不会生成文档, 要生成对应文档使用JSONField注解

JSONField注解

用于设置属性的别名

use Hyperf\DTO\Annotation\Dto;
use Hyperf\DTO\Annotation\JSONField;

#[Dto]
class DemoQuery
{
    #[ApiModelProperty('这是一个别名')]
    #[JSONField('alias_name')]
    #[Required]
    public string $name;   
}
  • 设置JSONField后会生成代理类,生成alias_name属性
  • 接受和返回字段都以alias_name 为准

aspects.php中配置

return [
    \Hyperf\DTO\Aspect\ObjectNormalizerAspect::class
]

当框架导入 symfony/serializer (^5.0) 和 symfony/property-access (^5.0) 后,并在 dependencies.php 中配置一下映射关系

use Hyperf\Serializer\SerializerFactory;
use Hyperf\Serializer\Serializer;

return [
    Hyperf\Contract\NormalizerInterface::class => new SerializerFactory(Serializer::class),
];

Phar 打包器

# 1.启动生成代理类和注解缓存
php bin/hyperf.php start
# 2.打包
php bin/hyperf.php phar:build

Swagger界面

hMvJnQ

PHP Accessor

生成类访问器(Getter & Setter)

推荐使用free2one/hyperf-php-accessor

api-docs's People

Contributors

miwei230 avatar tw2066 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

api-docs's Issues

能否支持下划线驼峰互转的传参与返回

有些时候后端接口对外定义的传参/返回都是下划线命名风格,但是类成员变量通常是推荐驼峰命名方式的,那么必然就存在一个传参下换线,转换成驼峰的场景;以及在返回时,将驼峰命名的转换成下划线

securitySchemes中使用type = http时 无法使用schema属性

配置如下
image

报错如下

PHP Fatal error:  Uncaught Error: Call to undefined method phpDocumentor\Reflection\DocBlock\Tags\See::getType() in /data/www/hyperf-admin/vendor/tangwei/dto/src/JsonMapper.php:177
Stack trace:
#0 /data/www/hyperf-admin/vendor/tangwei/dto/src/JsonMapper.php(100): Hyperf\DTO\JsonMapper->parseAnnotationsNew(Object(ReflectionClass), Object(ReflectionProperty), '/**\n     * The ...')
#1 /data/www/hyperf-admin/vendor/netresearch/jsonmapper/src/JsonMapper.php(167): Hyperf\DTO\JsonMapper->inspectProperty(Object(ReflectionClass), 'scheme')
#2 /data/www/hyperf-admin/vendor/tangwei/dto/src/Mapper.php(17): JsonMapper->map(Array, Object(OpenApi\Attributes\SecurityScheme))
#3 /data/www/hyperf-admin/vendor/tangwei/apidocs/src/Swagger/SwaggerOpenApi.php(104): Hyperf\DTO\Mapper::map(Array, Object(OpenApi\Attributes\SecurityScheme))
#4 /data/www/hyperf-admin/vendor/tangwei/apidocs/src/Swagger/SwaggerOpenApi.php(43): Hyperf\ApiDocs\Swagger\SwaggerOpenApi->setComponentsSecuritySchemes()
#5 /data/www/hyperf-admin/vendor/tangwei/apidocs/src/Listener/AfterDtoStartListener.php(52): Hyperf\ApiDocs\Swagger\SwaggerOpenApi->init()
#6 /data/www/hyperf-admin/vendor/hyperf/event/src/EventDispatcher.php(48): Hyperf\ApiDocs\Listener\AfterDtoStartListener->process(Object(Hyperf\DTO\Event\AfterDtoStart))
#7 /data/www/hyperf-admin/vendor/tangwei/dto/src/BeforeServerListener.php(63): Hyperf\Event\EventDispatcher->dispatch(Object(Hyperf\DTO\Event\AfterDtoStart))
#8 /data/www/hyperf-admin/vendor/hyperf/event/src/EventDispatcher.php(48): Hyperf\DTO\BeforeServerListener->process(Object(Hyperf\Framework\Event\BeforeServerStart))
#9 /data/www/hyperf-admin/vendor/hyperf/server/src/Server.php(131): Hyperf\Event\EventDispatcher->dispatch(Object(Hyperf\Framework\Event\BeforeServerStart))
#10 /data/www/hyperf-admin/vendor/hyperf/server/src/Server.php(72): Hyperf\Server\Server->initServers(Object(Hyperf\Server\ServerConfig))
#11 /data/www/hyperf-admin/vendor/hyperf/server/src/ServerFactory.php(56): Hyperf\Server\Server->init(Object(Hyperf\Server\ServerConfig))
#12 /data/www/hyperf-admin/vendor/hyperf/server/src/Command/StartServer.php(52): Hyperf\Server\ServerFactory->configure(Array)
#13 /data/www/hyperf-admin/vendor/symfony/console/Command/Command.php(298): Hyperf\Server\Command\StartServer->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 /data/www/hyperf-admin/vendor/symfony/console/Application.php(1042): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 /data/www/hyperf-admin/vendor/symfony/console/Application.php(299): Symfony\Component\Console\Application->doRunCommand(Object(Hyperf\Server\Command\StartServer), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 /data/www/hyperf-admin/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#17 /data/www/hyperf-admin/bin/hyperf.php(23): Symfony\Component\Console\Application->run()
#18 /data/www/hyperf-admin/bin/hyperf.php(24): {closure}()
#19 /data/www/hyperf-admin/vendor/hyperf/watcher/watcher.php(22): require_once('/data/www/hyper...')
#20 {main}
  thrown in /data/www/hyperf-admin/vendor/tangwei/dto/src/JsonMapper.php on line 177

Fatal error: Uncaught Error: Call to undefined method phpDocumentor\Reflection\DocBlock\Tags\See::getType() in /data/www/hyperf-admin/vendor/tangwei/dto/src/JsonMapper.php:177
Stack trace:
#0 /data/www/hyperf-admin/vendor/tangwei/dto/src/JsonMapper.php(100): Hyperf\DTO\JsonMapper->parseAnnotationsNew(Object(ReflectionClass), Object(ReflectionProperty), '/**\n     * The ...')
#1 /data/www/hyperf-admin/vendor/netresearch/jsonmapper/src/JsonMapper.php(167): Hyperf\DTO\JsonMapper->inspectProperty(Object(ReflectionClass), 'scheme')
#2 /data/www/hyperf-admin/vendor/tangwei/dto/src/Mapper.php(17): JsonMapper->map(Array, Object(OpenApi\Attributes\SecurityScheme))
#3 /data/www/hyperf-admin/vendor/tangwei/apidocs/src/Swagger/SwaggerOpenApi.php(104): Hyperf\DTO\Mapper::map(Array, Object(OpenApi\Attributes\SecurityScheme))
#4 /data/www/hyperf-admin/vendor/tangwei/apidocs/src/Swagger/SwaggerOpenApi.php(43): Hyperf\ApiDocs\Swagger\SwaggerOpenApi->setComponentsSecuritySchemes()
#5 /data/www/hyperf-admin/vendor/tangwei/apidocs/src/Listener/AfterDtoStartListener.php(52): Hyperf\ApiDocs\Swagger\SwaggerOpenApi->init()
#6 /data/www/hyperf-admin/vendor/hyperf/event/src/EventDispatcher.php(48): Hyperf\ApiDocs\Listener\AfterDtoStartListener->process(Object(Hyperf\DTO\Event\AfterDtoStart))
#7 /data/www/hyperf-admin/vendor/tangwei/dto/src/BeforeServerListener.php(63): Hyperf\Event\EventDispatcher->dispatch(Object(Hyperf\DTO\Event\AfterDtoStart))
#8 /data/www/hyperf-admin/vendor/hyperf/event/src/EventDispatcher.php(48): Hyperf\DTO\BeforeServerListener->process(Object(Hyperf\Framework\Event\BeforeServerStart))
#9 /data/www/hyperf-admin/vendor/hyperf/server/src/Server.php(131): Hyperf\Event\EventDispatcher->dispatch(Object(Hyperf\Framework\Event\BeforeServerStart))
#10 /data/www/hyperf-admin/vendor/hyperf/server/src/Server.php(72): Hyperf\Server\Server->initServers(Object(Hyperf\Server\ServerConfig))
#11 /data/www/hyperf-admin/vendor/hyperf/server/src/ServerFactory.php(56): Hyperf\Server\Server->init(Object(Hyperf\Server\ServerConfig))
#12 /data/www/hyperf-admin/vendor/hyperf/server/src/Command/StartServer.php(52): Hyperf\Server\ServerFactory->configure(Array)
#13 /data/www/hyperf-admin/vendor/symfony/console/Command/Command.php(298): Hyperf\Server\Command\StartServer->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 /data/www/hyperf-admin/vendor/symfony/console/Application.php(1042): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 /data/www/hyperf-admin/vendor/symfony/console/Application.php(299): Symfony\Component\Console\Application->doRunCommand(Object(Hyperf\Server\Command\StartServer), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 /data/www/hyperf-admin/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#17 /data/www/hyperf-admin/bin/hyperf.php(23): Symfony\Component\Console\Application->run()
#18 /data/www/hyperf-admin/bin/hyperf.php(24): {closure}()
#19 /data/www/hyperf-admin/vendor/hyperf/watcher/watcher.php(22): require_once('/data/www/hyper...')
#20 {main}
  thrown in /data/www/hyperf-admin/vendor/tangwei/dto/src/JsonMapper.php on line 177
Stop server success.

我希望实现Bearer格式的token

DTO能否继承?

能否像java 的 dto 一样使用继承。
多个api, 都有相同的参数,把相同参数提取成超类; 然后注解验证,同时也能生成swagger 文档后也会包含父类的属性参数。

可以支持hyperf 的 phar打包吗

我看源码 注解dto是每次启动都会删除缓存重新生成 在phar包内是无法删除文件的 能否有一个配置 开启后则不清除缓存注解适合用于phar的模式

数组字段验证

可否增加对数组字段的规则验证功能,如下验证field1 和field2

{
  "info": [
    {
      "field1": 1,
      "field2": "string"
    },
    {
      "field1": 2,
      "field2": "string2"
    }
  ]
}

【BUG】前端传null值时DTO解析失败,程序报错

dto

<?php


namespace App\Dto\Admin\Carousel;


use App\Dto\BaseDto;
use Hyperf\ApiDocs\Annotation\ApiModelProperty;
use Hyperf\DTO\Annotation\Validation\Validation;

class CarouselUpdateDto extends BaseDto {

    #[ApiModelProperty('分类')]
    public $category_id;

    #[ApiModelProperty('图片')]
    #[Validation('array')]
    public $imgs;

    #[ApiModelProperty('链接类型')]
    public $type;

    #[ApiModelProperty('链接')]
    public $link;

    #[ApiModelProperty('启用状态')]
    public $enable;

    #[ApiModelProperty('排序值')]
    public $sort;
}

数据

{"carousel_id":1,"category_id":8,"imgs":[{"filename":"uploadlib-.png","type":"image","url":"http://127.0.0.1:9601/res-lib/upload/uploadlib-1653622489404.20221123143058.png","preview_url":"http://127.0.0.1:9601/res-lib/upload/uploadlib-1653622489404.20221123143058.png"}],"type":"none","link":null,"enable":1,"sort":1,"created_at":"2023-01-13 16:39:51","updated_at":"2023-01-13 17:55:31","deleted_at":null}

错误日志

Fatal error: Uncaught JsonMapper_Exception: JSON property "link" in class "App\Dto\Admin\Carousel\CarouselUpdateDto" must not be NULL in /data/www/hyperf-admin/vendor/netresearch/jsonmapper/src/JsonMapper.php:216
Stack trace:
#0 /data/www/hyperf-admin/vendor/tangwei/dto/src/Mapper.php(17): JsonMapper->map(Array, Object(App\Dto\Admin\Carousel\CarouselUpdateDto))
#1 /data/www/hyperf-admin/vendor/tangwei/dto/src/Middleware/CoreMiddleware.php(119): Hyperf\DTO\Mapper::map(Array, Object(App\Dto\Admin\Carousel\CarouselUpdateDto))
#2 /data/www/hyperf-admin/vendor/tangwei/dto/src/Middleware/CoreMiddleware.php(72): Hyperf\DTO\Middleware\CoreMiddleware->validateAndMap('App\\Controller\\...', 'dto', 'App\\Dto\\Admin\\C...', Object(App\Dto\Admin\Carousel\CarouselUpdateDto))
#3 /data/www/hyperf-admin/vendor/tangwei/dto/src/Middleware/CoreMiddleware.php(25): Hyperf\DTO\Middleware\CoreMiddleware->getInjections(Array, 'App\\Controller\\...', Array)
#4 /data/www/hyperf-admin/vendor/hyperf/http-server/src/CoreMiddleware.php(160): Hyperf\DTO\Middleware\CoreMiddleware->parseMethodParameters('App\\Controller\\...', 'update', Array)
#5 /data/www/hyperf-admin/vendor/hyperf/http-server/src/CoreMiddleware.php(113): Hyperf\HttpServer\CoreMiddleware->handleFound(Object(Hyperf\HttpServer\Router\Dispatched), Object(Hyperf\HttpMessage\Server\Request))
#6 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/AbstractRequestHandler.php(64): Hyperf\HttpServer\CoreMiddleware->process(Object(Hyperf\HttpMessage\Server\Request), Object(Hyperf\Dispatcher\HttpRequestHandler))
#7 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpRequestHandler.php(26): Hyperf\Dispatcher\AbstractRequestHandler->handleRequest(Object(Hyperf\HttpMessage\Server\Request))
#8 /data/www/hyperf-admin/runtime/container/proxy/App_Core_RBAC_Middleware_RBACMiddleware.proxy.php(49): Hyperf\Dispatcher\HttpRequestHandler->handle(Object(Hyperf\HttpMessage\Server\Request))
#9 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/AbstractRequestHandler.php(64): App\Core\RBAC\Middleware\RBACMiddleware->process(Object(Hyperf\HttpMessage\Server\Request), Object(Hyperf\Dispatcher\HttpRequestHandler))
#10 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpRequestHandler.php(26): Hyperf\Dispatcher\AbstractRequestHandler->handleRequest(Object(Hyperf\HttpMessage\Server\Request))
#11 /data/www/hyperf-admin/app/Core/Auth/Aspect/AuthMiddlewareAspect.php(45): Hyperf\Dispatcher\HttpRequestHandler->handle(Object(Hyperf\HttpMessage\Server\Request))
#12 /data/www/hyperf-admin/vendor/hyperf/di/src/Aop/Pipeline.php(30): App\Core\Auth\Aspect\AuthMiddlewareAspect->process(Object(Hyperf\Di\Aop\ProceedingJoinPoint))
#13 /data/www/hyperf-admin/vendor/hyperf/utils/src/Pipeline.php(95): Hyperf\Di\Aop\Pipeline->Hyperf\Di\Aop\{closure}(Object(Hyperf\Di\Aop\ProceedingJoinPoint))
#14 /data/www/hyperf-admin/vendor/hyperf/di/src/Aop/ProxyTrait.php(86): Hyperf\Utils\Pipeline->then(Object(Closure))
#15 /data/www/hyperf-admin/vendor/hyperf/di/src/Aop/ProxyTrait.php(29): Qbhy\HyperfAuth\AuthMiddleware::handleAround(Object(Hyperf\Di\Aop\ProceedingJoinPoint))
#16 /data/www/hyperf-admin/runtime/container/proxy/Qbhy_HyperfAuth_AuthMiddleware.proxy.php(49): Qbhy\HyperfAuth\AuthMiddleware::__proxyCall('Qbhy\\HyperfAuth...', 'process', Array, Object(Closure))
#17 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/AbstractRequestHandler.php(64): Qbhy\HyperfAuth\AuthMiddleware->process(Object(Hyperf\HttpMessage\Server\Request), Object(Hyperf\Dispatcher\HttpRequestHandler))
#18 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpRequestHandler.php(26): Hyperf\Dispatcher\AbstractRequestHandler->handleRequest(Object(Hyperf\HttpMessage\Server\Request))
#19 /data/www/hyperf-admin/vendor/hyperf/validation/src/Middleware/ValidationMiddleware.php(83): Hyperf\Dispatcher\HttpRequestHandler->handle(Object(Hyperf\HttpMessage\Server\Request))
#20 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/AbstractRequestHandler.php(64): Hyperf\Validation\Middleware\ValidationMiddleware->process(Object(Hyperf\HttpMessage\Server\Request), Object(Hyperf\Dispatcher\HttpRequestHandler))
#21 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpRequestHandler.php(26): Hyperf\Dispatcher\AbstractRequestHandler->handleRequest(Object(Hyperf\HttpMessage\Server\Request))
#22 /data/www/hyperf-admin/runtime/container/proxy/App_Core_RespFmt_Middleware_RespFmtMiddleware.proxy.php(35): Hyperf\Dispatcher\HttpRequestHandler->handle(Object(Hyperf\HttpMessage\Server\Request))
#23 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/AbstractRequestHandler.php(64): App\Core\RespFmt\Middleware\RespFmtMiddleware->process(Object(Hyperf\HttpMessage\Server\Request), Object(Hyperf\Dispatcher\HttpRequestHandler))
#24 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpRequestHandler.php(26): Hyperf\Dispatcher\AbstractRequestHandler->handleRequest(Object(Hyperf\HttpMessage\Server\Request))
#25 /data/www/hyperf-admin/runtime/container/proxy/App_Core_Utils_Middleware_LanguageMiddleware.proxy.php(30): Hyperf\Dispatcher\HttpRequestHandler->handle(Object(Hyperf\HttpMessage\Server\Request))
#26 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/AbstractRequestHandler.php(64): App\Core\Utils\Middleware\LanguageMiddleware->process(Object(Hyperf\HttpMessage\Server\Request), Object(Hyperf\Dispatcher\HttpRequestHandler))
#27 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpRequestHandler.php(26): Hyperf\Dispatcher\AbstractRequestHandler->handleRequest(Object(Hyperf\HttpMessage\Server\Request))
#28 /data/www/hyperf-admin/app/Core/Utils/Middleware/CorsMiddleware.php(32): Hyperf\Dispatcher\HttpRequestHandler->handle(Object(Hyperf\HttpMessage\Server\Request))
#29 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/AbstractRequestHandler.php(64): App\Core\Utils\Middleware\CorsMiddleware->process(Object(Hyperf\HttpMessage\Server\Request), Object(Hyperf\Dispatcher\HttpRequestHandler))
#30 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpRequestHandler.php(26): Hyperf\Dispatcher\AbstractRequestHandler->handleRequest(Object(Hyperf\HttpMessage\Server\Request))
#31 /data/www/hyperf-admin/vendor/hyperf/dispatcher/src/HttpDispatcher.php(40): Hyperf\Dispatcher\HttpRequestHandler->handle(Object(Hyperf\HttpMessage\Server\Request))
#32 /data/www/hyperf-admin/vendor/hyperf/http-server/src/Server.php(117): Hyperf\Dispatcher\HttpDispatcher->dispatch(Object(Hyperf\HttpMessage\Server\Request), Array, Object(Hyperf\DTO\Middleware\CoreMiddleware))
#33 {main}
  thrown in /data/www/hyperf-admin/vendor/netresearch/jsonmapper/src/JsonMapper.php on line 216
[2023-01-13 18:06:29 *1265.0]   WARNING Channel::~Channel() (ERRNO 10003): channel is destroyed, 2 consumers will be discarded
PHP Fatal error:  Uncaught Swoole\Error: API must be called in the coroutine in /data/www/hyperf-admin

同时使用 ApiHeader , RequestQuery 时,RequestQuery中对应数量字段在文档参数中会消失

环境: swow-skeketon: 3.0
swow: 1.0

#[ApiOperation(summary: '查询')]
    #[GetMapping(path: 'api')]
    #[ApiHeader(name: 'test', required: true, type: 'string')]
    #[ApiFormData(name: 'photo', required: true, type: 'file')]
    public function api(#[RequestQuery] #[Valid] DemoRequest $request): DemoResponse
    {
        $response = new DemoResponse();
        $response->setName('foo');
        $response->setUser((new User())->setName('bar'));
        $addressArr = [];
        for ($i = 2; $i--;) {
            $addressArr[] = (new Address())->setName('address');
        }
        $response->setAddressArr($addressArr);
        return $response;
    }

api_docs修改enable启动后

修改了此配置后
return [
// enable false 将不会启动 swagger 服务
'enable' => false,
'format' => 'json',
...
];
修改了以上配置 然后启动就报错了

报错:
Fatal error: Uncaught Error: Typed static property Hyperf\ApiDocs\Listener\BootAppRouteListener::$massage must not be accessed before initialization in /cygdrive/f/xycphp/php8/lsk-

能否将JSONField的这个info日志注掉或者变更为debug级别的?

能否将JSONField的这个info日志注掉或者变更为debug级别的?
当我定义个一个从头获取参数的类,Header中的名称和我实际要的属性名不一致,所以使用JSONField来设定别名。
#[JSONField('x-webhook-sender')] public string $sender;
但是,当我在请求头中带回来的比如UserAgent等参数,确实不需要,但是会报出一堆info日志。。。

[2023-08-01 13:11:40] [INFO] Property {property} does not exist in {class}
[2023-08-01 13:11:40] [INFO] Property {property} does not exist in {class}
[2023-08-01 13:11:40] [INFO] Property {property} does not exist in {class}
[2023-08-01 13:11:40] [INFO] Property {property} does not exist in {class}
[2023-08-01 13:11:40] [INFO] Property {property} does not exist in {class}
[2023-08-01 13:11:40] [INFO] Property {property} does not exist in {class}
[2023-08-01 13:11:40] [INFO] Property {property} does not exist in {class}
.....

2.0版本发布配置文件报错

php bin/hyperf.php vendor:publish tangwei/apidocs
2.0版本报错下面的是什么轻快
There are no commands defined in the "vendor" namespace.

能否支持多模块拆分文档

项目文档都放在单个文档中使得文档过于庞大

能否在Api注解上增加模块名以生成不同的swagger配置文件(如果没有更优的方案的话)

实现下图的效果
image

需要在swagger-ui中配置urls
image

感谢🙏

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.