MicroProfile OpenAPI 适用于所有人

MicroProfile OpenAPI 主要用于为 OpenAPI 添加到 JAX-RS 端点。 在这篇博文中,我们将探讨 SmallRye实现 如何通过一些额外的功能以及对更多Web框架的支持来扩展它,当在Quarkus中使用时。

使用Quarkus

示例代码可以在 此处 找到。您也可以使用 code.quarkus.io 初始化一个项目 - 只需确保包含SmallRye OpenAPI扩展。

JAX-RS

让我们从Quarkus中的一个基本JAX-RS示例开始。我们有一个Greeting对象,其中有一个message和一个to字段,我们将为问候语创建GETPOSTDELETE端点。

除了常规的Quarkus设置外,您还需要在pom.xml中添加以下内容来创建一个JAX-RS端点

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy</artifactId>
</dependency>

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>

在Quarkus中,您不需要Application类,我们可以直接添加端点类

@Path("/jax-rs")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class JaxRsGreeting {

    @GET
    @Path("/hello")
    public Greeting helloJaxRs() {
        return new Greeting("Hello", "JAX-RS");
    }

    @POST
    @Path("/hello")
    public Greeting newHelloJaxRs(Greeting greeting) {
        return greeting;
    }

    @DELETE
    @Path("/hello/{message}")
    public void deleteHelloJaxRs(@PathParam("message") String message) {
        // Here do the delete...
    }

}

到目前为止,我们还没有添加任何MicroProfile OpenAPI注解,但是因为我们添加了quarkus-smallrye-openapi扩展,我们将在/openapi下生成一个Schema文档

---
openapi: 3.0.3
info:
  title: Generated API
  version: "1.0"
paths:
  /jax-rs/hello:
    get:
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /jax-rs/hello/{message}:
    delete:
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content
components:
  schemas:
    Greeting:
      type: object
      properties:
        message:
          type: string
        to:
          type: string

有关更多信息,请参阅 quarkus.io/guides/rest-json

OpenAPI

您可以通过使用MicroProfile OpenAPI将更多信息添加到生成的Schema文档中。

使用配置添加头信息

我们在SmallRye中添加的一个功能是能够通过MicroProfile配置添加头信息,通常您会使用注解将这些信息添加到Application类中。这在Quarkus中很有用,因为您不需要Application类。因此,将以下内容添加到application.properties将为您提供一些头信息

mp.openapi.extensions.smallrye.info.title=OpenAPI for Everyone
%dev.mp.openapi.extensions.smallrye.info.title=OpenAPI for Everyone (development)
%test.mp.openapi.extensions.smallrye.info.title=OpenAPI for Everyone (test)
mp.openapi.extensions.smallrye.info.version=1.0.0
mp.openapi.extensions.smallrye.info.description=Example on how to use OpenAPI everywhere
mp.openapi.extensions.smallrye.info.contact.email=phillip.kruger@redhat.com
mp.openapi.extensions.smallrye.info.contact.name=Phillip Kruger
mp.openapi.extensions.smallrye.info.contact.url=https://www.phillip-kruger.com
mp.openapi.extensions.smallrye.info.license.name=Apache 2.0
mp.openapi.extensions.smallrye.info.license.url=https://apache.ac.cn/licenses/LICENSE-2.0.html

现在查看/openapi下生成的Schema文档的头信息

---
openapi: 3.0.3
info:
  title: OpenAPI for Everyone (development)
  description: Example on how to use OpenAPI everywhere
  contact:
    name: Phillip Kruger
    url: https://www.phillip-kruger.com
    email: phillip.kruger@redhat.com
  license:
    name: Apache 2.0
    url: https://apache.ac.cn/licenses/LICENSE-2.0.html
  version: 1.0.0

# Rest of the schema document...

为操作添加一些OpenAPI注解

您可以使用MicroProfile OpenAPI中的任何注解来进一步描述您的端点,例如Tag注解

@Path("/jax-rs")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "JAX-RS Resource", description = "Basic Hello World using JAX-RS") (1)
public class JaxRsGreeting {
    //...
}
1 MicroProfile OpenAPI注解的示例用法。

自动生成operation id

一些使用Schema文档生成客户端存根的工具需要在Schema文档中有一个operationId,该ID用于命名客户端存根方法。我们在SmallRye中添加了支持,可以使用方法名(METHOD)、类名和方法名(CLASS_METHOD)或包名、类名和方法名(PACKAGE_CLASS_METHOD)来自动生成它。为此,请将以下内容添加到application.properties

mp.openapi.extensions.smallrye.operationIdStrategy=METHOD

