如何使用 Swagger codegen 开发一个简单的 REST 客户端?

How to develop a simple REST Client using Swagger codegen?

我正在学习 Swagger 以及如何使用 Swagger codegen 生成 REST 客户端。我知道如何用 Swagger 做文档,我也知道如何用 Swagger 生成一个简单的 REST 服务器,但我不知道如何用 Swagger codegen 生成一个简单的 REST 客户端。

例如,我有一个简单的应用程序,它是一个 REST 服务器,我想生成 REST 客户端。我可以用 Swagger codegen 做到这一点吗?

REST 服务器的控制器:

package com.dgs.spring.springbootswagger.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@RestController
@RequestMapping("/api/v1")
@Api(value = "Employee Management System", description = "Operations pertaining to employee in Employee Management System")
public class EmployeeController {

     @Autowired
     private EmployeeRepository employeeRepository;

        @ApiOperation(value = "View a list of available employees", response = List.class)
        @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Successfully retrieved list"),
            @ApiResponse(code = 401, message = "You are not authorized to view the resource"),
            @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
            @ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
        })
     @GetMapping("/employees")
     public List<Employee> getAllEmployees() {
         return employeeRepository.findAll();
     }

     @ApiOperation(value = "Get an employee by Id")   
     @GetMapping("/employees/{id}")
     public ResponseEntity<Employee> getEmployeeById(
             @ApiParam(value = "Employee id from which employee object will retrieve", required = true) @PathVariable(value = "id") Long employeeId)
             throws ResourceNotFoundException {

          Employee employee = employeeRepository.findById(employeeId)
            .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

          return ResponseEntity.ok().body(employee);
     }

     @ApiOperation(value = "Add an employee")
     @PostMapping("/employees")
     public Employee createEmployee(
             @ApiParam(value = "Employee object store in database table", required = true) @Valid @RequestBody Employee employee) {
         return employeeRepository.save(employee);
     }

     @ApiOperation(value = "Update an employee")
     @PutMapping("/employees/{id}")
     public ResponseEntity<Employee> updateEmployee(
             @ApiParam(value = "Employee Id to update employee object", required = true) @PathVariable(value = "id") Long employeeId,
             @ApiParam(value = "Update employee object", required = true) @Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {

          Employee employee = employeeRepository.findById(employeeId)
            .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

          employee.setEmail(employeeDetails.getEmail());
          employee.setLastName(employeeDetails.getLastName());
          employee.setFirstName(employeeDetails.getFirstName());
          final Employee updatedEmployee = employeeRepository.save(employee);

          return ResponseEntity.ok(updatedEmployee);
     }

     @ApiOperation(value = "Delete an employee")
     @DeleteMapping("/employees/{id}")
     public Map<String, Boolean> deleteEmployee(
             @ApiParam(value = "Employee Id from which employee object will delete from database table", required = true) @PathVariable(value = "id") Long employeeId)
       throws ResourceNotFoundException {

      Employee employee = employeeRepository.findById(employeeId)
        .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

      employeeRepository.delete(employee);
      Map<String, Boolean> response = new HashMap<>();
      response.put("deleted", Boolean.TRUE);

      return response;
     }
}

之后我开发了一个简单的 REST 客户端:

package com.dgs.restclient.controllers;

@Controller
public class UpdateController {

    @Autowired
    private EmployeeRestClient restClient;

    @GetMapping("/showStartUpdate")
    public String showStartCheckin() {
        return "startUpdate";
    }

    @PostMapping("/startUpdate")
    public String startCheckIn(@RequestParam("employeeId") Long employeeId, ModelMap modelMap) {

        Employee employee = restClient.findEmployee(employeeId);
        modelMap.addAttribute("employee", employee);

        return "displayEmployeeDetails";
    }

    @PostMapping("/completeUpdate")
    public String completeCheckIn(@RequestParam("employeeId") Long employeeId,
            @RequestParam("employeeFirstName") String employeeFirstName,
            @RequestParam("employeeLastName") String employeeLastName,
            @RequestParam("employeeEmail") String employeeEmail) {

        EmployeeUpdateRequest employeeUpdateRequest = new EmployeeUpdateRequest();
        employeeUpdateRequest.setId(employeeId);
        employeeUpdateRequest.setFirstName(employeeFirstName);
        employeeUpdateRequest.setLastName(employeeLastName);
        employeeUpdateRequest.setEmail(employeeEmail);
        restClient.updateEmployee(employeeUpdateRequest);

        return "updateConfirmation";
    }

}

