Openapi Swaggerui

本指南介绍 Quarkus 应用程序如何通过 OpenAPI 标准暴露其 API 描述,以及如何通过用户友好的 Swagger UI 来测试它。

必备条件

要完成本指南,您需要:

  • 15 分钟以内

  • IDE

  • 安装了JDK 1.8+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.6.2+

结构

本指南中, 我们创建一个简单的 REST 应用程序来展示下如何快速暴露您的 API 规范并在用户界面中测试它。

成果

我们建议您按照下面章节指示,一步一步创建应用程序。 但是你也可以直接跳到已完成的示例。

克隆 Git 仓库: git clone https://github.com/quarkusio/quarkus-quickstarts.git, 或下载 压缩包

解决方案在 openapi-swaggerui-quickstart 目录.

创建 Maven 项目

首先,我们需要一个新项目。 通过以下命令创建一个新项目:

mvn io.quarkus:quarkus-maven-plugin:1.3.1.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=openapi-swaggerui-quickstart \
    -DclassName="org.acme.openapi.swaggerui.FruitResource" \
    -Dpath="/fruits" \
    -Dextensions="resteasy-jsonb"
cd openapi-swaggerui-quickstart

此命令生成一个带有 /fruits REST 接口的 Maven 项目。

暴露一个 REST 资源

我们将创建一个 Fruit bean 和一个 FruitResouce REST 资源 (如果您想详细了解如何通过 Quarkus 创建 REST API,请随时查看 编写 JSON REST 服务指南)。

package org.acme.openapi.swaggerui;

public class Fruit {

    public String name;
    public String description;

    public Fruit() {
    }

    public Fruit(String name, String description) {
        this.name = name;
        this.description = description;
    }
}
package org.acme.openapi.swaggerui;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.DELETE;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;

@Path("/fruits")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class FruitResource {

    private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));

    public FruitResource() {
        fruits.add(new Fruit("Apple", "Winter fruit"));
        fruits.add(new Fruit("Pineapple", "Tropical fruit"));
    }

    @GET
    public Set<Fruit> list() {
        return fruits;
    }

    @POST
    public Set<Fruit> add(Fruit fruit) {
        fruits.add(fruit);
        return fruits;
    }

    @DELETE
    public Set<Fruit> delete(Fruit fruit) {
        fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
        return fruits;
    }
}

当我们修改API时,我们还需要更新测试:

package org.acme.openapi.swaggerui;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import javax.ws.rs.core.MediaType;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsInAnyOrder;

@QuarkusTest
public class FruitResourceTest {

    @Test
    public void testList() {
        given()
                .when().get("/fruits")
                .then()
                .statusCode(200)
                .body("$.size()", is(2),
                        "name", containsInAnyOrder("Apple", "Pineapple"),
                        "description", containsInAnyOrder("Winter fruit", "Tropical fruit"));
    }

    @Test
    public void testAdd() {
        given()
                .body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}")
                .header("Content-Type", MediaType.APPLICATION_JSON)
                .when()
                .post("/fruits")
                .then()
                .statusCode(200)
                .body("$.size()", is(3),
                        "name", containsInAnyOrder("Apple", "Pineapple", "Pear"),
                        "description", containsInAnyOrder("Winter fruit", "Tropical fruit", "Winter fruit"));

        given()
                .body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}")
                .header("Content-Type", MediaType.APPLICATION_JSON)
                .when()
                .delete("/fruits")
                .then()
                .statusCode(200)
                .body("$.size()", is(2),
                        "name", containsInAnyOrder("Apple", "Pineapple"),
                        "description", containsInAnyOrder("Winter fruit", "Tropical fruit"));
    }
}

暴露 OpenAPI 规范

Quarkus 提议使用与 Eclipse MicroProfile OpenAPI 标准兼容的 smallrye-openapi extension 来生成你 API 的 OpenAPI v3 规范.

您只需要将 openapi 扩展添加到您的 Quarkus 应用程序:

./mvnw quarkus:add-extension -Dextensions="openapi"

现在,准备运行我们的应用程序:

./mvnw compile quarkus:dev

一旦应用程序启动,您可以访问网址 /openapi

$ curl http://localhost:8080/openapi
openapi: 3.0.1
info:
  title: Generated API
  version: "1.0"
paths:
  /fruits:
    get:
      responses:
        200:
          description: OK
          content:
            application/json: {}
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Fruit'
      responses:
        200:
          description: OK
          content:
            application/json: {}
    delete:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Fruit'
      responses:
        200:
          description: OK
          content:
            application/json: {}
components:
  schemas:
    Fruit:
      properties:
        description:
          type: string
        name:
          type: string

如果不喜欢默认的网址 /openapi,你可以在 application.properties 中添加以下配置来调整:

quarkus.smallrye-openapi.path=/swagger

CTRL+C 停掉应用程序。

提供的应用程序级别 OpenAPI 注解

有一些 MicroProfile OpenAPI 注解描述了全局的 API 信息,例如:

  • API 标题

  • API 描述

  • 版本

  • 联系信息

  • 许可协议

