如何使用Swagger代码生成器开发一个简单的REST客户端?

20

我正在学习Swagger,以及如何使用Swagger代码生成器生成REST客户端。我知道如何使用Swagger进行文档编写,也知道如何使用Swagger生成简单的REST服务器,但是我不知道如何使用Swagger代码生成器生成简单的REST客户端。

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

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客户端是由我开发的,我想知道是否可以使用Swagger codegen来进行REST客户端开发,如果可以,我需要怎么做呢?我只需要在pom.xml中添加swagger-codegen-maven-plugin吗?我听说只需要添加该插件和一个yml文件,Swagger就会创建REST客户端。非常感谢您的任何反馈!


是的。只需添加Swagger文件并在pom.xml中配置插件,即可在Maven构建命令期间自动生成Rest Client类并将其放置在目标文件夹classes中。您能否在此处添加Swagger文件,以便我可以向您展示一个工作演示?!! - Imran
我认为Elvis想要做的是直接从源代码生成REST客户端,而不需要手动编写Swagger文件。 - Ken Chan
6个回答

27
是的。你可以使用swagger-codegen-maven-plugin生成一个REST客户端。但在此之前,你需要使用YAML或JSON描述REST API在OpenAPI Specification中,主要是因为swagger-codegen-maven-plugin只能从符合此规范的文件生成REST客户端。
其他答案假设你需要手动编写规范,而我的解决方案更进一步,可以从REST控制器源代码自动生成规范。 最新的OpenAPI版本是3.0。但根据导入的swagger注释包,你正在使用2.0版本(或之前)。因此,我的解决方案假定你正在使用OpenAPI 2.0。 生成Open 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客户端。

默认情况下,它会生成整个maven项目,其中包括测试用例和其他文档内容。但我只需要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的情况下,您可以在项目属性中进行配置➡️ Java Build Path ➡️ 添加生成的REST客户端文件夹) 要开始生成客户端,只需执行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异常,您可能需要参考此处

谢谢你的解释,Ken。我想问你一些问题,如果我想从这个Spring Boot应用程序创建一个JAR,并在另一个应用程序中使用它作为依赖项,我该怎么做?我知道Spring Boot Fat JAR与传统JAR不同,它不包含来自src/main/java的类,但我已经在pom.xml中添加了spring-boot-maven-plugin,它创建了2个JAR文件,一个是Fat JAR,另一个JAR包含来自src/main/java的类,但它仍然不包含来自target/generated-sources的类。你知道我该如何创建这种类型的JAR吗? - elvis
嗨@elvis,参考该JAR依赖项的pom.xml,您可以找到其<groupId><artifactId><version>。然后在想要使用此JAR依赖项的项目中,只需修改其pom.xml以在<dependency>部分包含JAR依赖项即可。您必须先转到依赖项项目,通过执行类似于mvn clean package install的命令来构建和安装依赖项JAR到本地maven存储库。然后包含依赖项的项目应该能够从您的本地maven存储库获取JAR。 - Ken Chan
可以使用相同的配置来处理使用 build.gradle 而不是 pom.xml 的项目吗? - Shrikant Havale
swagger.json 中有一些响应类未被包括,同时它生成了一些在 apidoc 定义标签内不可用的类。 - Singh

9

更新:

您的问题已在另一篇文章中得到解答。请查看:相关文章

...

提醒一个使用命令行的简单方法:

Baeldung的教程介绍了一个很好的方法: 如何使用Swagger Codegen创建REST客户端

例如,执行命令:

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. jersey1 + Jackson
  2. Jersey2 + Jackson
  3. Feign + Jackson
  4. OkHttp + Gson
  5. Retrofit2/OkHttp + Gson
  6. Spring RestTemplate + Jackson
  7. Resteasy + Jackson

P.S. 如您所见,REST客户端是从Swagger规范定义中生成的,并且使用"-i"参数定义。


--library resttemplate 在 swagger-codegen 3 中不可用。我找不到替代方案。 - Christian Vincenzo Traina
RestTemplate仍然存在于swagger-codegen-cli 3中。您可以尝试以下示例: java -jar swagger-codegen-cli-3.0.41.jar generate -i https://petstore.swagger.io/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 - Ariel Carrera

3

Swagger Endpoints

假设你的应用程序的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 Central Repository下载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:指向你应用的Swagger api文档的URL。
  • -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

可以在此处找到已生成客户端项目的示例

使用REST Client

客户端项目包含许多Java类。但是,最重要的类是EmployeeControllerApi.java。这是一个包含为制作REST客户端类的所有逻辑的类。

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

URL更改

ApiClient 类包含与建立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 = 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
}

您可以在这里找到一个完整的示例。


1

1)访问https://editor.swagger.io,创建Swagger文档,此处以“Swagger Petstore”为例。

2)选择“文件”,导入下载的swagger.json文件。

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

4)按以下步骤操作:

i)将存储库克隆到磁盘git clone 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是一个开源项目,允许从OpenAPI规范自动生成API客户端库(SDK生成)、服务器存根和文档。Swagger Codegen可在GitHub存储库中下载,也可以在集成的SwaggerHub平台上为任何新的或现有的OpenAPI定义的API生成。SwaggerHub将Swagger编辑器、UI和Codegen工具集成到云中,用于与Swagger(OpenAPI)规范一起工作的API团队的设计和文档。对于构建工具,如Maven和Gradle,已经有插件,因此不在此处添加。

0

我曾经为此苦苦挣扎,最终自己开发了一个工具。它非常小巧,仅依赖于spring-web。我甚至提交了PR,希望它能成为Spring的一部分。

我称之为Spring RestTemplate Client,它可以做到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();

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接