EmployeeRestClient:

package com.dgs.restclient.integration;

@Component
public class EmployeeRestClientImpl implements EmployeeRestClient {

    private static final String EMPLOYEE_REST_URL = 
            "http://localhost:8080/api/v1/employees/";

    @Override
    public Employee findEmployee(Long id) {

        RestTemplate restTemplate = new RestTemplate();
        Employee employee = restTemplate
                .getForObject(EMPLOYEE_REST_URL + id, Employee.class);

        return employee;
    }

    @Override
    public Employee updateEmployee(EmployeeUpdateRequest request) {

        RestTemplate restTemplate = new RestTemplate();
        restTemplate
                .put(EMPLOYEE_REST_URL + request.getId(), request, Employee.class); 

        Employee employee = restTemplate
                .getForObject(EMPLOYEE_REST_URL + request.getId(), Employee.class);

        return employee;
    }

}

这个 REST Client 是我开发的,我想知道我是否可以用 Swagger codegen 做这个 REST Client 开发,如何做?我是否只需要在 pom.xml 中添加 swagger-codegen-maven-plugin?我听说过添加这个插件和一个 yml 文件,Swagger 将创建 REST 客户端。任何反馈将不胜感激!

已更新:

您的问题已在另一个 post 中得到解答。看看:

...

仅供参考,使用命令行的简单方法:

baeldung 上有一个很好的教程: how to create rest client with swagger codegen

例如 执行命令:

java -jar swagger-codegen-cli.jar generate \
  -i http://mydomain/v2/swagger.json \
  --api-package com.mypackage.api \
  --model-package com.mypackage.model \
  --invoker-package com.mypackage.invoker \
  --group-id com.mygroup \
  --artifact-id spring-swagger-codegen-api-client \
  --artifact-version 0.0.1-SNAPSHOT \
  -l java \
  --library resttemplate \
  -o spring-swagger-codegen-api-client

Swagger Codegen 支持以下客户端实现:

  1. 球衣 1 + 杰克逊
  2. 球衣 2 + 杰克逊
  3. 假装 + 杰克逊
  4. OkHttp + Gson
  5. Retrofit2/OkHttp + Gson
  6. Spring RestTemplate + 杰克逊
  7. Resteasy + 杰克逊

P.S。如您所见,其余客户端是根据 swagger 规范定义生成的,并使用“-i”参数定义。

是的。您可以使用 swagger-codegen-maven-plugin to generate a REST client. But before that , you need to describe the REST API in YAML or JSON in OpenAPI Specification 主要是因为 swagger-codegen-maven-plugin 只能从本规范中编写的文件生成 REST 客户端。

其他答案假定您需要手动编写规范,而我的解决方案更进一步,可以从 REST 控制器源代码自动生成规范。

最新的OpenAPI版本是3.0。但是根据你导入的swagger注解的包,你使用的是2.0(或之前)版本。所以我的解决方案假设您使用的是 OpenAPI 2.0.

生成打开API规范

首先,您可以使用 swagger-maven-plugin 从 RestController 源代码生成 OpenAPI 规范。它基本上分析了在 @RestController 类 中注释的 Swagger 注释,在 <locations> 中指定并将 OpenAPI 规范转储到 /src/main/resources/swagger.json :

<plugin>
    <groupId>com.github.kongchen</groupId>
    <artifactId>swagger-maven-plugin</artifactId>
    <version>3.1.5</version>
    <configuration>
        <apiSources>
            <apiSource>
                <springmvc>true</springmvc>
                <locations>
                    <location>com.dgs.spring.springbootswagger.controller.EmployeeController</location>
                    <location>com.dgs.spring.springbootswagger.controller.FooController</location>
                </locations>
                <schemes>
                    <scheme>http</scheme>
                </schemes>
                <host>127.0.0.1:8080</host>
                <basePath>/</basePath>
                <info>
                    <title>My API</title>
                    <version>1.1.1</version>
                </info>
                <swaggerDirectory>${basedir}/src/main/resources/</swaggerDirectory>
            </apiSource>
        </apiSources>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

执行以下maven命令开始生成:

mvn clean compile

正在生成 Rest 客户端

生成swagger.json后,您可以将其复制并粘贴到您的客户端项目中(例如/src/main/resources/swagger.json)。然后我们可以使用 swagger-codegen-maven-plugin 生成一个 HTTP 客户端。

