[Spring boot] MVC ํจํด์ ์ด์ฉํ REST API ๊ฐ๋ฐ
์ง๋ ํฌ์คํธ์์ REST API๊ฐ ๋ฌด์์ธ์ง, ์ด๋ป๊ฒ ์ค๊ณ๋ฅผ ํด์ผํ๋์ง์ ๋ํด์ ๋ค๋ค๋ดค์ต๋๋ค. REST API๋ HTTP Method๋ฅผ ์ด์ฉํ์ฌ ํ์๋ฅผ ์ ํ๊ณ , URI๋ฅผ ์ด์ฉํด์ ๋ฆฌ์์ค๋ฅผ ์ ํ๋ ๋ฐฉ์์ผ๋ก ๋์ํ๋ ์๋ฒ์๋๋ฐ์.
์ด๋ฒ ํฌ์คํธ์์๋ MVC ํจํด + Spring boot 2.x ์กฐํฉ์ ์ด์ฉํ์ฌ ๊ฐ๋จํ REST API ์๋ฒ๋ฅผ ๊ฐ๋ฐํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
What is MVC ?
MVC ํจํด์ ๋ํด์๋ ์๋์ ๊ธ์์ ๋ค๋ค ๋ณธ์ ์ด ์๋๋ฐ์. ํน์ MVC ํจํด์ ๋ํด ๋ค์ ๋ณต์ตํด๋ณด์๊ฑฐ๋, ์ ๋ชจ๋ฅด์ ๋ค๋ฉด, ์๋์ ๊ธ์ ๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
2016/12/29 - [Programming/JavaFX] - MVC Pattern์ ๊ธฐ๋ฐํ GUI ๋ผ์ด๋ธ๋ฌ๋ฆฌ JavaFX
๊ฐ๋ฐ ํ๊ฒฝ ์ค์
์ด์ ๋ณธ๊ฒฉ์ ์ธ ์๋ฒ ๊ฐ๋ฐ์ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ๋จผ์ ๊ฐ๋ฐ์ ์ํด ํ๊ฒฝ ์ค์ ์ ์งํํ ํ ๋ฐ, ๊ทธ ์ ์ ์ฐ๋ฆฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ์ด๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ์ง๋ฅผ ๊ฒฐ์ ํ๋ ๊ฒ ์ข๊ฒ ์ฃ ? ์ด ํฌ์คํธ์์๋ Java 8๊ณผ MySQL์ ์ด์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ธํ ๋ฆฌJ์์ ์ ๊ณตํ๋ Spring Initializr๋ฅผ ์ด์ฉํด Java 8๊ณผ Gradle Project๋ก ๋ง์ถฐ์ฃผ๋๋ก ํฉ์๋ค.
์ฌ๊ธฐ์์ REST API๋ฅผ ๊ตฌํํ๊ธฐ ์ํด Spring Web ๋ํ๋์๋ฅผ ์ถ๊ฐํ๊ณ , DB์์ ์ฐ๋์ ์ํด Spring Data JPA์ MySQL Driver๋ฅผ ์ ํํด์ค๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ๊ธฐ์ ์ถ๊ฐ๋ก Lombok์ ํ๋ ๋ ์ถ๊ฐํ๊ฒ ์ต๋๋ค.
Lombok์ ๋ฐ์ดํฐ ๋ชจ๋ธ๋ง์ ํธ๋ฆฌํ๊ฒ ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. Getter, Setter ๋ฑ์ ์ด๋ ธํ ์ด์ ์ ์ด์ฉํด ์ฝ๊ฒ ๊ตฌํํ ์ ์๋๋ก ํ๋ฉฐ, ๋น๋ ํจํด์ ์ง์ํ์ฌ ์ปจ๋ฒํ ๋ฑ์ ํด๋์ค ๊ตฌํ์ ์ฝ๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
Spring Data JPA๋ Spring์์ Database์ ์ฐ๋ํ๊ธฐ ์ํ ๋ํ๋์์ธ๋ฐ, ๋ณธ๋๋ MyBatis๋ผ๋ ๊ฒ์ด ์์ง๋ง Spring boot JPA๋ Object-oriented Programming ํํ๋ก DB์ ์ ๊ทผํ ์ ์๋๋ก ํ์ฌ, ๋์ฑ ๋ ์ฝ๊ฒ DB ์ฐ๋์ ๊ตฌํํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ฐจํ, JPA์ Hibernate๋ฅผ ๋ค๋ฃจ๋ ํฌ์คํธ์์ ์์ธํ๊ฒ ์ด์ผ๊ธฐ ํ๋๋ก ํ๊ฒ ์ต๋๋ค.
๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ์ ์ข ๋ ํธํ๊ฒ ์ค์ ํ๊ธฐ ์ํด, application.properties๋ฅผ application.yml ํ์ผ๋ก ์์ ํด์ค๋๋ค.
์ด ์ค์ ์ ์งํํ๊ธฐ ์ ์, ๋จผ์ MySQL ์๋ฒ๊ฐ ๊ตฌ์ถ๋์ด ์๋ ์ํ์ฌ์ผ ํฉ๋๋ค. ์ด ๋ถ๋ถ์ ๋ํด์๋ ํฌ์คํธ์์ ๋ค๋ฃจ์ง ์์ ๊ฒ์ด๋ฉฐ, ๋ก์ปฌ ํ๊ฒฝ์ด๋ผ๋ฉด Docker ๋ฑ์ ์ปจํ ์ด๋ ํ๊ฒฝ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅ๋๋ฆฌ๊ณ , ์๋ฒ๊ฐ ์๋ค๋ฉด ๊ทธ๊ฒ์ ์ฐ๋ ๊ฒ์ด ์ข๊ฒ ์ฃ ?
์๋ฒ ์ค์น๊ฐ ๋๋ฌ๋ค๋ฉด, ์์ ์ค์ ๋๋ก username, password๋ฅผ ์ ๋ ฅํ๊ณ , DB๋ช ์ ์ ํด์ค๋๋ค. ๋จ, DB๋ ๋ง๋ค์ด๋์ง ์์ต๋๋ค.
JPA ์ต์ ์์ ddl-auto ์ต์ ์ create๋ก ์ค์ ํด์ฃผ๊ณ , Database๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด์ฃผ๋๋ก ํฉ์๋ค.
์ค์ ์ด ๋๋ฌ์ผ๋ฉด, ์ํ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ์ ์ฅํ Domain, API๋ฅผ ๊ตฌํํ Controller์ Repository ์ด๋ ๊ฒ 3๊ฐ์ง ํจํค์ง๋ฅผ ๋ง๋ค์ด์ฃผ๋ฉด, ๊ธฐ๋ณธ์ ์ธ ํ๋ก์ ํธ ์ค์ ์ด ๋ชจ๋ ๋๋ฌ์ต๋๋ค.
REST API ๊ตฌํ
๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ์ด ๋๋ฌ์ผ๋ ์ด์ ๋ฐ๋ก REST API ๊ตฌํ์ ์์ํด๋ณด๋๋ก ํ์ฃ . Spring boot์์ REST API๋ฅผ ๊ตฌํํ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์๋ฒ๊ฐ ์์ํ ๋ ์๋์ผ๋ก ์์ฑํด์ฃผ๊ณ , ์ด์ ๋จ์ ๊ฑด Entity๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค. ์ํ์ ๋ํ Entity๋ฅผ ๋ง๋ค์ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
Spring boot JPA๋ ๊ฐ๋จํ ์ด๋ ธํ ์ด์ ๋ง์ผ๋ก๋ ํ ์ด๋ธ์ ์ ์ํ ์ ์๊ณ , ์ด๋ฅผ ์ปค๋ฐ๊น์ง ํด์ค๋๋ค. ๊ทธ๋ฆฌ๊ณ , ์ด๋ค ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ธฐ ์ํด์ Getter์ Setter๋ฅผ ์ ์ํด์ผ ํ๋๋ฐ, Getter Setter๋ ์ธํ ๋ฆฌJ์์ Alt + Insert ๋จ์ถํค๋ฅผ ํตํด์๋ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ง๋ง, ๊ทธ๋ ๊ฒ ๋๋ฉด ์ฝ๋๊ฐ ๊ธธ์ด์ง๋ฏ๋ก Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ Getter ์ด๋ ธํ ์ด์ ์ ์ด์ฉํด์ ํ ๋ฒ์ ๋ชจ๋ ๋ณ์๋ค์ ๋ํ Getter๋ฅผ ๊ตฌํํด์ฃผ๋ฉด ์์ ๊ฐ์ด ๊น๋ํ ์ฝ๋๊ฐ ๋์ค๊ฒ ๋ฉ๋๋ค.
Setter์ ๊ฒฝ์ฐ, ๊ฐ ๋ฉค๋ฒ ๋ณ์๋ณ๋ก set ๋ฉ์๋๋ฅผ ์ผ์ผ์ด ๋ถ๋ฌ์์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฝ๋๊ฐ ์ง์ ๋ถํด์ง๋ฏ๋ก, ์์ฑ์์ Builder ์ด๋ ธํ ์ด์ ์ ์ฃผ๊ณ , ๋น๋ ํจํด์ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ ์ ์๋๋ก ํฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก NoArgusConstructor ์ด๋ ธํ ์ด์ ์ ์ค์ ๋ก REST API๋ฅผ ์ด์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ฌ ๋, ๊ธฐ๋ณธ ์์ฑ์๊ฐ ์์ด์ผ ํ๋๋ฐ, ์ด๋ฅผ ์์ฑํ์ง ์๊ณ , ์ด๋ ธํ ์ด์ ์ ์ค์ผ๋ก์จ ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ์๋์ผ๋ก ๋ง๋ค๋๋ก ํด์ฃผ๋ฉด ๊น๋ํ ์ฝ๋๊ฐ ๋ฉ๋๋ค.
๊ทธ ๋ค์์ Repository๋ฅผ ์ธํฐํ์ด์ค๋ก ๊ตฌํํ๊ณ , Spring Data JPA์์ ์ ๊ณตํ๋ JpaRepository๋ฅผ ์์๋ฐ๋๋ก ํฉ๋๋ค. Generic์๋ ์์์ ๋ง๋ค์ด์ค Item ํด๋์ค์ PK์ ํ์ ์ธ Long ํ์ ์ผ๋ก ์ฃผ๋ฉด ๋ฉ๋๋ค.
๋ณธ๋ Repository๋ฅผ ๊ตฌํํด ์ค ๋ค, ์๋น์ค ํด๋์ค๋ฅผ ๊ตฌํํ์ฌ, Repository ์ธํฐํ์ด์ค๋ฅผ ์ฃผ์ ํ ๋ค์, ์๋น์ค์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํด์ผ ํ์ง๋ง, ์ฌ๊ธฐ์ ๋ณ๋์ ์ฒ๋ฆฌ ๋ก์ง์ด ํ์์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก Controller ๊ตฌํ์ผ๋ก ๋์ด๊ฐ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ค๊ณ ํฌ์คํธ์์ ํ๋๋๋ก GET, POST, PUT, DELETE 4๊ฐ์ ๋ฉ์๋๋ฅผ ๋ง๋ค์์ต๋๋ค. ๊ฐ ๋ฉ์๋์ ๋ํด์๋ **Mapping์ผ๋ก ๋๋๋ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ๋ฉด ๋๊ณ , ๋ฐํ๋์ด์ผ ํ๋ ๋ฐ์ดํฐ ํ์ ์ ResponseEntity๋ฅผ ํตํด ๊ธฐ๋ณธ ํ์ ์ ์ฌ์ฉํ ์ ์๊ณ , ์ปค์คํ ํด๋์ค๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ๋ ์์ง๋ง, ์ฌ๊ธฐ์๋ ResponseEntity ํด๋์ค๋ฅผ ์ด์ฉํ์์ต๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค I/O ์์ ์ Repository ์ธํฐํ์ด์ค์์ ์ฒ๋ฆฌ๋ฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก JpaRepository์์๋ save ๋ฉ์๋๋ฅผ ํตํด INSERT ํน์ UPDATE ์ฟผ๋ฆฌ๊ฐ ์ด๋ฃจ์ด์ง๊ณ , find** ๋ฉ์๋๋ฅผ ํตํด SELECT๊ฐ ์ด๋ฃจ์ด์ง๋๋ค.
Test
API ์๋ฒ๊ฐ ์ ๋๋ก ๋์ํ๋์ง ๊ฐ๋จํ ํ ์คํธ๋ฅผ ์งํํ๋๋ก ํ๊ฒ ์ต๋๋ค. ํ ์คํธ๋ฅผ ์ํด Curl์ ์ด์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
$ curl http://localhost:8080/api/items | json_pp
์ฒ์์๋ ์๋ฌด๊ฒ๋ ๋ํ๋์ง ์์ต๋๋ค. ์๋ฌด๋ฐ ์ํ๋ ์ถ๊ฐํ์ง ์์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ POST ๋ฉ์๋๋ฅผ ์ด์ฉํด ์๋กฑ๋ ์ํ์ ์ถ๊ฐ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
$ curl -X POST -H "Content-Type: application/json" --data '{ "name": "apple", "price": 3000 }' http://localhost:8080/api/items | json_pp
POST ๋ฉ์๋๋ฅผ ์ด์ฉํด ์์ ๊ฐ์ด ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ ํ, GET ๋ฉ์๋๋ฅผ ๋ถ๋ฅด๋ฉด, ์์ ๊ฐ์ด ์๋ก ์ถ๊ฐ๋ ์ํ์ด ๋ํ๋๊ณ ์์์ ์ ์ ์์ต๋๋ค.
$ curl -X PUT -H "Content-Type: application/json" --data '{ "name": "apple", "price": 1500 }' http://localhost:8080/api/items/1 | json_pp
๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก PUT ๋ฉ์๋๋ฅผ ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค. ์ํ์ ๊ฐ๊ฒฉ์ด ๋น์ธ๊ฒ ์ฑ ์ ๋์ด, ๊ฐ๊ฒฉ์ ๋ด๋ฆฌ๊ณ ์ ํ๋ ๊ฒฝ์ฐ, PUT ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
PUT, POST๋ฅผ ์ด์ฉํด JSON ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๊ฒฝ์ฐ, Curl์ ์ฌ์ฉํ ๋๋ Header์ ๋ฐ๋์ application/json์ ์ ๋ ฅํด์ผ ํฉ๋๋ค.
$ curl -X DELETE http://localhost:8080/api/items/1 | json_pp
๋ง์ง๋ง์ผ๋ก ๋ฐ์ดํฐ๊ฐ ์ ์ญ์ ๋๋์ง๋ ํ์ธํด๋ณด์ฃ .
ID ๊ฐ์ ์ด์ฉํด ์ ์์ ์ผ๋ก ๋ฐ์ดํฐ๊ฐ ์ญ์ ๋์ด, GET ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ ๋ ์ด์ ๋์ค์ง ์๋ ๋ชจ์ต์ ๋๋ค.
๋ง์น๋ฉฐ...
์ฌ๊ธฐ๊น์ง ์์ฃผ ๊ฐ๋จํ REST API ์๋ฒ๋ฅผ ๊ฐ๋ฐํด๋ดค์ต๋๋ค. ์๋น์ค์ ๋ฐ๋ผ์ ์ด๋ค์์ผ๋ก Controller ์ฝ๋๋ฅผ ๊ตฌํํด์ผ ํ๊ณ , ๋ชจ๋ธ๋ง์ ์ด๋ป๊ฒ ํ์ฌ์ผ ํ๋ฉฐ, ๋ฐํ ๊ฐ์ด๋ ์์ฒญ ๊ฐ์ ํํ๋ฅผ ์ด๋ป๊ฒ ์ค์ผํ ์ง, ์ด๋ค ๊ฐ์ ์ ์ธํ๊ณ , ์ด๋ค ๊ฐ์ ์ค์ผ ํ ์ง ๋ฑ์ ์๊ฐํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ค์ ์ค๋ฌด์์๋ ์ด ํฌ์คํธ์์ ๋ค๋ฃจ๋ ๊ฒ๋ณด๋ค ๋ค์ ์ด๋ ค์ธ ๊ฒ์ ๋๋ค.
๋ค์ ํฌ์คํธ์์๋ Spring Data Rest๋ฅผ ์ด์ฉํ REST API ๊ฐ๋ฐ์ ๋ํด ์ ์ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
'Programming > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring boot] Spring Data Rest๋ฅผ ์ด์ฉํ REST API ๊ฐ๋ฐ 2 (1) | 2020.05.20 |
---|---|
[Spring boot] Spring Data Rest๋ฅผ ์ด์ฉํ REST API ๊ฐ๋ฐ 1 (0) | 2020.05.20 |
[Spring boot] REST API์ ๊ธฐ์ด์ ์ค๊ณ (0) | 2020.05.19 |
[Spring boot] Spring boot test starter๋ฅผ ์ด์ฉํ ํ ์คํธ ์ฝ๋ ์์ฑ (0) | 2020.04.23 |
[Spring boot] ๋๋ง์ ํ๊ฒฝ ์ค์ ๋ง๋ค๊ธฐ (0) | 2020.04.22 |