跳到内容

NelmioApiDocBundle

编辑此页

NelmioApiDocBundle 扩展包允许您生成 OpenAPI (Swagger) 格式的文档,并提供一个沙箱以交互式地体验 API。

支持哪些功能?

此扩展包支持 Symfony 路由要求,Symfony 请求映射 (Symfony 属性), PHP 注解, Swagger-Php 注解, FOSRestBundle 注解以及使用 Api-Platform 的应用程序。

对于模型,它支持 Symfony 序列化器 , JMS 序列化器willdurand/Hateoas 库。它还支持 Symfony 表单 类型。

从 4.7 版本和 PHP 8.1 开始支持属性。

安装

打开命令控制台,进入您的项目目录并执行以下命令来下载此扩展包的最新版本

1
$ composer require nelmio/api-doc-bundle

默认情况下,仅记录 /api 下的路由。更新 config/packages/nelmio_api_doc.yaml 中的 nelmio_api_doc.areas.path_patterns 处的正则表达式以更改此策略。

注意

如果您未使用 Flex,请将扩展包添加到您的内核

1
2
3
4
5
6
7
8
9
10
11
12
13
class AppKernel extends Kernel
{
    public function registerBundles(): iterable
    {
        $bundles = [
            // ...

            new Nelmio\ApiDocBundle\NelmioApiDocBundle(),
        ];

        // ...
    }
}

要使用 UI 浏览您的文档,请注册以下路由之一

1
2
3
4
5
# config/routes.yaml
app.swagger_ui:
    path: /api/doc
    methods: GET
    defaults: { _controller: nelmio_api_doc.controller.swagger_ui }
1
2
3
4
5
# config/routes.yaml
app.redocly:
    path: /api/doc
    methods: GET
    defaults: { _controller: nelmio_api_doc.controller.redocly }
1
2
3
4
5
# config/routes.yaml
app.stoplight:
    path: /api/doc
    methods: GET
    defaults: { _controller: nelmio_api_doc.controller.stoplight }

如果您还想在 JSON 中公开它,请注册此路由

1
2
3
4
5
# config/routes.yaml
app.swagger:
    path: /api/doc.json
    methods: GET
    defaults: { _controller: nelmio_api_doc.controller.swagger }

由于您刚刚安装了该扩展包,您可能会看到文档中不需要的路由,例如 /_profiler/。要解决此问题,您可以配置扩展包来过滤要记录的路由

1
2
3
4
5
6
7
# config/packages/nelmio_api_doc.yaml
nelmio_api_doc:
    areas:
        path_patterns: # an array of regexps (document only routes under /api, except /api/doc)
            - ^/api(?!/doc$)
        host_patterns: # document only routes with a host of the form api.*
            - ^api\.

提示

使用 swagger ui 需要 TwigAssets 包。

此扩展包如何工作?

它借助 Describers 从您的 Symfony 应用程序生成 OpenAPI 文档。一个从 SwaggerPHP 属性/注解中提取数据,一个从您的路由中提取数据,等等。

如果您配置了上面的 app.swagger_ui 路由,您可以在 http://example.org/api/doc 浏览您的文档。

使用扩展包

您可以在扩展包配置 documentation.info 部分配置全局信息(查看 OpenAPI 3.0 规范(以前称为 Swagger) 以了解可用字段)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
nelmio_api_doc:
    documentation:
        servers:
          - url: http://api.example.com/unsafe
            description: API over HTTP
          - url: https://api.example.com/secured
            description: API over HTTPS
        info:
            title: My App
            description: This is an awesome app!
            version: 1.0.0
            x-build: #CommitHash
        components:
            securitySchemes:
                Bearer:
                    type: http
                    scheme: bearer
                    bearerFormat: JWT
        security:
            - Bearer: []

注意

如果您正在使用 Flex,则此配置默认位于 config/packages/nelmio_api_doc.yaml 下。不要忘记将其调整为您的应用程序!