默认情况下,它将生成 whole maven project,其中包括测试用例和其他文档内容。但我想要的只是 HttpClient 的源代码,没有其他东西。经过几次尝试和错误,我定下了以下配置:

<plugin>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.4.7</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${basedir}/src/main/resources/swagger.json</inputSpec>
                <language>java</language>
                <library>resttemplate</library>
                <output>${project.basedir}/target/generated-sources/</output>

                <apiPackage>com.example.demo.restclient.api</apiPackage>
                <modelPackage>com.example.demo.restclient.model</modelPackage>
                <invokerPackage>com.example.demo.restclient</invokerPackage>

                <generateApiTests>false</generateApiTests>
                <generateModelTests>false</generateModelTests>
                <generateApiDocumentation>false</generateApiDocumentation>
                <generateModelDocumentation>false</generateModelDocumentation>
                <configOptions>
                    <dateLibrary>java8</dateLibrary>
                    <sourceFolder>restclient</sourceFolder>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>

生成的HTTP客户端基于RestTemplate,会生成到文件夹target/generated-sources/restclient。您可能必须配置 IDE 以导入生成的客户端才能使用它。 (如果是Eclipse,可以在Project Properties中配置➡️ Java Build Path ➡️ 添加生成的rest client的文件夹)

要开始生成客户端,只需执行 maven 命令:

mvn clean compile

要使用生成的 HTTP 客户端:

ApiClient apiClient = new ApiClient();

//Override the default API base path configured in Maven
apiClient.setBasePath("http://api.example.com/api");

EmployeeManagementSystemApi api = new EmployeeManagementSystemApi(apiClient);
api.getEmployeeById(1l);

注:

  • 如果在使用 java8+ 生成过程中遇到 javax/xml/bind/annotation/XmlRootElement 异常,可能需要参考 .

只添加swagger插件不会生成rest client,您需要按照以下步骤操作。

以 YAML 格式写下规范。根据规范结果,将生成。将规范另存为 YAML 文件。它将被保存为 swagger.yaml 按照教程进行操作:https://howtodoinjava.com/swagger2/code-generation-for-rest-api/

1) 转到 https://editor.swagger.io 创建您的 swagger 文档,我使用 "Swagger Petstore" 作为示例

2) 现在select文件,导入文件并上传下载的swagger.json文件

3) 打开 https://swagger.io/tools/swagger-codegen/

4) 使用以下步骤:

i) 将存储库克隆到磁盘 git 克隆 https://github.com/swagger-api/swagger-codegen.git

ii) 运行 mvn clean package

iii) 将 swagger-codegen-cli.jar 文件从目标文件夹复制到计算机上的本地驱动器。

iv) 接下来执行以下命令生成客户端:

     java -jar swagger-codegen-cli.jar -i <json_file> -l python -o my_client

这个命令有三个参数:

 -i Specifies the path to the input file. This can be a URL

 -l Specifies the programming language for the client

 -o Specifies the output directory where the generate code should be located

Swagger Codegen is an open source project which allows generation of API client libraries (SDK generation), server stubs, and documentation automatically from an OpenAPI Specification. Swagger Codegen is available for download in the GitHub repository, or can be generated for any new or existing OpenAPI-defined API in the integrated SwaggerHub platform. SwaggerHub brings the Swagger Editor, UI, and Codegen tools to the cloud in an integrated API design and documentation, built for API teams working with the Swagger (OpenAPI) specification.

有用于构建工具的插件,例如 Maven 和 Gradle,因为已经给出了一些答案所以这里不添加

Swagger 端点

假设您的应用程序的 Swagger 端点可以在以下位置访问:

  1. 测试 Swagger 2.0 JSON API 文档

    http://localhost:8080/v2/api-docs?group=employee

    http://localhost:8080/v2/api-docs(如果您还没有设置名为employee的组)

  2. 测试 Swagger UI

    http://localhost:8080/swagger-ui.html

下载 Swagger Codegen 可执行文件

您可以从 Maven 中央存储库下载 swagger-codegen-cli-2.4.7.jar

正在生成客户端代码

现在您已经有了 Swagger Codegen JAR,您可以通过执行以下命令生成 REST 客户端:

java -jar swagger-codegen-cli-2.4.7.jar generate \
  -i http://localhost:8080/v2/api-docs?group=employee \
  -l java \
  -o swagger-codegen-client

如果没有swagger分组,

