使用OpenAPI Generator實現Open API Server

1.概述

顧名思義, OpenAPI Generator會根據OpenAPI規範生成代碼。它可以為客戶端庫,服務器存根,文檔和配置創建代碼。

它支持各種語言和框架。值得注意的是,它支持C ++,C#,Java,PHP,Python,Ruby,Scala –幾乎所有廣泛使用的工具。

在本教程中,我們將學習如何通過OpenAPI Generator的maven插件實現基於Spring的服務器存根。使用生成器的其他方式是通過其CLI在線工具

2. YAML文件

首先,我們需要一個指定API的YAML文件。我們將其作為生成器的輸入,以生成服務器存根。

這是我們的petstore.yml的片段:

openapi: "3.0.0"

 paths:

 /pets:

 get:

 summary: List all pets

 operationId: listPets

 tags:

 - pets

 parameters:

 - name: limit

 in: query

 ...

 responses:

 ...

 post:

 summary: Create a pet

 operationId: createPets

 ...

 /pets/{petId}:

 get:

 summary: Info for a specific pet

 operationId: showPetById

 ...

 components:

 schemas:

 Pet:

 type: object

 required:

 - id

 - name

 properties:

 id:

 type: integer

 format: int64

 name:

 type: string

 tag:

 type: string

 Error:

 type: object

 required:

 - code

 - message

 properties:

 code:

 type: integer

 format: int32

 message:

 type: string

3. Maven依賴

3.1 OpenAPI Generator的插件

接下來,讓我們為生成器插件添加Maven依賴項:

<plugin>

 <groupId>org.openapitools</groupId>

 <artifactId>openapi-generator-maven-plugin</artifactId>

 <version>5.1.0</version>

 <executions>

 <execution>

 <goals>

 <goal>generate</goal>

 </goals>

 <configuration>

 <inputSpec>

 ${project.basedir}/src/main/resources/petstore.yml

 </inputSpec>

 <generatorName>spring</generatorName>

 <apiPackage>com.baeldung.openapi.api</apiPackage>

 <modelPackage>com.baeldung.openapi.model</modelPackage>

 <supportingFilesToGenerate>

 ApiUtil.java

 </supportingFilesToGenerate>

 <configOptions>

 <delegatePattern>true</delegatePattern>

 </configOptions>

 </configuration>

 </execution>

 </executions>

 </plugin>

如我們所見,我們傳入YAML文件作為inputSpec 。之後,由於需要基於Spring的服務器,因此將generatorName用作spring

然後apiPackage指定將在其中生成API的程序包名稱。接下來,我們在生成器放置數據模型的地方放置了modelPackagedelegatePattern設置為true ,我們要求創建一個可以實現為自定義@Service類的接口。

重要的**是,無論您使用的是CLI,Maven / Gradle插件還是在線生成選項,OpenAPI Generator的選項**都相同。

3.2 Spring依賴

在生成Spring服務器時,我們還需要其依賴項( Spring Boot Starter WebSpring Data JPA ),以便生成的代碼可以按預期進行編譯和運行

<dependencies>

 <dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-web</artifactId>

 <version>2.4.4</version>

 </dependency>

 <dependency>

 <groupId>org.springframework.data</groupId>

 <artifactId>spring-data-jpa</artifactId>

 <version>2.4.6</version>

 </dependency>

 </dependencies>

4.代碼生成

要生成服務器存根,我們只需要運行:

mvn clean install

結果,我們得到:

使用OpenAPI

現在讓我們看一下代碼,從apiPackage的內容開始。

首先,**我們獲得一個名為PetsApi**的API接口,其中包含YAML規範中定義的所有請求映射。這是代碼段:

@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen",

 date = "2021-03-22T23:26:32.308871+05:30[Asia/Kolkata]")

 @Validated

 @Api(value = "pets", description = "the pets API")

 public interface PetsApi {

 /**

 * GET /pets : List all pets

 *

 * @param limit How many items to return at one time (max 100) (optional)

 * @return A paged array of pets (status code 200)

 * or unexpected error (status code 200)

 */

 @ApiOperation(value = "List all pets", nickname = "listPets", notes = "",

 response = Pet.class, responseContainer = "List", tags={ "pets", })

 @ApiResponses(value = { @ApiResponse(code = 200, message = "A paged array of pets",

 response = Pet.class, responseContainer = "List"),

 @ApiResponse(code = 200, message = "unexpected error", response = Error.class) })

 @GetMapping(value = "/pets", produces = { "application/json" })

 default ResponseEntity<List> listPets(@ApiParam(

 value = "How many items to return at one time (max 100)")

 @Valid @RequestParam(value = "limit", required = false) Integer limit) {

 return getDelegate().listPets(limit);

 }



 // other generated methods

 }