提示

此配置字段通常可以用于将您的文档存储为 yaml。您可以在 SwaggerPHP 示例.yaml 文件中找到。

要记录您的路由,您可以使用 SwaggerPHP 属性/注解和控制器中的 #[Model] 属性/注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
namespace AppBundle\Controller;

use AppBundle\Entity\Reward;
use AppBundle\Entity\User;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Annotations as OA;
use Symfony\Component\Routing\Annotation\Route;

class UserController
{
    /**
     * List the rewards of the specified user.
     *
     * This call takes into account all confirmed awards, but not pending or refused awards.
     *
     * @Route("/api/{user}/rewards", methods={"GET"})
     * @OA\Response(
     *     response=200,
     *     description="Returns the rewards of an user",
     *     @OA\JsonContent(
     *        type="array",
     *        @OA\Items(ref=@Model(type=Reward::class, groups={"full"}))
     *     )
     * )
     * @OA\Parameter(
     *     name="order",
     *     in="query",
     *     description="The field used to order rewards",
     *     @OA\Schema(type="string")
     * )
     * @OA\Tag(name="rewards")
     * @Security(name="Bearer")
     */
    public function fetchUserRewardsAction(User $user)
    {
        // ...
    }
}

控制器方法上的普通 PHPDoc 块用于摘要和描述。

提示

使用属性/注解的示例可以在 SwaggerPHP 示例中找到。但是,与这些示例不同的是,当使用此扩展包时,您无需指定路径,并且可以轻松记录模型以及下面描述的其他一些属性,因为可以使用 Symfony 集成自动记录它们。

提示

NelmioApiDocBundle 理解 symfony 的控制器属性。在控制器内部使用这些属性允许此扩展包自动创建必要的文档。更多信息可以在这里找到:Symfony 属性

使用模型

如上面的示例所示,该扩展包提供了 #[Model] 属性。使用它代替定义引用,扩展包将推断您的模型属性。

注意

模型可以是 Symfony 表单类型、Doctrine ORM 实体或通用 PHP 对象。

此属性有两个选项

  • type 用于指定模型的类型
1
2
3
4
5
6
/**
 * @OA\Response(
 *     response=200,
 *     @Model(type=User::class)
 * )
 */
  • groups 用于指定用于(反)序列化模型的序列化组
1
2
3
4
5
6
/**
* @OA\Response(
*     response=200,
*     @Model(type=User::class, groups={"non_sensitive_data"})
* )
*/
  • groups 也可以用于指定用于(反)序列化模型的约束验证组,但这必须在配置中启用
1
2
3
nelmio_api_doc:
    use_validation_groups: true
    # ...

启用此功能后,模型中设置的组将同时应用于序列化器属性和验证器约束。以下面的模型类为例

1
2
3
4
5
6
7
8
9
10
11
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

class UserDto
{
    /**
     * @Groups({"default", "create", "update"})
     * @Assert\NotBlank(groups={"default", "create"})
     */
    public string $username;
}

NotBlank 约束将仅应用于 defaultcreate 组,但不应用于 update。更实际地说:username 属性将显示为模型创建和默认组的 required,但不显示为更新组的 required。当使用代码生成器构建 API 客户端时,这通常会转化为客户端验证和类型。NotBlank 添加 required 将导致该属性类型不可为空,例如。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use OpenApi\Annotations as OA;

 /**
  * shows `username` as `required` in the OpenAPI schema (not nullable)
  * @OA\Response(
  *     response=200,
  *     @Model(type=UserDto::class, groups={"default"})
  * )
  */

 /**
  * Similarly, this will make the username `required` in the create
  * schema
  * @OA\RequestBody(@Model(type=UserDto::class, groups={"create"}))
  */

 /**
  * But for updates, the `username` property will not be required
  * @OA\RequestBody(@Model(type=UserDto::class, groups={"update"}))
  */

提示

