openapi: 3.0.3
info:
title: Sample Ecommerce App
description: >
'This is a ***sample ecommerce app API***. You can find out more about Swagger at [swagger.io](http://swagger.io).
Description supports markdown markup. For example, you can use the `inline code` using back ticks.'
termsOfService: https://github.com/PacktPublishing/Modern-API-Development-with-Spring-6-and-Spring-Boot-3/blob/main/LICENSE
contact:
name: Packt Support
url: https://www.packt.com
email: support@packtpub.com
license:
name: MIT
url: https://github.com/PacktPublishing/Modern-API-Development-with-Spring-6-and-Spring-Boot-3/blob/main/LICENSE
version: 1.0.0
externalDocs:
description: Any document link you want to generate along with API.
url: http://swagger.io
servers:
- url: https://ecommerce.swagger.io/v2
tags:
- name: cart
description: Everything about cart
externalDocs:
description: Find out more (extra document link)
url: http://swagger.io
- name: order
description: Operation about orders
- name: user
description: Operations about users
- name: customer
description: Operations about user's persona customer
- name: address
description: Operations about user's address
- name: payment
description: Operations about payments
- name: shipping
description: Operations about shippings
- name: product
description: Operations about products
- name: card
description: card operation
components:
schemas:
Cart:
description: Shopping Cart of the user
type: object
properties:
customerId:
description: Id of the customer who possesses the cart
type: string
items:
description: Collection of items in cart.
type: array
items:
$ref: '#/components/schemas/Item'
<필드명>:
type: number
format: date-time
기본 데이터 타입 | 상세 데이터 타입 | 설명 |
number | float | float 타입 실수 |
number | double | double 타입 실수 |
integer | int32 | int 타입 정수 |
integer | int64 | long 타입 정수 |
string | date | yyyy-MM-dd 형식의 날짜 |
string | date-time | yyyy-MM-ddThh:mm:ss 형식의 날짜 |
string | byte | Base62로 인코딩한 값 |
string | binary | 이진 데이터, 파일에 사용 |
paths:
/api/v1/carts/{customerId}:
get:
tags:
- cart
summary: Returns the shopping cart
description: Returns the shopping cart of given customer
operationId: getCartByCustomerId
parameters:
- name: customerId
in: path
description: Customer Identifier
required: true
schema:
type: string
responses:
200:
description: successful operation
content:
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Cart'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Cart'
404:
description: Given customer ID doesn't exist
content: {}
tags | API를 그룹화할 때 사용 |
summary | 요약 |
description | 설명. 마크다운 사용 가능 |
operationId | 오퍼레이션 명. Swagger Codegen에서 사용한 API 인ㅇ터페이스의 메소드 명으로 사용됨 |
parameters | 파라미터에 대한 정보 명시 |
responses | API가 요청에 대해 응답할 수 있는 응답 타입 정의 |
requestBody | 요청 페이로드 객체 정의 |
swaggerCodegen 'org.openapitools:openapi-generator-cli:6.2.1'
compileOnly 'io.swagger:swagger-annotations:1.6.4'
compileOnly 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.openapitools:jackson-databind-nullable:0.2.3'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml'
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
// required for schema in swagger generated code
implementation 'io.springfox:springfox-oas:3.0.0'
plugins {
...
id 'org.hidetake.swagger.generator' version '2.19.2'
}
{
"library": "spring-boot",
"dateLibrary": "java8",
"hideGenerationTimestamp": true,
"modelPackage": "com.packt.modern.api.model",
"apiPackage": "com.packt.modern.api",
"invokerPackage": "com.packt.modern.api",
"serializableModel": true,
"useTags": true,
"useGzipFeature" : true,
"hateoas": true,
"unhandledException": true,
"useSpringBoot3": true,
"useSwaggerUI": true,
"importMappings": {
"ResourceSupport":"org.springframework.hateoas.RepresentationModel",
"Link": "org.springframework.hateoas.Link"
}
}
**/*Controller.java
swaggerSources {
def typeMappings = 'URI=URI'
def importMappings = 'URI=java.net.URI'
eStore {
def apiYaml = "${rootDir}/src/main/resources/api/openapi.yaml"
def configJson = "${rootDir}/src/main/resources/api/config.json"
inputFile = file(apiYaml)
def ignoreFile = file("${rootDir}/src/main/resources/api/.openapi-generator-ignore")
code {
language = 'spring'
configFile = file(configJson)
rawOptions = ['--ignore-file-override', ignoreFile, '--type-mappings',
typeMappings, '--import-mappings', importMappings] as List<String>
components = [models: true, apis: true, supportingFiles: 'ApiUtil.java']
dependsOn validation
}
}
}
compileJava.dependsOn swaggerSources.eStore.code
processResources {
dependsOn(generateSwaggerCode)
}
sourceSets.main.java.srcDir "${swaggerSources.eStore.code.outputDir}/src/main/java"
sourceSets.main.resources.srcDir "${swaggerSources.eStore.code.outputDir}/src/main/resources"
@Getter
@Setter
public class Error {
private String errorCode;
private String message;
private Integer status;
private String url = "Not available";
private String reqMethod = "Not available";
}
@Getter
@AllArgsConstructor
public enum ErrorCode {
GENERIC_ERROR("PACKT-0001", "The system is unable to complete the request. Contact system support."),
HTTP_MEDIATYPE_NOT_SUPPORTED("PACKT-0002", "Requested media type is not supported. Please use application/json or application/xml as 'Content-Type' header value"),
private String errCode;
private String errMsgKey;
}
@NoArgsConstructor
public class ErrorUtils {
public static Error createError(final String errMsgKey, final String errorCode,
final Integer httpStatusCode) {
Error error = new Error();
error.setMessage(errMsgKey);
error.setErrorCode(errorCode);
error.setStatus(httpStatusCode);
return error;
}
}
@RequiredArgsConstructor
@ControllerAdvice
public class RestApiErrorHandler {
private final MessageSource messageSource;
@ExceptionHandler(Exception.class)
public ResponseEntity<Error> handleException(HttpServletRequest request, Exception ex,
Locale locale) {
ex.printStackTrace(); // TODO: Should be kept only for development
Error error = ErrorUtils
.createError(ErrorCode.GENERIC_ERROR.getErrMsgKey(), ErrorCode.GENERIC_ERROR.getErrCode(),
HttpStatus.INTERNAL_SERVER_ERROR.value()).setUrl(request.getRequestURL().toString())
.setReqMethod(request.getMethod());
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public ResponseEntity<Error> handleHttpMediaTypeNotSupportedException(HttpServletRequest request,
HttpMediaTypeNotSupportedException ex,
Locale locale) {
ex.printStackTrace(); // TODO: Should be kept only for development
Error error = ErrorUtils
.createError(ErrorCode.HTTP_MEDIATYPE_NOT_SUPPORTED.getErrMsgKey(),
ErrorCode.HTTP_MEDIATYPE_NOT_SUPPORTED.getErrCode(),
HttpStatus.UNSUPPORTED_MEDIA_TYPE.value()).setUrl(request.getRequestURL().toString())
.setReqMethod(request.getMethod());
log.info("HttpMediaTypeNotSupportedException :: request.getMethod(): " + request.getMethod());
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
curl --request GET 'http://localhost:8080/api/v1/carts/1' \
--header 'Content-Type: application/json'\
--header 'Accept: application/json'\
--data-raw '{"id":"1", "quantity":1, "unitPrice":2.5}'
소라브 샤르마, 『스프링 6와 스프링 부트 3로 배우는 모던 API 개발』 5장 (0) | 2025.02.03 |
---|---|
소라브 샤르마, 『스프링 6와 스프링 부트 3로 배우는 모던 API 개발』 4장 (0) | 2025.01.21 |
소라브 샤르마, 『스프링 6와 스프링 부트 3로 배우는 모던 API 개발』 2장 (3) | 2025.01.09 |
소라브 샤르마, 『스프링 6와 스프링 부트 3로 배우는 모던 API 개발』 1장 (0) | 2024.12.24 |
[필독! 개발자 온보딩 가이드] 시맨틱 버저닝 (0) | 2024.02.01 |