為了讓其他開發人員能夠串接我們後端程式的 API,我們需要提供說明文件,而這個很繁瑣的文件撰寫流程可以透過一些工具解決,例如本次要介紹的 springdoc 套件,能夠依據專案程式自動產生 OpenAPI 文件。
註: springdoc 是基於 OpenAPI 3.0 (Swagger 3), 如果需要產生 Swagger 2 可以使用 SpringFox
延伸閱讀:OpenAPI 和 Swagger 是什麼?他們是什麼關係?Swagger 規範和工具不同嗎?
預設查看定義文件(JSON):
預設查看定義文件(yaml):
Swagger UI:
如果覺得每次都要輸入這麼長的網址才能開啟 Swagger UI 頁面,可以在設定檔中設定路徑別名
依照下面的設定,以後在網址中輸入 http://localhost:8080/su 時就會被自動跳轉到 Swagger UI 頁面
註: 文末附有完整程式碼
首先我們先來調整 Swagger UI 最上面的說明文字和版本號碼:
在同一個 Controller 類別中的 API 會被放在一個標籤下面,修改標籤的方式如下:
指定 API 的摘要和說明
指定 API 的回應資訊:
這裡指定了兩種回應情況:
1: 狀態代號 200,回傳 MemberDto 物件清單
2: 狀態代號 200,沒有回傳值
指定 API 參數:
這裡指示範了三種參數:
1: 字串,在 Swagger UI 上預設值為 "00"
2: 清單,在 Swagger UI 上預設值為 "01",可填入多個
3: 列舉,在 Swagger UI 上預設值為 "ALL",會有下拉式選單方便測試
如果參數是類別物件,則可以在類別中的變數上增加 @Schema 註解(Annotation)
參考資料:
springdoc 官方文件
springdoc GitHub
OpenAPI Specification
註: springdoc 是基於 OpenAPI 3.0 (Swagger 3), 如果需要產生 Swagger 2 可以使用 SpringFox
延伸閱讀:OpenAPI 和 Swagger 是什麼?他們是什麼關係?Swagger 規範和工具不同嗎?
引用依賴
如果是使用 Maven 的話先在 pom.xml 引用依賴:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.8</version>
</dependency>
如果不是 Maven 的可以查看mvnrepository
查看 API 文件
只要引用依賴之後就已經自動產生完畢了,執行後可以使用下列網址查看自動產生的文件預設查看定義文件(JSON):
http://localhost:8080/v3/api-docs
預設查看定義文件(yaml):
http://localhost:8080/v3/api-docs.yaml
Swagger UI:
http://localhost:8080/swagger-ui/index.html
如果覺得每次都要輸入這麼長的網址才能開啟 Swagger UI 頁面,可以在設定檔中設定路徑別名
依照下面的設定,以後在網址中輸入 http://localhost:8080/su 時就會被自動跳轉到 Swagger UI 頁面
springdoc.swagger-ui.path=/su
增加自訂說明文字
雖然目前已經能夠產生文件了,但是完全沒有註解,還是不太容易理解,下面使用幾個 API 來示範加上自訂說明註: 文末附有完整程式碼
首先我們先來調整 Swagger UI 最上面的說明文字和版本號碼:
@OpenAPIDefinition(info = @Info(title = "Ruyut Example", version = "1.0.0"))
在同一個 Controller 類別中的 API 會被放在一個標籤下面,修改標籤的方式如下:
@Tag(name = "會員")
指定 API 的摘要和說明
@Operation(summary = "取得所有會員", description = "取得所有會員資料,每次上限 1000 筆")
指定 API 的回應資訊:
這裡指定了兩種回應情況:
1: 狀態代號 200,回傳 MemberDto 物件清單
2: 狀態代號 200,沒有回傳值
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Success",
content = {
@Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = MemberDto.class))
)
}),
@ApiResponse(responseCode = "401", description = "參數錯誤或沒有權限", content = {
@Content()
})
})
指定 API 參數:
這裡指示範了三種參數:
1: 字串,在 Swagger UI 上預設值為 "00"
2: 清單,在 Swagger UI 上預設值為 "01",可填入多個
3: 列舉,在 Swagger UI 上預設值為 "ALL",會有下拉式選單方便測試
@Parameter(description = "排序代號", example = "00") @RequestParam(defaultValue = "-1") String sortCode,
@Parameter(description = "會員類別", example = "[\"01\"]") @RequestParam(defaultValue = "") List<String> type,
@Parameter(description = "會員等級", example = "ALL") @RequestParam(defaultValue = "ALL") MemberType sittingType
如果參數是類別物件,則可以在類別中的變數上增加 @Schema 註解(Annotation)
public class MemberDto {
@Schema(description = "會員代號")
private String id;
@Schema(description = "會員名稱")
private String name;
}
隱藏 API 文件
要停用 api-docs 和 swagger-ui 文件只要在設定檔內增加下面這兩項設定即可:
springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false
參考資料:
springdoc 官方文件
springdoc GitHub
OpenAPI Specification
完整範例程式碼:
package app.ruyut.ruyutexample.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Getter;
import lombok.Setter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Tag(name = "會員")
@RestController
public class MemberController {
@Operation(summary = "取得所有會員", description = "取得所有會員資料,每次上限 1000 筆")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Success",
content = {
@Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = MemberDto.class))
)
}),
@ApiResponse(responseCode = "401", description = "參數錯誤或沒有權限", content = {
@Content()
})
})
@GetMapping("/member")
public ResponseEntity<List<Map<String, Object>>> member(
@Parameter(description = "排序代號", example = "00") @RequestParam(defaultValue = "-1") String sortCode,
@Parameter(description = "會員類別", example = "[\"01\"]") @RequestParam(defaultValue = "") List<String> type,
@Parameter(description = "會員等級", example = "ALL") @RequestParam(defaultValue = "ALL") MemberType sittingType
) {
List<Map<String, Object>> list = new ArrayList<>();
return new ResponseEntity<>(list, HttpStatus.OK);
}
public enum MemberType {
ALL,
BASE,
ADVANCED
}
@Getter
@Setter
public class MemberDto {
@Schema(description = "會員代號")
private String id;
@Schema(description = "會員名稱")
private String name;
}
@Operation(summary = "取得指定會員資料")
@ApiResponse(responseCode = "404", description = "沒有找到")
@GetMapping("/member/{id}")
public ResponseEntity<List<Map<String, Object>>> member(
@Parameter(description = "會員代號", example = "123456") @PathVariable() String id
) {
List<Map<String, Object>> list = new ArrayList<>();
return new ResponseEntity<>(list, HttpStatus.OK);
}
@Operation(summary = "更新", description = "更新會員資料")
@PostMapping("/member")
public ResponseEntity<String> memberPost(
@Parameter(description = "排序代號", example = "00") @RequestBody MemberDto member
) {
return new ResponseEntity<>("Success", HttpStatus.OK);
}
}
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com