您现在将在每个操作的Schema文档中看到operationId

---
openapi: 3.0.3

# Header omitted...

/jax-rs/hello:
    get:
      tags:
      - JAX-RS Resource
      operationId: helloJaxRs (1)
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - JAX-RS Resource
      operationId: newHelloJaxRs (1)
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /jax-rs/hello/{message}:
    delete:
      tags:
      - JAX-RS Resource
      operationId: deleteHelloJaxRs (1)
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content
1 自动生成的operationId

更改OpenAPI版本

一些API网关可能需要特定版本的OpenAPI才能正常工作。SmallRye扩展生成的Schema文档将使用3.0.3作为版本,但由于这些版本之间只有细微的差异,您可以将其更改为3.0.03.0.13.0.2。您可以通过在application.properties中添加以下内容来实现

mp.openapi.extensions.smallrye.openapi=3.0.2

现在生成的版本将是

---
openapi: 3.0.2

# Rest of the document...

有关更多信息,请参阅 quarkus.io/guides/openapi-swaggerui

Spring Web

最近,SmallRye OpenAPI添加了对Spring Web的支持,这意味着,当您在Quarkus中使用Spring Web时,不仅可以看到默认的OpenAPI文档,还可以使用MicroProfile OpenAPI来进一步描述您的Spring Web端点。

让我们将一个Spring Rest Controller添加到我们当前的应用程序中。首先,在您的pom.xml中添加这个

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-spring-web</artifactId>
</dependency>

现在您可以创建一个类似于我们到目前为止看到的JAX-RS的端点,但使用Spring Web

@RestController
@RequestMapping(value = "/spring", produces = MediaType.APPLICATION_JSON_VALUE)
@Tag(name = "Spring Resource", description = "Basic Hello World using Spring")
public class SpringGreeting {

    @GetMapping("/hello")
    public Greeting helloSpring() {
        return new Greeting("Hello", "Spring");
    }

    @PostMapping("/hello")
    public Greeting newHelloSpring(@RequestBody Greeting greeting) {
        return greeting;
    }

    @DeleteMapping("/hello/{message}")
    public void deleteHelloSpring(@PathVariable(name = "message") String message) {
        // Here do the delete...
    }
}

Spring注解将被扫描,并添加到您的Schema文档中

---
openapi: 3.0.3

# Header omitted...

/spring/hello:
    get:
      tags:
      - Spring Resource
      operationId: helloSpring
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - Spring Resource
      operationId: newHelloSpring
      requestBody:
        content:
          '_/_':
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /spring/hello/{message}:
    delete:
      tags:
      - Spring Resource
      operationId: deleteHelloSpring
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content

有关更多信息,请参阅 quarkus.io/guides/spring-web

Vert.x Reactive Routes

在Quarkus中,您还可以使用Reactive Routes构建Vert.x端点。与Spring Web类似,您的端点将在OpenAPI Schema中可用,并且可以使用MicroProfile OpenAPI进一步描述。要在Quarkus中添加Vert.x Reactive Route,您需要在pom.xml中添加以下内容

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-vertx-web</artifactId>
</dependency>

现在您可以创建端点

@ApplicationScoped
@RouteBase(path = "/vertx", produces = "application/json")
@Tag(name = "Vert.x Resource", description = "Basic Hello World using Vert.x")
public class VertxGreeting {

    @Route(path = "/hello", methods = HttpMethod.GET)
    public Greeting helloVertX() {
        return new Greeting("Hello", "Vert.x");
    }

    @Route(path = "/hello", methods = HttpMethod.POST)
    public Greeting newHelloVertX(@Body Greeting greeting) {
        return greeting;
    }

    @Route(path = "/hello/:message", methods = HttpMethod.DELETE)
    public void deleteHelloVertX(@Param("message") String message) {
        // Here do the delete...
    }
}

现在您的Vert.x Routes在OpenAPI中可用了

---
openapi: 3.0.3

# Header omitted...

/vertx/hello:
    get:
      tags:
      - Vert.x Resource
      operationId: helloVertX
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - Vert.x Resource
      operationId: newHelloVertX
      requestBody:
        content:
          '_/_':
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /vertx/hello/{message}:
    delete:
      tags:
      - Vert.x Resource
      operationId: deleteHelloVertX
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content

有关更多信息,请参阅 quarkus.io/guides/reactive-routes

使用Panache生成的端点

在Quarkus中,您可以使用Panache生成JAX-RS端点。如果您的pom.xml中包含quarkus-smallrye-openapi扩展,这些生成的类也将被扫描并添加到OpenAPI Schema文档中。

有关更多信息,请参阅 quarkus.io/guides/rest-data-panache

