openApi3 规范及knife4j使用

2,515 阅读7分钟

理解 OpenAPI3 及使用

OpenAPI 3,也被称为OpenAPI规范(OpenAPI Specification,OAS),起源于Swagger 2.0规范,提供一个标准的、与具体编程语言无关的 RESTful API 描述规范

项目中使用 Swagger 来自动生成 RESTful API 的接口文档,对于配置项 SwaggerConfiguration 之前都是 CV ,但关于每一项配置的含义都是一知半解,本文通过 Swagger EditorOpenAPI规范 理解清楚常用配置项的含义。

基于springboot2.x + OpenAPI3,使用 Knife4j 来自动生成接口文档,依赖引入

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
    <version>4.3.0</version>
</dependency>

Info 对象

通过 OpenAPI3 info 对象设置接口文档的基本信息,info 对象:

字段名类型描述
titlestring必选. 应用的名称。
descriptionstring对应用的简短描述。可以被用来表示富文本呈现。
termsOfServicestring指向服务条款的URL地址,必须是URL地址格式。
contact对象所开放的API的联系人信息。
license对象所开放的API的证书信息。
versionstring必选. API文档的版本信息(注意:这个版本和开放API规范版本没有任何关系)。

Contact 对象:

字段名类型描述
namestring人或组织的名称。
urlstring指向联系人信息的URL地址,必须是URL地址格式。
emailstring人或组织的email地址,必须是email地址格式。

License 对象:

字段名类型描述
namestring必选. API的证书名。
urlstring指向API所使用的证书的URL地址,必须是URL地址格式。

配置项如下:

openapi: "3.0.2"
info:
  title: openAPI Demo
  description: "This is an API program for teaching"
  version: '1.1'
  termsOfService: "https://openapi.apifox.cn/"
  contact:
    name: "api developer"
    url: "http://myblog.cn"
    email: "youemai@gmail.com"
  license:
    name: "Apache 2.0"
    url: "http://springdoc.org"
paths: {}

SwaggerConfiguration 配置项

package com.auth.cloud.swagger.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

/**
 *
 * @author 
 * @date 2024/02/27
 */
@AutoConfiguration
@ConditionalOnClass({OpenAPI.class})
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerConfiguration {

    // ========== 全局 OpenAPI 配置 ==========
    @Bean
    public OpenAPI createOpenApi(SwaggerProperties swaggerProperties) {
        System.out.println("SwaggerAutoConfiguration.createOpenApi()"+swaggerProperties);
        return new OpenAPI()
                .info(buldInfo(swaggerProperties))
                ;
    }

    public Info buldInfo(SwaggerProperties swaggerProperties) {
        return new Info()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .version(swaggerProperties.getVersion())
                .termsOfService(swaggerProperties.getTermsOfService())
                .contact(new Contact().name(swaggerProperties.getAuthor()).email(swaggerProperties.getEmail()).url(swaggerProperties.getUrl()))
                .license(new License().name(swaggerProperties.getLicense()).url(swaggerProperties.getLicenseUrl()));
    }
}

效果图如下:

1.info.png

servers 对象

servers 主要表示访问服务端的基础路径,既在访问接口前都会带上该参数,无需手动配置,示例如下:

2.servers.png

Paths 对象

paths 对象包含真正的 API 信息内容,定义各个的端点和操作的相对路径,自动生成。

字段名模式类型描述
/{path}Path Item 对象到各个端点的相对路径,路径必须以/打头,这个路径会被直接连接Server 对象url字段以组成完整URL地址(不会考虑是否是相对路径)。这里可以使用 Path templating ,当做URL地址匹配时,不带路径参数的路径会被优先匹配。应该避免定义多个具有相同路径层级但是路径参数名不同的路径,因为他们是等价的。当匹配出现歧义时,由使用的工具自行决定使用那个路径。

3.paths.png

以下是目前会用到的所有关于接口文档的注解

import com.auth.cloud.common.pojo.CommonResult;