所有这些信息(以及更多信息) 都可以在 Java 代码中 JAX-RS Application 类上使用合适的 OpenAPI 注解来指定。 因为 Quarkus 中 JAX-RS Application 类不是必备的,您很可能需要创建一个。 它可以只是一个简单 extends javax.ws.rs.core.Application 的空类。 然后此空类就可以用各种 OpenAPI 注解,如 @OpenAPIDefinition 。 例如:

@OpenAPIDefinition(
    tags = {
            @Tag(name="widget", description="Widget operations."),
            @Tag(name="gasket", description="Operations related to gaskets")
    },
    info = @Info(
        title="Example API",
        version = "1.0.1",
        contact = @Contact(
            name = "Example API Support",
            url = "http://exampleurl.com/contact",
            email = "techsupport@example.com"),
        license = @License(
            name = "Apache 2.0",
            url = "http://www.apache.org/licenses/LICENSE-2.0.html"))
)
public class ExampleApiApplication extends Application {
}

从静态文件加载 OpenAPI 规范

相对通过扫描注解动态创建 OpenAPI 规范,Quarkus 也支持静态的 OpenAPI 规范文档。 静态文件必须是符合 OpenAPI 标准 的有效文档。 符合 OpenAPI 标准的 OpenAPI 文档本身就是一个有效的 JSON 对象,可以以 yamljson 格式表示。

要使用它,我们将把 OpenAPI 文档放在 META-INF/openapi.yaml 对应 /fruits 接口 。 如果你喜欢 Quarkus 也支持其它 OpenAPI document paths 路径。

openapi: 3.0.1
info:
  title: Static OpenAPI document of fruits resource
  description: Fruit resources Open API documentation
  version: "1.0"

servers:
  - url: http://localhost:8080/openapi
    description: Optional dev mode server description

paths:
  /fruits:
    get:
      responses:
        200:
          description: OK - fruits list
          content:
            application/json: {}
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Fruit'
      responses:
        200:
          description: new fruit resource created
          content:
            application/json: {}
    delete:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Fruit'
      responses:
        200:
          description: OK - fruit resource deleted
          content:
            application/json: {}
components:
  schemas:
    Fruit:
      properties:
        description:
          type: string
        name:
          type: string

默认情况下,请求 /openapi 时会返回融合了静态文件和根据应用程序接口代码生成的 OpenAPI 文档。 但我们可以修改 application.properties 中的 mp.openapi.scan.disabl=true 来改为仅使用静态 OpenAPI 文档。

现在, /openapi 接口将只使用静态的 OpenAPI 文档,而不是动态生成一个。

关于 OpenAPI 文档路径

Quarkus 支持各种路径来存储您的 OpenAPI 文档。 我们建议你将其放在`META-INF/openapi.yml`下。 替代路径:

  • META-INF/openapi.yaml

  • META-INF/openapi.yml

  • META-INF/openapi.json

  • WEB-INF/classes/META-INF/openapi.yml

  • WEB-INF/classes/META-INF/openapi.yaml

  • WEB-INF/classes/META-INF/openapi.json

在开发过程中支持静态OpenAPI 文档的实时重新加载。 修改 OpenAPI 文档就会被 Quarkus 采用。

使用 Swagger UI 进行开发

构建 API 时,开发者想要快速测试它们。 Swagger UI 是一个很好的工具 可以与您的 API 直观交互。 界面是根据您的 OpenAPI 规范自动生成的。

Quarkus smallrye-openapi extension 伴有一个 swagger-ui extension 来嵌入了一个配置正确的 Swagger UI 页面。

默认情况下,Swagger UI 仅在 Quarkus 在开发或测试模式下启动时有效。

如果你也想要在生产中提供它,你可以在你的 application.properties 中包含以下配置:

quarkus.swagger-ui.always-include=true

这是一个构建阶段属性,它不能在应用程序生成后在运行时更改。

默认情况下,Swagger UI 可以通过 /swagger-ui 访问。

您可以通过设置 application.properties 中的 quarkus.swagger-ui.path 属性来调整此路径:

quarkus.swagger-ui.path=/my-custom-path

不允许使用`/`值,因为它会阻止应用程序任何其他服务。

现在,准备运行我们的应用程序:

./mvnw compile quarkus:dev

您可以在应用程序日志中检查 Swagger UI 路径:

00:00:00,000 INFO  [io.qua.swa.run.SwaggerUiServletExtension] Swagger UI available at /swagger-ui

一旦您的应用程序启动,您可以访问 http://localhost:8080/swagger-ui 探索下你的 API。

您可以可视化您的 API 的操作和规范。 Visualize your API

您可以与 API 交互以快速测试。 Interact with your API

CTRL+C 停掉应用程序。

配置参考

OpenAPI

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The path at which to register the OpenAPI Servlet.

string

/openapi

Swagger UI

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The path where Swagger UI is available. The value / is not allowed as it blocks the application from serving anything else.

string

/swagger-ui

If this should be included every time. By default this is only included when the application is running in dev mode.

boolean

false

If Swagger UI should be enabled. By default, Swagger UI is enabled.

boolean

true

quarkus.pro 是基于 quarkus.io 的非官方中文翻译站 ,最后更新 2020/04 。
沪ICP备19006215号-8
QQ交流群:1055930959
微信群: