OpenAPI 및 SpringBoot로 REST API 작성
38114 단어 springbootopenapipracticalspringboot
OpenAPI 사양
API는 애플리케이션과 애플리케이션 소비자 간의 계약입니다. 이러한 소비자는 기계일 수도 있고 사람일 수도 있습니다. OpenAPI는 사람과 기계가 읽을 수 있는 형식으로 API 계약을 작성하기 위한 사양입니다. API를 설명할 수 있는 방법을 표준화합니다. 전체 사양은 여기
https://spec.openapis.org/oas/v3.1.0
에서 찾을 수 있습니다.첫 번째 API 사양
inventory-service
라고 부르는 새 서비스를 만들어 보겠습니다. 이제 우리는 새로운 스프링 부트 애플리케이션을 생성하는 방법을 알고 있습니다. src/resources/spec/inventory-api.yml
에 yml openAPI 사양 파일을 추가합니다. 최소 API는 다음과 같습니다.openapi: "3.0.3"
info:
title: inventory-api
version: 1.0.0
paths:
/products:
get:
description: Get All Products
operationId: getAllProducts
responses:
'200':
description: All products are returned
content:
application/json:
schema:
$ref: '#/components/schemas/ListOfProducts'
'404':
description: No Product returned
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
description: Add A Product to inventory
operationId: addProduct
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
responses:
'201':
description: Product added successfully
headers:
location:
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/products/{id}:
get:
description: Get A Product By ID
operationId: getProductById
parameters:
- in: path
name: id
schema:
type: string
format: uuid
required: true
responses:
'200':
description: Get a product by id
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'404':
description: No Product returned
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
description: Update A Product
operationId: updateProduct
parameters:
- in: path
name: id
schema:
type: string
format: uuid
required: true
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
responses:
'200':
description: Created product is returned
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Product Does not Exist
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
ListOfProducts:
type: array
items:
$ref: '#/components/schemas/Product'
Product:
type: object
properties:
id:
type: string
format: UUID
Error:
type: object
properties:
message:
type: string
아주 최소한의 API입니다.
paths
섹션에서 API에 대한 설명을 볼 수 있습니다. 각 API 끝점에는 선택적 요청 본문과 응답 본문이 있습니다. 또한 일부 사용자 정의 헤더가 필요한지 여부, 경로 매개변수, 쿼리 매개변수 등을 정의할 수 있습니다.components
섹션에서 모델을 정의하고 API에서 참조합니다.OpenAPI 사양에 대해 더 깊이 들어가지는 않겠지만 사양이 매우 방대하기 때문에 특정 사용 사례에 대한 사양을 항상 참조할 수 있습니다.
Spring용 REST API 생성
이제 OpenAPI 사양이 있으므로 사양에서 코드를 생성하는 데 사용할 수 있는 플러그인과 도구가 있습니다.
openapi-generator
https://openapi-generator.tech/docs/installation을 사용하여 REST API를 생성할 수 있습니다. cli를 사용하여 REST API를 생성할 수 있습니다.소스를 생성하는 데 사용할 maven 플러그인https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin도 있습니다.
maven 플러그인은 openapi-generator를 사용하여 소스 코드를 생성합니다.
maven-plugin을 사용하기 위해 다음과 같이 빌드 섹션에 추가합니다.
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>5.4.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/spec/inventory-api.yml</inputSpec>
<generatorName>spring</generatorName>
<generateSupportingFiles>false</generateSupportingFiles>
<configOptions>
<basePackage>com.sab.inventory</basePackage>
<sourceFolder>src/java/main</sourceFolder>
<interfaceOnly>true</interfaceOnly>
<modelPackage>com.sab.inventory.dto</modelPackage>
<apiPackage>com.sab.inventory.api</apiPackage>
<skipDefaultInterface>true</skipDefaultInterface>
<openApiNullable>false</openApiNullable>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
플러그인과 실제 openapi-generator 모두 https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin 및 https://openapi-generator.tech/docs/generators/spring 에서 확인할 수 있는 많은 구성 옵션이 있습니다.
위의 예에서는 최소 구성을 사용했습니다. 아래에서 설명하겠습니다.
* `inputSpec` - This is the path to the OpenAPI spec file.
* `generatorName` - ooenapi-generator can produce source code multiple language and framework. Because we want to generate for Spring I chose spring as the generator name.
* `generateSupportingFiles` - When I generated first I saw some unecessary supporting files were generated as I do not need those I turned it to false.
* `configOptions` - Properties that maps directly to the generator options.
** `basePackage` - package name for your generated sources
** `sourceFolder` - folder where your generated sources will be placed
** `interfaceOnly` - We can either generate only REST API interface or we can generate some default code. I make it true as I want to generate only REST API interface.
** `modelPackage` - package name for your generated model/dto classes.
** `apiPackage` - package name for your generated API classes.
** `skipDefaultInterface` - We can skip the genration of default methods in the interface.
** `openApiNullable` - With the value true it will generate an import of `org.openapitools.jackson.nullable.JsonNullable` however I didn't need it so I make it false.
그렇다면 위 코드의 출력은 무엇일까요? 다음은 REST API 스텁의 모습입니다.
/**
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (5.4.0).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package com.sab.inventory.api;
import com.sab.inventory.dto.Error;
import com.sab.inventory.dto.Product;
import java.util.UUID;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
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.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Generated;
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2022-04-23T22:00:49.464591+02:00[Europe/Berlin]")
@Validated
@Tag(name = "products", description = "the products API")
public interface ProductsApi {
/**
* POST /products
* Add A Product to inventory
*
* @param product (optional)
* @return All products are returned (status code 201)
* or No Product returned (status code 400)
*/
@Operation(
operationId = "addProduct",
responses = {
@ApiResponse(responseCode = "201", description = "All products are returned", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Product.class))),
@ApiResponse(responseCode = "400", description = "No Product returned", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class)))
}
)
@RequestMapping(
method = RequestMethod.POST,
value = "/products",
produces = { "application/json" },
consumes = { "application/json" }
)
ResponseEntity<Product> addProduct(
@Parameter(name = "Product", description = "", schema = @Schema(description = "")) @Valid @RequestBody(required = false) Product product
);
/**
* GET /products
* Get All Products
*
* @return All products are returned (status code 200)
* or No Product returned (status code 404)
*/
@Operation(
operationId = "getAllProducts",
responses = {
@ApiResponse(responseCode = "200", description = "All products are returned", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Product.class))),
@ApiResponse(responseCode = "404", description = "No Product returned", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class)))
}
)
@RequestMapping(
method = RequestMethod.GET,
value = "/products",
produces = { "application/json" }
)
ResponseEntity<List<Product>> getAllProducts(
);
/**
* GET /products/{id}
* Get A Product By ID
*
* @param id (required)
* @return All products are returned (status code 200)
* or No Product returned (status code 404)
*/
@Operation(
operationId = "getProductById",
responses = {
@ApiResponse(responseCode = "200", description = "All products are returned", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Product.class))),
@ApiResponse(responseCode = "404", description = "No Product returned", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class)))
}
)
@RequestMapping(
method = RequestMethod.GET,
value = "/products/{id}",
produces = { "application/json" }
)
ResponseEntity<Product> getProductById(
@Parameter(name = "id", description = "", required = true, schema = @Schema(description = "")) @PathVariable("id") UUID id
);
/**
* PUT /products/{id}
* Update A Product
*
* @param id (required)
* @param product (optional)
* @return Created product is returned (status code 200)
* or Error (status code 400)
* or Product Does not Exist (status code 404)
*/
@Operation(
operationId = "updateProduct",
responses = {
@ApiResponse(responseCode = "200", description = "Created product is returned", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Product.class))),
@ApiResponse(responseCode = "400", description = "Error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class))),
@ApiResponse(responseCode = "404", description = "Product Does not Exist", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Error.class)))
}
)
@RequestMapping(
method = RequestMethod.PUT,
value = "/products/{id}",
produces = { "application/json" },
consumes = { "application/json" }
)
ResponseEntity<Product> updateProduct(
@Parameter(name = "id", description = "", required = true, schema = @Schema(description = "")) @PathVariable("id") UUID id,
@Parameter(name = "Product", description = "", schema = @Schema(description = "")) @Valid @RequestBody(required = false) Product product
);
}
이제 API 인터페이스가 있으므로 컨트롤러를 만들고 메서드를 구현할 수 있습니다.
이번 포스팅은 여기까지 하고, 실제로 테스트를 통해 API를 구현할 예정이니 다음 포스팅을 기대해주세요.
Reference
이 문제에 관하여(OpenAPI 및 SpringBoot로 REST API 작성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/sabyasachi/writing-rest-api-with-openapi-and-springboot-34p6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)