고민거리

[Spring] 첫 스프링 공식 문서 기여 🎉

스프링피바라기 2022. 6. 12. 00:05

https://github.com/spring-projects/spring-framework/releases/tag/v5.3.21

 

Release v5.3.21 · spring-projects/spring-framework

⭐ New Features Expose ThreadPoolTaskExecutor queue size and capacity for metrics #28583 Lazily initialize DataSize.PATTERN #28560 MockMvcWebTestClient forces HTTP POST for multipart requests #2854...

github.com

#28603

 

안녕하세요!

저는 장기적으로 Spring 및 기타 오픈소스에 PR 기여를 하고싶다고

이전 게시글에서 말씀드렸었는데요

어떻게보면 첫 시작(?) 이 될 수 있는 Spring framework 공식 문서 기여를 달성했습니다! 

🎉🎉🎉

22/06/15 에 업데이트되어지는 spring 5.3.21 에 반영이되어진다.

 

https://github.com/spring-projects/spring-framework/issues/28603

 

Fix code sample for nested router functions · Issue #28603 · spring-projects/spring-framework

Hi, About nested Routes in Web on Reactive Docs , https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#nested-routes says path("/person", builder -> .....

github.com

 

 

 

최근에 Reactive Programming 을 공부하면서

Spring framework 의 Web on reative stack (WebFlux)

공식문서를 하나씩 훑어보면서 학습을 진행하고 있었습니다.

 

특히나 MVC에서도 지원되는 어노테이션 방식의 핸들러매핑 말고,

functional end-point 에 대한 방식에 관심이 많아 집중적으로 학습을 수행하고있었습니다.

 

그리고 RouterFunctions 에서 route() 하는 방식에 있어서,

중복되는 api uri 에 대해서 nest 처리할 수 있는 방식에 대한 예시가 뭔가 잘못된것같아서 이슈를 남겼습니다.

 

 

우선 해당 예시가 무엇에 대한것인지, 어떻게 문제가 될 수 있는지에 대해서 소개해드리겠습니다.

 

Spring MVC module 에서 요청에 대한 컨트롤러 매핑 상황을 생각해보면,

@GetMapping, @PostMapping 등 Request 에 대한 Mapping 어노테이션을 통해

사용자의 요청을 어떤 컨트롤러로, 정해진 비즈니스 로직이 수행되도록합니다.

 

이때,

GET /person

GET /person/{id}

POST /person 

과 같이 중복되는 path 에 대해서,

Controller 클래스 스코프에서 @RequestMapping("/person") 을 통해서

일괄적으로 prefix 에 대한 중복처리를 수행할 수 있습니다.

 

여기서 중요한 핵심은 "중복 제거" 입니다.

불필요한 반복을 지우는것이죠. 그리고 이것은 곧 RESTful 하고 Clean 한 API 설계로 이어진다고 생각합니다.

 

그리고 이제 Spring WebFlux module 에서 Funcional End-point 에 대해 살펴보자면,

RouterFounctions 를 통해 RouterFunction 인터페이스를 구현해 사용자의 Request를 매핑하게되는데,

 

이때,

RouterFuctions.route().path("something", Builder ) 형식으로 정의하게된다며느,

something 이라는 path 는 prefix 로 중복처리되어 Builder 에서 구현되어지는 Router 대상들로 매핑하게됩니다.

추가로, nest() 라는 메서드를 통해서 추가적인 중복 요소를 지정할 수 있습니다.

(예를 들어 Accept Type, Content-Type 등)

 

그리고 이제 문서에서 어떤 점이 저는 잘못되었다 생각했고, 문제를 제기 했는지 말씀드리겠습니다.

우선 실제 문서를 보여드리자면,

https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#nested-routes

.path("/person", ...) 을 통해

/person 이라는 prefix uri 의 매핑을 수행한다고 명시했습니다.

그리고 Builder 에서

GET "/{id}"

GET ""

POST "/person" 

이렇게 세가지의 라우터를 매핑하고 있습니다.

 

여기서, 저는 POST 의 예시가 올바르지 못하다고 판단했습니다.

그 근거로써 2가지를 말씀드리겠습니다.

 

1. 중복제거를 위한 예시인데, 의도한 API가 아니라면, 중복제거를 표현하지 못했다. 

해당 문서 예시는 "Nested Route" 와 관련한 예시였습니다.

그러나, POST /person/person 은 중복을 제거하기는 커녕 오히려 더 중복을 만드는 엉뚱한 상황이 생겼습니다.

의도한 API 라면 모를까, 그렇지 않다면 저는 이 부분을 실수로 판단했습니다.

 

2. 의도한 API 라면, 공식 문서로써, RESTful 한 API 를 예시를 들지 못했다고 생각한다.

handler::createPerson 라는 HandlerFunction 인터페이스는 네이밍에서 알 수 있듯이, 

"회원 생성" 을 담당하는 로직의 handler 라는 것을 알 수 있습니다. 

그리고 우리는 RESTful 한 API 는 api 만으로 어떤 것을 의도하는지 단번에 알아차릴수 있어야합니다.

 

그러나

POST /person/person 가 만약 의도한 API 라면, 

필자 본인은 당최 무슨 의도를 전달하고 싶은 API 인지 알 수 가 없었습니다.

(물론 회원생성이라는 것을 짐작할 수 있었지만, 직관적인 이해가 되기는 힘들었습니다.)

 

따라서 저는 Spring framework 의 공식 문서인만큼, 

학습자에게 명확하고 정확한 예시로 설명이되어야한다고 생각했습니다.

(저도 학습자에 포함합니다..)

 

그래서 저는 이슈를 남겼습니다.

사실 이 문서가 WebFlux 초창기부터 완성된 문서였어서, 

몇년동안 과연 아무도 이 api 에 대해서 의구심을 품지않았었나? 에대한 의심을 했습니다.

그래서 저는 제가 괜히 오지랖을 부리는것 아닐까.. 생각을 해서 주저했지만,

여러번 실제 예시를 수행해보고, 테스트 해본 결과,

도저히 해당 api 에 대한 설계를 이해할 수 없어서 문제를 제기했습니다. 

(작은 예시라할지라도.. 진지하게.. 제대로..!)

 

내가 제시한 업데이트 방향

 

 

여기서 저는 왜 POST("", handler::createPerson) 으로 업데이트를 추천했냐하면,

그냥 단순히

.POST(handler::createPerson) 으로하는 경우에는,

POST /person/** 과 같이 판단되어, 

하위 path 에 대해서도 요청이 유효하게되어,

"" 라고 명시함으로써 createPerson 은 POST /person 으로만 가능하게 하는 의도였습니다.

 

(하지만, 실제 수정은 .POST(handler::createPerson) 으로 되었더라구요.. ^^ )

 

결과적으로는 5.3.21 에 제 이슈가 반영이됩니다!

 

 

 

저는 이번 이슈와 반영에 대해서,

사실 엄청난 코드 PR 기여를 한것이 아니라서 막 자랑할 거리는 아니라고 생각하지만,

그래도 제 개인적인 목표달성에 있어서는 첫 걸음을 뗀 중요한 시작이라고 생각합니다..! 😊

 

저처럼 오픈소스 기여에 관심 있으신 분들도 

문제라고 생각되고, 문제에대한 명확한 근거가있다면, 

주저하지 말고 이슈를 제기해보세요!!

 

앞으로도 꾸준히 반영, 기여하려 노력하고

최종적으로 contributor 가 될 수 있도록..! 

 

긴 글 읽어주셔서 감사합니다 😄