java -jar swagger-codegen-cli-2.4.7.jar generate \
  -i http://localhost:8080/v2/api-docs \
  -l java \
  -o swagger-codegen-client

选项

尽管 Swagger Codegen CLI 带有许多选项,但我们使用的选项对于 生成客户端代码。

  • -i URL 指向您应用程序的 Swagger api docs.
  • -l 客户端的编程语言,在本例中为 java
  • -o 生成的客户端代码的输出文件夹。

执行前面生成代码的命令后,您应该注意终端上的以下消息:

[main] INFO io.swagger.parser.Swagger20Parser - reading from http://localhost:8080/v2/api-docs?group=employee
[main] WARN io.swagger.codegen.ignore.CodegenIgnoreProcessor - Output directory does not exist, or is inaccessible. No file (.swagger-codegen-ignore) will be evaluated.
[main] INFO io.swagger.codegen.AbstractGenerator - writing file swagger-codegen-client/src/main/java/io/swagger/client/model/Employee.java
[main] INFO io.swagger.codegen.AbstractGenerator - writing file swagger-codegen-client/docs/Employee.md
[main] INFO io.swagger.codegen.AbstractGenerator - writing file swagger-codegen-client/src/main/java/io/swagger/client/api/EmployeeControllerApi.java
...
[main] INFO io.swagger.codegen.AbstractGenerator - writing file swagger-codegen-client/src/main/java/io/swagger/client/ApiClient.java
...

REST 客户端项目

代码生成完成后,您应该会注意到一个具有以下结构的 gradle/maven 项目:

__ swagger-codegen-client
  |__ README.md
  |__ build.gradle
  |__ build.sbt
  |__ docs
  |__ git_push.sh
  |__ gradle
  |__ gradle.properties
  |__ gradlew
  |__ gradlew.bat
  |__ pom.xml
  |__ settings.gradle
  |__ src
     |__ main
        |__ java
          |__ io.swagger.client.api
             |__ EmployeeControllerApi.java
     |__ test
        |__ java
          |__ io.swagger.client.api
             |__ EmployeeControllerApiTest.java

可以找到生成的客户端项目的示例 here

使用 REST 客户端

客户端项目包含很多 java classes。然而最重要的 class 是 EmployeeControllerApi.java。 这是 class,其中包含制作 REST 客户端的所有逻辑 classes.

另一个重要的class是EmployeeControllerApiTest.java。它向您展示了如何使用 EmployeeControllerApi.java。生成的客户端项目还提供了一个非常有用的 README 文件。

URL 变化

ApiClient class 包含与建立 HTTP 客户端连接相关的信息。请确保 basePath 您的 REST 应用程序是正确的。在生成的示例中,basePath 有一个 https://localhost:8080 URL 而不是 http://localhost:8080.

Java 12 个变化

生成的项目与 Java 8 配合良好。如果您使用的是 Java 12,则必须添加以下依赖项才能使项目编译:

    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-core</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>

    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>javax.annotation-api</artifactId>
        <version>1.3.2</version>
    </dependency>

示例 REST 调用

下面是一个通过调用 REST POST 方法来创建 employee 的示例。

Employee employee = new Employee();
employee.setId(3L);
employee.setFirstName("Sam");
employee.setLastName("Fox");
employee.setEmail("sfox@gmail.com");

EmployeeControllerApi api = new EmployeeControllerApi();
Employee response = api.createEmployeeUsingPOST(employee);
System.out.println(response);

您应该得到类似这样的回复:

class Employee {
    email: sfox@gmail.com
    firstName: Sam
    id: 3
    lastName: Fox
}

您可以找到完整的示例 here

我为此苦苦挣扎,最终制作了自己的工具。真的很小只依赖于spring-web。我什至filed a PR看看它是否可以成为Spring的一部分。

我称它为 Spring RestTemplate Client and it does what Feign,其他工具也这样称呼它,但更轻巧,仅支持 Spring。

final MyApiInterface myClient = SpringRestTemplateClientBuilder
  .create(MyApiInterface.class)
  .setUrl(this.getMockUrl())
  .setRestTemplate(restTemplate)         // Optional
  .setHeader("header-name", "the value") // Optional
  .setHeaders(HttpHeaders)               // Optional
  .build();

myClient 的任何调用都将使用 MyApiInterface:

的注释转换为 HTTP 调用
final ResponseEntity<MyDTO> response = myClient.getMyDto();