当在 #[OA\Response]#[OA\Parameter] 的根部使用时,#[Model] 会自动嵌套在 #[OA\Schema] 中。

媒体类型默认为 application/json

要直接在 #[OA\Schema], #[OA\Items]#[OA\Property] 中使用 #[Model],您必须使用 $ref 字段

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * @OA\Response(
 *     @OA\JsonContent(ref=@Model(type=User::class))
 * )
 *
 * or
 *
 * @OA\Response(@OA\XmlContent(
 *     @OA\Schema(type="object",
 *         @OA\Property(property="foo", ref=@Model(type=FooClass::class))
 *     )
 * ))
 */

Symfony 表单类型

您可以使用 documentation 选项自定义表单字段的文档

1
2
3
4
5
6
$builder->add('username', TextType::class, [
    'documentation' => [
        'type' => 'string', // would have been automatically detected in this case
        'description' => 'Your username.',
    ],
]);

请参阅 OpenAPI 3.0 规范 以查看 documentation 选项的所有可用字段(它接受与 OpenApi Property 对象相同的字段)。

通用 PHP 对象

提示

如果您未使用 JMS Serializer,则 Symfony PropertyInfo 组件 用于描述您的模型。它支持 doctrine 属性/注解、类型提示,甚至 PHP doc 块。当使用 Symfony 序列化器时,它还支持序列化组。

如果您正在使用 JMS Serializer,则默认情况下使用 JMS 序列化器的元数据来描述您的模型。其他信息从 PHP doc 块注释中提取,但属性类型必须在 JMS 属性/注解中指定。

注意:如果您正在使用序列化上下文(例如 Groups),则每个排列都将被视为单独的路径。例如,如果您在代码的不同位置定义了以下两个变体

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * A nested serializer property with no context group
 *
 * @JMS\VirtualProperty
 * @JMS\Type("ArrayCollection<App\Response\ItemResponse>")
 * @JMS\Since("1.0")
 *
 * @return Collection|ItemResponse[]
 */
public function getItems(): Collection|array
{
    return $this->items;
}
1
@OA\Schema(ref=@Model(type="App\Response\ItemResponse", groups=["Default"])),

即使 Default 和 blank 相同,它也会生成两个不同的组件模式(ItemResponse,ItemResponse2)。这是按设计进行的。

如果您更喜欢使用 Symfony PropertyInfo 组件(您将无法使用 JMS 序列化组),您可以在配置中禁用 JMS 序列化器支持

1
2
nelmio_api_doc:
    models: { use_jms: false }

或者,也可以通过在 serializationContext 中设置 useJms 来选择每个端点不使用 JMS 序列化器

1
/** @OA\Response(response=200, @Model(type=UserDto::class, serializationContext={"useJms"=false})) */

当将 JMS 序列化器与 willdurand/Hateoas (和 BazingaHateoasBundle)结合使用时,将自动提取 HATEOAS 元数据

提示

在您的配置中启用 TypeInfo 组件 以改进自动类型猜测

1
2
3
nelmio_api_doc:
    type_info: true
    # ...

4.35

TypeInfo 组件 在 Symfony 7.2 中作为稳定功能引入。

如果您想自定义对象属性的文档,可以使用 #[OA\Property]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use Nelmio\ApiDocBundle\Attribute\Model;
use OpenApi\Annotations as OA;

class User
{
    /**
     * @var int
     * @OA\Property(description="The unique identifier of the user.")
     */
    public $id;

    /**
     * @OA\Property(type="string", maxLength=255)
     */
    public $username;

    /**
     * @OA\Property(ref=@Model(type=User::class))
     */
    public $friend;

    /**
     * @OA\Property(description="This is my coworker!")
     */
    public setCoworker(User $coworker) {
        // ...
    }
}

请参阅 OpenAPI 3.0 规范 以查看 #[@OA\Property] 的所有可用字段。

本作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可协议获得许可。
目录
    版本