Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
0
1
2
3
4
5
6
7
8
9
10
2017년1월
2017년2월
2017년3월
2017년4월
2017년5월
2017년6월
2017년7월
2017년8월
2017년9월
2017년10월
2017년11월
2017년12월
2018년1월
2018년2월
2018년3월
2018년4월
2018년5월
2018년6월
2018년7월
2018년8월
2018년9월
2018년10월
2018년11월
2018년12월
2019년1월
2019년2월
2019년3월
2019년4월
2019년5월
2019년6월
2019년7월
푸시 이메일 문자 카카오톡
0
1
2
3
4
5
6
7
푸시 이메일 문자 카카오톡 비즈
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
//	v1.0	Message
{
"id": "3bnKmSrLEdrckTlA",
"to": "jinho.shin",
"title": "제목",
"body": "내용",
"messageType": "AD",
"status": "FAILED",
"createdDateTime": "2019-11-10T14:48:42.846+09:00"
}
//	v1.1	Message
{
"id": "V9MdIGgVEMCIcs5g",
"to": "jinho.shin",
"title": "제목",
"body": "내용",
"messageType": "AD",
"status": "FAILED",
"statusMessage": "'jinho.shin'	is	not	registered",
"createdDateTime": "2019-11-10T14:51:04.262+09:00",
"updatedDateTime": "2019-11-10T14:51:04.262+09:00"
}
return	V1_0Message
.builder()
.id(messageEntity.getId())
.title(messageEntity.getTitle())
.body(messageEntity.getBody())
.messageType(messageEntity.getMessageType())
.status(messageEntity.getStatus())
.createdDateTime(messageEntity.getCreatedDateTime())
.build();
return	V2_0Message
.builder()
.id(messageEntity.getId())
.title(messageEntity.getTitle())
.body(messageEntity.getBody())
.messageType(messageEntity.getMessageType())
.status(messageEntity.getStatus())
.statusMessage(messageEntity.getStatusMessage())
.createdDateTime(messageEntity.getCreatedDateTime())
.updatedDateTime(messageEntity.getUpdatedDateTime())
.build();
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
2927
2846
88
11
0.23
처리량
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
@Mapper
public	interface MessageMapper {
MessageEntity toMessageEntity(V1_0SendMessage	v1_0SendMessage);
}
…
@Override
public MessageEntity toMessageEntity(V1_0SendMessage	v1_0SendMessage)	{
if (	v1_0SendMessage	== null	)	{
return	null;
}
MessageEntity messageEntity =	new MessageEntity();
messageEntity.setTo(	v1_0SendMessage.getTo()	);
…
return messageEntity;
}
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
@Mapper(componentModel =	"spring")	
public	interface MessageMapper {
…
@Mapping(source	= "id", target	= "message.id")
V1_0SendMessageResponse	toV1_0SendMessageResponse(MessageEntity messageEntity);
default V1_0GetMessageResponse	toV1_0GetMessageResponse(MessageEntity messageEntity)	{
…
}
}
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
$	curl	-i -X	POST 
-H	'X-Secret-Key:vOwlgJY4'	
-H	'Content-Type:application/json'	
-d	'{"to":"jinho.shin","title":"힌트는","body":"오타","messageType":"NOTIFIACITON	"}'	
'http://127.0.0.1/v1.0/messages'
{
"header": {
"isSuccessful": false,
"resultCode": -400,
"resultMessage": "Client	Error.	property	is	invalid."
}
}
$	curl	-i -X	POST 
-H	'X-Secret-Key:vOwlgJY4'	
-H	'Content-Type:application/json'	
-d	'{"to":"jinho.shin","title":"힌트는","body":"오타","messageType":"NOTIFIACITON	"}'	
'http://127.0.0.1/v1.0/messages’
{
"header": {
"isSuccessful": false,
"resultCode": -400,
"resultMessage": "messageType['NOTIFIACITON']	- must	match	"AD|NOTIFICATION""
}
}
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
public	boolean sendMessageV1_0(V1_0SendMessage	sendMessage)	{
if (StringUtils.isBlank(sendMessage.getTo()))	{
throw	new	IllegalArgumentException("to	is	blank");
}
if (!EmojiParser .parseToAliases(sendMessage.getTo()).equals(sendMessage.getTo()))	{
throw	new	IllegalArgumentException("to	contains	emoji");
}
if (!"NOTIFICATION".equals(sendMessage.getMessageType())	&&
!"AD".equals(sendMessage.getMessageType()))	{
throw	new	IllegalArgumentException("messageType[" + sendMessage.getMessageType()	+ …);
}
…
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
public	class V1_0SendMessage	{
@Length(max	=	128)	//	최대 길이 127
@NotBlank //	값이 없거나 빈 문자열은 안됨
private String	to;
@Length(max	=	256)
@NotBlank
private String	title;
@Length(max	=	1024)
@NotBlank
private	String	body;
@NotBlank
@Pattern(regexp =	"AD|NOTIFICATION")	//	‘AD’,	‘NOTIFICATION’	둘 중 하나
private String	messageType;
}
@RestController
public	class V1_0MessageController	{
…
@PostMapping("/v1.0/messages")
public	V1_0SendMessageResponse	sendMessage(@RequestBody @Valid V1_0SendMessage	sendMessage)	{
…
}
}
@Validated
@Service
public	class MessageService {
public MessageEntity send(@Valid	@NotNull MessageEntity messageEntity)	{
…
}
}
@ControllerAdvice
public	class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value	=	ConstraintViolationException.class)
@ResponseBody
protected Response	handleException(ConstraintViolationException exception)	{
Response	response =	…
…
return response;
}
public	interface	ConstraintViolation<T>	{
String	getMessage(); //	생성된 메시지
Object	getLeafBean(); //	데이터 유효성 검사한 객체
Path	getPropertyPath(); //	데이터 유효성 검사가 실패한 속성
Object	getInvalidValue(); //	잘 못된 값
...
}
$	curl	-i -X	POST 
-H	'X-Secret-Key:vOwlgJY4'	
-H	'Content-Type:application/json'	
-d	'{"to":"jinho.shin","title":"힌트는","body":"오타","messageType":"NOTIFIACITON	"}'	
'http://127.0.0.1/v1.0/messages’
{
"header": {
"isSuccessful": false,
"resultCode": -400,
"resultMessage": "messageType['NOTIFIACITON']	- must	match	"AD|NOTIFICATION""
}
}
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy =	NoEmojiValidator.class)
@Documented
public @interface NoEmoji {
String	message()	default "Emoji	is	not	allowed";
…
}
public	class NoEmojiValidator implements ConstraintValidator<NoEmoji, String>	{
@Override
public boolean isValid(String	value,	ConstraintValidatorContext context)	{
if (StringUtils.isEmpty(value)	==	true)	{
return	true;
}
return EmojiParser.parseToAliases(value).equals(value);
}
}
public	class	V1_0SendMessage	{
@NoEmoji
@Length(max	=	128)	//	최대 길이 127
@NotBlank //	값이 없거나 빈 문자열은 안됨
private String	to;
@Length(max	=	256)
@NotBlank
private String	title;
@Length(max	=	1024)
@NotBlank
private String	body;
@NotBlank
@Pattern(regexp =	"AD|NOTIFICATION")	//	‘AD’,	‘NOTIFICATION’	둘 중 하나
private String	messageType;
}
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
public	class V1_0SendMessage	{
@To
private String	to;
@Length(max	=	256)
@NotBlank
private String	title;
@Length(max	=	1024)
@NotBlank
private String	body;
@NotBlank
@Pattern(regexp =	"AD|NOTIFICATION")	//	‘AD’,	‘NOTIFICATION’	둘 중 하나
private String	messageType;
}
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
ValidationMessage.properties 파일
org.hibernate.validator.constraints.EAN.message = invalid	{type}	barcode
org.hibernate.validator.constraints.Email.message = not	a	well-formed	email	address
org.hibernate.validator.constraints.ISBN.message = invalid	ISBN
org.hibernate.validator.constraints.Length.message = length	must	be	between	{min}	and	{max}
org.hibernate.validator.constraints.CodePointLength.message = length	must	be	between	{min}	and	{max}
ValidationMessage_ko.properties 파일
org.hibernate.validator.constraints.EAN.message = 올바르지 않은 {type}	바코드입니다
org.hibernate.validator.constraints.Email.message = 올바른 형식의 이메일 주소여야 합니다
org.hibernate.validator.constraints.ISBN.message = 올바르지 않은 ISBN입니다
org.hibernate.validator.constraints.Length.message = 길이가 {min}에서 {max}	사이여야 합니다
org.hibernate.validator.constraints.CodePointLength.message = 길이가 {min}에서 {max}	사이여야 합니다
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음
[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음

More Related Content

[2019] PaaS & API Experience: 좋은 API DX를 제공하기 위한 작은 걸음