任何其他Web框架

您还可以通过在yaml文件中提供Schema文档的该部分来将任何其他端点添加到您的文档中。例如,假设您有一个Servlet公开了一些方法,并且您想将它们添加到Schema文档中。Servlet只是一个例子,任何Web框架都可以在这里工作。

因此,我们首先在pom.xml中添加此项以在Quarkus中添加Servlet支持

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-undertow</artifactId>
</dependency>

我们现在可以像这样创建一个Servlet端点示例

@WebServlet("/other/hello/*")
public class ServletGreeting extends HttpServlet {

    private static final Jsonb JSONB = JsonbBuilder.create();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
        response.setContentType("application/json");
        Greeting greeting = new Greeting("Hello", "Other");
        PrintWriter out = response.getWriter();
        out.print(JSONB.toJson(greeting));
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("application/json");
        Greeting greeting = JSONB.fromJson(request.getInputStream(), Greeting.class);
        PrintWriter out = response.getWriter();
        out.print(JSONB.toJson(greeting));
    }

    @Override
    protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // Here do the delete...
    }
}

现在我们需要一个OpenAPI Schema文档来映射这些端点。您需要将其添加到src/main/resources/META-INF中的一个名为openapi.yml的文件中

---
openapi: 3.0.3
tags:
- name: Other Resource
  description: Basic Hello World using Something else
paths:
  /other/hello:
    get:
      tags:
      - Other Resource
      operationId: helloOther
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - Other Resource
      operationId: newHelloOther
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /other/hello/{message}:
    delete:
      tags:
      - Other Resource
      operationId: deleteHelloOther
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content

这将与其余的端点合并,以公开您文档中的所有路径。因此,最终您的/openapi输出将如下所示

---
openapi: 3.0.2
info:
  title: OpenAPI for Everyone (development)
  description: Example on how to use OpenAPI everywhere
  contact:
    name: Phillip Kruger
    url: https://www.phillip-kruger.com
    email: phillip.kruger@redhat.com
  license:
    name: Apache 2.0
    url: https://apache.ac.cn/licenses/LICENSE-2.0.html
  version: 1.0.0
tags:
- name: Other Resource
  description: Basic Hello World using Something else
- name: Spring Resource
  description: Basic Hello World using Spring
- name: JAX-RS Resource
  description: Basic Hello World using JAX-RS
- name: Vert.x Resource
  description: Basic Hello World using Vert.x
paths:
  /other/hello:
    get:
      tags:
      - Other Resource
      operationId: helloOther
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - Other Resource
      operationId: newHelloOther
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /other/hello/{message}:
    delete:
      tags:
      - Other Resource
      operationId: deleteHelloOther
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content
  /jax-rs/hello:
    get:
      tags:
      - JAX-RS Resource
      operationId: helloJaxRs
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - JAX-RS Resource
      operationId: newHelloJaxRs
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /jax-rs/hello/{message}:
    delete:
      tags:
      - JAX-RS Resource
      operationId: deleteHelloJaxRs
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content
  /spring/hello:
    get:
      tags:
      - Spring Resource
      operationId: helloSpring
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - Spring Resource
      operationId: newHelloSpring
      requestBody:
        content:
          '_/_':
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /spring/hello/{message}:
    delete:
      tags:
      - Spring Resource
      operationId: deleteHelloSpring
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content
  /vertx/hello:
    get:
      tags:
      - Vert.x Resource
      operationId: helloVertX
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
    post:
      tags:
      - Vert.x Resource
      operationId: newHelloVertX
      requestBody:
        content:
          '_/_':
            schema:
              $ref: '#/components/schemas/Greeting'
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
  /vertx/hello/{message}:
    delete:
      tags:
      - Vert.x Resource
      operationId: deleteHelloVertX
      parameters:
      - name: message
        in: path
        required: true
        schema:
          type: string
      responses:
        "204":
          description: No Content
components:
  schemas:
    Greeting:
      type: object
      properties:
        message:
          type: string
        to:
          type: string

这包含来自JAX-RS、Spring Web、Vert.x Reactive Routes和Servlet的资源。

Swagger UI

在Quarkus中,Swagger UI是默认包含的,当您现在浏览到 localhost:8080/swagger-ui 时,您将看到包含所有端点的UI

swagger-ui

总结

在这篇文章中,我们探讨了Quarkus如何扩展MicroProfile OpenAPI规范,以便更轻松地记录您的端点。我们还讨论了如何使用它来记录任何Web框架。

如果您发现任何问题或有任何建议,请前往 SmallRye OpenAPI 项目,我们将在那里进行讨论。