import com.auth.cloud.i18n.core.I18n;
import com.auth.cloud.permission.service.RoleService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


/**
 * @author 
 * @date 2024/01/03
 */
@RestController
@RequestMapping("/role")
@Slf4j
@Validated
@Tag(name = "权限管理后台 - 角色", description = "角色信息接口")
public class RoleController {

    @Autowired
    private I18n i18n;

    @Autowired
    private RoleService roleService;

    @GetMapping("/{id}")
    @Operation(summary = "测试接口",description = "测试接口参数")
    @Parameters({
            @Parameter(name = "id", description = "文件id", in = ParameterIn.PATH),
            @Parameter(name = "token", description = "请求token", required = true, in = ParameterIn.HEADER),
            @Parameter(name = "name", description = "文件名称", required = true, in = ParameterIn.QUERY)
    })
    public CommonResult<String> test(@PathVariable("id") String id, @RequestHeader("token") String token,
                                         @RequestParam("name") String name) {
        return CommonResult.success("name" + name + "id" + id + "token" + token);
    }
}

配置项如下:

paths:
  '/role/{id}':
    get:
      tags:
        - 权限管理后台 - 角色
      summary: 测试接口
      description: 测试接口参数
      operationId: test
      parameters:
        - name: id
          in: path
          description: 文件id
          required: true
          schema:
            type: string
        - name: token
          in: header
          description: 请求token
          required: true
          schema:
            type: string
        - name: name
          in: query
          description: 文件名称
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/CommonResultString'
components:
  schemas:
    CommonResultString:
      type: object
      properties:
        code:
          type: integer
          format: int32
        msg:
          type: string
        data:
          type: string

3.paths_2.png

以上信息描述一个 /role/{id} 的接口 ,它只包含一个 get 操作对象,也称 Operation 对象,属性包含以下:

字段名类型描述
tags[string]用于控制API文档的标签列表,标签可以用于在逻辑上分组
summarystring对此操作行为的简短描述。
descriptionstring对此操作行为的详细解释。
operationIdstring用于标识此操作的唯一字符串,即方法名。
parameters[Parameter 对象 | Reference 对象]定义可用于此操作的参数列表,如果一个同名的参数已经存在于 Path Item,那么这里的定义会覆盖它但是不能移除上面的定义。这个列表不允许包含重复的参数,参数的唯一性由 namelocation 的组合来确定。这个列表可以使用 Reference 对象 来连接定义于 OpenAPI 对象 components/parameters 的参数。
responsesResponses 对象必选. 定义执行此操作后的可能的响应值列表。
security[Security Requirement 对象]声明哪种安全机制可用于此操作。这个列表可以包含多种可用于此操作的安全需求对象,但是在认证一个请求时应该仅使用其中一种。这里的定义会覆盖任何在顶层 security 中的安全声明,因此可以声明一个空数组来变相的移除顶层的安全声明。

parameters:该接口的请求参数对象,描述如下:

  • name:参数名称

  • in:参数出现的位置,通常是 headerpathquerycookie

  • description:参数的描述(支持 markdown)

  • required:必填项

  • deprecated:是否弃用

  • allowEmptyValue:允许提交空值

  • style:参数序列化方式

  • explode:与数组相关的参数

  • schema:参数的模型

  • example:媒体类型的示例

3.paths_3.png

Response :描述单个API操作的响应,描述如下:

字段名类型描述
descriptionstring必选. 对响应的简短描述。CommonMark syntax可以被用来呈现富文本格式.
headersMap[string, Header 对象 | Reference 对象]映射HTTP头名称到其定义。RFC7230 规定了HTTP头名称不区分大小写。如果一个响应头使用"Content-Type"作为HTTP头名称,它会被忽略。
contentMap[string, Media Type 对象]一个包含描述预期响应负载的映射。使用 media type 或 media type range 作为键,以响应的描述作为值。当一个响应匹配多个键时,只有最明确的键才适用。比如:text/plain 会覆盖 text/*

security 对象

大部分的 Web 服务都是需要经过身份认证的才能访问,security 就是用于描述 API 的安全信息和访问授权协议等信息的对象,该属性定义可以放在 Paths 对象的 Operation 对象中,在可在 OpenAPI 文档的根目录添加安全对象,两者的区别如下:

4.security_2.png

4.security.png

Security Requirement 对象

每个属性的名字都必须与Components 对象Security Schemes 声明的 security scheme 相符。

字段名模式类型描述
{name}[string]每个名称都必须对应于 Components 对象 下的 Security Schemes 的一个 security scheme。如果此 security scheme 是 "oauth2""openIdConnect" 类型,那么其值是用于执行的一组 scope names。对于其他 security scheme 类型。此数组必须是空的。

Security Requirement 对象示例

Non-OAuth2 Security Requirement

{
  "api_key": []
}
api_key: []

OAuth2 Security Requirement

{
  "petstore_auth": [
    "write:pets",
    "read:pets"
  ]
}
petstore_auth:
- write:pets
- read:pets

Security Scheme 对象

固定字段

字段名类型Applies To描述
typestringAny必选. security scheme 的类型。有效值包括 "apiKey", "http", "oauth2", "openIdConnect".
descriptionstringAny对 security scheme 的简短描述. CommonMark syntax可以被用来呈现富文本格式.
namestringapiKey必选. 用于 header、 query 或 cookie 的参数名字。
instringapiKey必选. API key 的位置。有效值包括 "query""header""cookie".
schemestringhttp必选. 用于 Authorization header as defined in RFC7235 的 HTTP Auahorization scheme 的名字.
bearerFormatstringhttp ("bearer")用于提示客户端所使用的bearer token的格式。Bearer token 通常通过一个authorization server生成,所以这个字段最主要的目的是用来记录这个信息。
flowsOAuth Flows 对象oauth2必选. 一个包含所支持的 flow types 的配置信息的对象。
openIdConnectUrlstringopenIdConnect必选. 用于发现 OAuth2 配置值的OpenId Connect URL,必须是 URL 形式。

4.security_3.png

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;

import java.util.HashMap;
import java.util.Map;

/**
 * Swagger 自动配置类,基于 OpenAPI + Springdoc 实现。
 *
 * @author 
 * @date 2024/02/27
 */
@AutoConfiguration
@ConditionalOnClass({OpenAPI.class})
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerAutoConfiguration {

    // ========== 全局 OpenAPI 配置 ==========
    @Bean
    public OpenAPI createOpenApi(SwaggerProperties swaggerProperties) {
        Map<String, SecurityScheme> securitySchemas = buildSecuritySchemes();
        OpenAPI openAPI = new OpenAPI()
                .info(buldInfo(swaggerProperties))
                // 接口安全配置
                .components(new Components().securitySchemes(securitySchemas))
                .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
        return openAPI;
    }

    /**
     * API 摘要信息
     */
    public Info buldInfo(SwaggerProperties swaggerProperties) {
        return new Info()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .version(swaggerProperties.getVersion())
                .termsOfService(swaggerProperties.getTermsOfService())
                .contact(new Contact().name(swaggerProperties.getAuthor()).email(swaggerProperties.getEmail()).url(swaggerProperties.getUrl()))
                .license(new License().name(swaggerProperties.getLicense()).url(swaggerProperties.getLicenseUrl()));
    }

    /**
     * 安全模式,这里配置通过请求头 Authorization 传递 token 参数
     */
    private Map<String, SecurityScheme> buildSecuritySchemes() {
        Map<String, SecurityScheme> securitySchemes = new HashMap<>();
        SecurityScheme securityScheme = new SecurityScheme()
                .type(SecurityScheme.Type.APIKEY) // 类型
                .name(HttpHeaders.AUTHORIZATION) // 请求头的 name
                .in(SecurityScheme.In.HEADER); // token 所在位置
        securitySchemes.put(HttpHeaders.AUTHORIZATION, securityScheme);
        return securitySchemes;
    }
}

参考:

OpenAPI 3.0 规范-食用指南