其次,由於我們使用委託模式,因此OpenAPI還會為我們PetsApiDelegate特別是,在此接口中聲明的方法返回的HTTP狀態默認為501未實現

@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen",

 date = "2021-03-22T23:26:32.308871+05:30[Asia/Kolkata]")

 public interface PetsApiDelegate {

 /**

 * GET /pets : List all pets

 *

 * @param limit How many items to return at one time (max 100) (optional)

 * @return A paged array of pets (status code 200)

 * or unexpected error (status code 200)

 * @see PetsApi#listPets

 */

 default ResponseEntity<List<Pet>> listPets(Integer limit) {

 getRequest().ifPresent(request -> {

 for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {

 if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {

 String exampleString = "{ \"name\" : \"name\", \"id\" : 0, \"tag\" : \"tag\" }";

 ApiUtil.setExampleResponse(request, "application/json", exampleString);

 break;

 }

 }

 });

 return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

 }



 // other generated method declarations

 }

在那之後,我們看到有一個PetsApiController類,它簡單地連接了委託者

@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen",

 date = "2021-03-22T23:26:32.308871+05:30[Asia/Kolkata]")

 @Controller

 @RequestMapping("${openapi.swaggerPetstore.base-path:}")

 public class PetsApiController implements PetsApi {



 private final PetsApiDelegate delegate;



 public PetsApiController(

 @org.springframework.beans.factory.annotation.Autowired(required = false) PetsApiDelegate delegate) {

 this.delegate = Optional.ofNullable(delegate).orElse(new PetsApiDelegate() {});

 }



 @Override

 public PetsApiDelegate getDelegate() {

 return delegate;

 }

 }

modelPackage ,基於YAML輸入中定義schemas ,生成ErrorPet的數據模型POJO。

讓我們看看其中一個– Pet

@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen",

 date = "2021-03-22T23:26:32.308871+05:30[Asia/Kolkata]")

 public class Pet {

 @JsonProperty("id")

 private Long id;



 @JsonProperty("name")

 private String name;



 @JsonProperty("tag")

 private String tag;



 // constructor



 @ApiModelProperty(required = true, value = "")

 @NotNull

 public Long getId() {

 return id;

 }



 // other getters and setters



 // equals, hashcode, and toString methods

 }

5.測試服務器

現在,要使服務器存根作為服務器發揮作用,所需要做的就是添加委託者接口的實現。

為了簡單起見,在這裡我們不會這樣做,而僅測試存根。此外,在此之前,我們需要一個Spring Application

@SpringBootApplication

 public class Application {

 public static void main(String[] args) {

 SpringApplication.run(Application.class, args);

 }

 }

5.1 使用curl

啟動應用程序後,我們只需運行以下命令:

curl -I http://localhost:8080/pets/

這是預期的結果:

HTTP/1.1 501

 Content-Length: 0

 Date: Fri, 26 Mar 2021 17:29:25 GMT

 Connection: close

5.2 整合測試

另外,我們可以為它編寫一個簡單的集成測試:

@RunWith(SpringRunner.class)

 @SpringBootTest

 @AutoConfigureMockMvc

 public class OpenApiPetsIntegrationTest {

 private static final String PETS_PATH = "/pets/";



 @Autowired

 private MockMvc mockMvc;



 @Test

 public void whenReadAll_thenStatusIsNotImplemented() throws Exception {

 this.mockMvc.perform(get(PETS_PATH)).andExpect(status().isNotImplemented());

 }



 @Test

 public void whenReadOne_thenStatusIsNotImplemented() throws Exception {

 this.mockMvc.perform(get(PETS_PATH + 1)).andExpect(status().isNotImplemented());

 }

 }

六,結論

在本教程中,我們看到瞭如何使用OpenAPI生成器的maven插件根據YAML規範生成基於Spring的服務器存根