Spring과 RESTful API 노트
또 nginx이네...
정적파일은 nginx가 앞에서 먼저 정적 파일 서빙 -> 단순한걸로 was에 부하를 주지 않기 위함. 등
그래서 우리가 만들 RESTful API이란? REST(Representational State Transfer 원칙을 따르는 웹 기반 API)
URI vs URL URI는 리소스를 식별하는 모든 방식 (이름, 위치, 둘다 포함의 총칭) 모든 URL은 URI 이지만 모든 URI가 URL은 아니다. 이거 간단한 예시와함께 쉽게 다시 설명
RESTful API
- 자원 명사 사용 -> 실무가서도 원칙을 지키야. 대산은 명사로. 가져올대상, 업데이트할 대상. 영어권애들은 자원명에 복수단수 구분하는경우도 있는데 이건 컨벤션 따라서
- 동사 대신 GET.POST.PUT,DELETE 등 HTTP 메서드로 동작을 표현
- 계층적구조
- 단수복수일관성
- 쿼리 파라미터
- 상태코드 활용
- 응답포맷 주로 JSON형식 사용
- Stateless: 각 요청은 독립적으로 처리, 서버는 클라이언트의 상태 저장 X
- 이 방식의 장단점 기술.
Spring과 Spring boot의 차이점. 톰캣 탑재와 빈 관점에서
bff 나중에 BFF 한번 써봐라 스프링클라우드게이트웨이. 즉 백앤드와 프론트 사이에서 마이크로서비스아키텍쳐를 위해 스프링클라우드게이트웨이가 분기처리를 비동기로 빠르게 해준다. 프론트에서 받아온 API를 받아서 백단에 spring, pythonaiserver 등등 다양한 백단까지 왔다갔다하는거. 이 과정에서 JWT 토큰의 사용이 bff 노드에서 일어남
컴포넌트 스캔? 실무에서 만약 누군가 만들어준 공통 라이브러리를 사용해야한다면 Maven에 등록해서 디펜던시 걸고 컴포넌트 스캔해서 넣어야함
MVC 패턴 Model View Controller
그리고 결국 api 구성에는 Repository-service-Controller 쌍으로 묶여서 활동하게됨.
- spring 컨테이너
- 스프링 빈의 생성,설정,관리,소멸 등 생명 주기 전반을 담당하는 핵심 엔진 스프링빈의 생성,
- 빈이란?
- 스프링이 관리하는 객체(인스턴스)를 의미
- 스프링 컨테이너가 생성하고 생명주기를 관리. 개발자가 new로 직접생성X
- 싱글턴 방식으로 관리.
- 싱클톤패턴
- 프로그램 실행 내내 단 하나의 객체만 생성해서 공유하는 디자인 패턴
- 스프링 컨테이너는 기본적으로 모든 비능ㄹ 싱글턴으로 관리
- 어노테이션
- 자바 코드에 메타데이터를 제공하는 특수한 표기법
- @기호로 시작
- 컴파일러, 개발 툴, 런타임 등에서 특별한 의미로 해석
- 스프링에서의 어노테이션?
- 설정 및 의존성 주입을 간편하게 처리하고 객체를 자동으로 등록하거나 관리
- 다양한 기능(트랜잭션, 보안, 예외처리등)을 선언적으로 적용하는 방식2
클라이언트가 스프링 서버로 보내는 데이터는 위치와 목적에 따라 다양합니다. 요청의 성격에 맞춰 데이터를 어떻게 구분하고, 어떤 어노테이션을 사용하여 받는지 한 페이지로 완벽하게 정리해 드릴게요.
📥 스프링 부트 요청 인풋(Input) 유형 총정리
HTTP 요청의 어느 부분에 데이터가 담겨 오느냐에 따라 크게 5가지로 나뉩니다.
1. 요청 데이터 분류 체계
| 구분 | 위치 | 설명 | 핵심 어노테이션 |
|---|---|---|---|
| URL 경로 (Path) | /users/{id} |
URL 경로 자체에 값을 포함 (자원 식별) | @PathVariable |
| 쿼리 파라미터 (Query) | ?name=kim&age=20 |
URL 끝에 ?와 함께 전달 (필터링, 검색) |
@RequestParam |
| 폼 데이터 (Form) | Body (key=value) |
HTML <form> 태그를 통해 전달되는 데이터 |
@ModelAttribute / @RequestParam |
| 메시지 바디 (API/JSON) | Body ({...}) |
REST API에서 주로 쓰는 JSON 형태의 데이터 | @RequestBody |
| 메타데이터 (Metadata) | Header / Cookie | 인증 토큰, 브라우저 정보, 세션 ID 등 | @RequestHeader / @CookieValue |
2. 인풋별 상세 설명 및 활용
📍 URL 경로 변수 (@PathVariable)
- 특징: 자원의 위치를 명확히 할 때 사용합니다.
- 예시:
GET /posts/10→ 10번 게시글을 가져올 때. - 용도: 주로 RESTful API에서 특정 리소스를 식별하는 ID 값으로 씁니다.
🔍 쿼리 파라미터 (@RequestParam)
- 특징: URL은 유지하면서 추가적인 옵션을 줄 때 사용합니다.
- 예시:
GET /posts?category=tech&sort=desc→ tech 카테고리 글을 최신순으로 정렬할 때. - 용도: 검색, 필터링, 페이징 처리에 적합합니다.
📝 폼(Form) 데이터 (@ModelAttribute)
- 특징:
application/x-www-form-urlencoded형식으로 전달됩니다. - 용도: 전통적인 웹 페이지의 회원가입, 게시글 작성 화면에서 사용자가 입력한 값을 객체(DTO)로 통째로 바인딩할 때 매우 편리합니다.
🤖 메시지 바디 / API (@RequestBody)
- 특징: 주로 JSON 형식을 사용하며, 외부에 노출되지 않도록 HTTP Body에 담겨 옵니다.
- 용도: 현대적인 웹(React, Vue)이나 앱과의 통신에서 복잡한 객체 데이터를 주고받을 때 표준으로 사용됩니다.
📑 메타데이터 (@RequestHeader)
- 특징: 비즈니스 데이터가 아닌, 통신에 필요한 부가 정보를 담습니다.
- 용도: 인증 토큰(JWT), 클라이언트 기기 정보(User-Agent), 응답받고 싶은 데이터 형식(Accept) 등을 확인할 때 씁니다.
3. 데이터 흐름 요약도
데이터가 들어오면 Handler Adapter가 이 어노테이션들을 확인하여 적절한 데이터 형식으로 변환해 줍니다.
💡 팁: > * 단순한 값 1~2개면? 👉
@RequestParam
- 복잡한 객체나 JSON이면? 👉
@RequestBody- URL 경로에 포함된 ID면? 👉
@PathVariable
a 컴포넌트 b컴포넌트 있응ㅇㄹ때, A가 있어야 B가있는 상황에서 어노테이션을 통해 빈 시공간순서 제어가능
private final을 이용한 생성자 주입이 권장된다는 사실을 아시다니, 이미 스프링의 핵심을 꿰뚫고 계시네요! 사실 현대 스프링 개발에서는 필드 주입(@Autowired 직접 사용)을 "피해야 할 안티 패턴"으로 보기도 하지만, 여전히 실무에서 사용되는 **'현실적인 이유'**들이 있습니다.
@Autowired 필드 주입 방식을 사용해도 괜찮거나, 혹은 어쩔 수 없이 쓰게 되는 4가지 상황을 정리해 드릴게요.
🏗️ @Autowired 필드 주입을 사용하는 상황
1. 테스트 코드 (@SpringBootTest)
가장 대표적인 경우입니다. 테스트 코드에서는 객체의 불변성을 보장하거나 생성자를 복잡하게 설계할 필요가 없습니다.
- 이유: 테스트 클래스는 스프링이 생성자를 통해 빈을 주입하는 방식과 JUnit의 동작 방식이 충돌할 수 있어, 가장 단순한
@Autowired필드 주입을 주로 사용합니다. - 예시:
@SpringBootTest
class MyTest {
@Autowired
MyService myService; // 테스트에서는 간결함이 최고!
}
2. 레거시 코드 유지보수
이미 수만 줄의 코드가 필드 주입 방식으로 작성된 프로젝트를 맡게 되었을 때입니다.
- 이유: 혼자만 생성자 주입으로 바꾸면 코드의 일관성이 깨지고, 전체를 다 바꾸기엔 리스크가 큽니다. 이런 경우 팀의 컨벤션을 따르기 위해 계속 사용하기도 합니다.
3. 설정 클래스 (@Configuration)
스프링 설정 자체를 담당하는 클래스 내에서 다른 빈을 잠시 참조해야 할 때 사용합니다.
- 이유: 설정 클래스는 실제 비즈니스 로직이 아니므로 불변성이나 테스트 용이성에서 상대적으로 자유롭기 때문입니다.
4. 의존성이 필수가 아닐 때 (Optional Dependency)
특정 빈이 없어도 프로그램이 돌아가야 하는 경우에 사용합니다.
- 방법:
@Autowired(required = false)옵션을 주면, 주입할 빈이 없어도 에러가 나지 않고null로 유지됩니다. - 참고: 생성자 주입은 빈이 없으면 객체 생성 자체가 안 되어 애플리케이션이 멈추기 때문에, 옵션이 필요한 경우 필드 주입이나 Setter 주입이 대안이 됩니다.
⚠️ 그럼에도 주의할 점
제공해주신 표를 보면 @Autowired는 필드, 생성자, 메서드 어디든 사용 가능하다고 되어 있습니다. 하지만 실무에서는 다음과 같은 이유로 여전히 생성자 주입을 선호합니다.
| 문제점 | 필드 주입 (@Autowired) |
해결책 (생성자 주입) |
|---|---|---|
| NPE 위험 | 주입 없이 객체를 생성하면 메서드 호출 시 터짐 | 객체 생성 시점에 주입이 강제됨 |
| 의존성 숨김 | 클래스 외부에서 어떤 의존성이 있는지 알기 어려움 | 생성자의 파라미터를 통해 명확히 보임 |
💡 한 줄 요약
"테스트 코드나 아주 간단한 프로토타이핑이 아니라면, 가급적 private final과 생성자 주입을 쓰되, @Autowired는 보조 수단으로 이해하자!"
결국 생성자 final 방식으로 선언하는게 제일 안전함. 서비스 빈이 만들어지는 동시에 레포지토리 빈 주소까지 받아오는.
순환참조 오류 -> 내지말아라