๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring/Boost Course Web

4.3 WEB API

1) Rest API๋ž€?

HTTP ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ๋žœ๋”๋งํ•˜์—ฌ ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

HTTP์˜ ์ด๋Ÿฐ ํŠน์ง•์„ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์„๊นŒ? ๋ผ๋Š” ๊ณ ๋ฏผ์„ ๊ฐœ๋ฐœ์ž๋“ค์€ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 

์ฆ‰, ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ, ๋ชจ๋ฐ”์ผ ์•ฑ, Javascript ๋“ฑ์—์„œ HTTP๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์—†์„๊นŒ? ํ•˜๋Š”

์ƒ๊ฐ์„ ํ•˜๊ฒŒ ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด, ์ •๋ถ€์—์„œ ๋ฒ„์Šค ์šดํ–‰ ์‹œ๊ฐ„ํ‘œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ •๋ถ€์—์„œ๋Š” 300๋ฒˆ ๋ฒ„์Šค์— ๋Œ€ํ•œ ์‹œ๊ฐ„ํ‘œ๋ฅผ ์ œ๊ณตํ•˜๋Š” URL์„ ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

http://ip์ฃผ์†Œ/api/buses/300

์œ„์™€ ๊ฐ™์€ URL์„ ํ˜ธ์ถœ ํ•˜๊ฒŒ ๋˜์—ˆ์„ ๋•Œ ์‹œ๊ฐ„ํ‘œ ์ •๋ณด๋ฅผ ํŠน์ •ํ•œ ํ˜•ํƒœ๋กœ ์ œ๊ณตํ•œ๋‹ค๋ฉด, 

๊ทธ ์ •๋ณด๋ฅผ ๋‹ค์–‘ํ•œ ํด๋ผ์ด์–ธํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

HTTP ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•ด ์š”์ฒญ์„ ๋ฐ›๊ณ  ์•Œ๋งž์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ์‹์ค‘์—์„œ REST API๋ผ๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํ•™์Šต์—์„œ๋Š” REST API์— ๋Œ€ํ•ด ํ•™์Šตํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

2000๋…„๋„์— ๋กœ์ด ํ•„๋”ฉ(Roy Fielding) ๋ฐ•์‚ฌ์˜ ํ•™์œ„ ๋…ผ๋ฌธ์— REST๋ผ๋Š” ๊ฐœ๋…์ด ์ฒ˜์Œ ๋“ฑ์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค. 

REST๋Š” ‘Representational State Transfer’์˜ ์•ฝ์ž๋กœ ์ž์›์„ ์ด๋ฆ„์œผ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ํ•ด๋‹น ์ž์›์˜ ์ƒํƒœ(์ •๋ณด)๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. 

 

๋กœ์ด ํ•„๋”ฉ์˜ ๋…ผ๋ฌธ์—๋Š” ๋จผ์ € ์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ(architectural style)์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. 

์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์ด๋ž€ ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์ง€์ผœ์•ผ ํ•˜๋Š” ์ œ์•ฝ ์กฐ๊ฑด๋“ค์˜ ์ง‘ํ•ฉ์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋กœ์ด ํ•„๋”ฉ์€ ์›น ์•„ํ‚คํ…์ฒ˜์˜ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ํ•ด๊ฒฐํ•ด์•ผํ•  ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ ‘๊ทผ ๋ฐฉ๋ฒ•์„ ๋…ผ๋ฌธ์—์„œ ์ œ์‹œํ•˜๋ฉด์„œ, ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์ธ REST๋ฅผ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. 

 

REST๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์›น์˜ ๊ธฐ์กด ๊ธฐ์ˆ ๊ณผ HTTPํ”„๋กœํ† ์ฝœ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์›น์˜ ์žฅ์ ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํ•™์Šต์—์„œ๋Š” ๋กœ์ดํ•„๋”ฉ์ด ๋งํ•œ REST์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

1. REST ๊ตฌ์„ฑ

REST API๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ 3๊ฐ€์ง€ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

 

- ์ž์›(Resource) : ์ž์›์€ Data, Meta Data, HATEOAS๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.

- ํ–‰์œ„(Verb) : HTTP Method๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค.

- ํ‘œํ˜„(Representations)

 

 

2. REST์˜ ํŠน์ง•

 

1) Uniform Interface(์œ ๋‹ˆํผ ์ธํ„ฐํŽ˜์ด์Šค)

๊ตฌ์„ฑ ์š”์†Œ(ํด๋ผ์ด์–ธํŠธ, ์„œ๋ฒ„ ๋“ฑ) ์‚ฌ์ด์˜ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ท ์ผ(uniform)ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ผ๋ฐ˜ํ™”ํ•จ์œผ๋กœ์จ, ์ „์ฒด ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋‹จ์ˆœํ•ด์ง€๊ณ , ์ƒํ˜ธ ์ž‘์šฉ์˜ ๊ฐ€์‹œ์„ฑ์ด ๊ฐœ์„ ๋˜๋ฉฐ, 

๊ตฌํ˜„๊ณผ ์„œ๋น„์Šค๊ฐ€ ๋ถ„๋ฆฌ๋˜๋ฏ€๋กœ ๋…๋ฆฝ์ ์ธ ์ง„ํ™”๊ฐ€ ๊ฐ€๋Šฅํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

2) Stateless (๋ฌด์ƒํƒœ์„ฑ)

ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ํ†ต์‹ ์—๋Š” ์ƒํƒœ๊ฐ€ ์—†์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”์ฒญ์€ ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์š”์ฒญ ํ•˜๋‚˜๋งŒ ๋ด๋„ ๋ฐ”๋กœ ๋ญ”์ง€ ์•Œ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ€์‹œ์„ฑ์ด ๊ฐœ์„ ๋˜๊ณ , task ์‹คํŒจ์‹œ ๋ณต์›์ด ์‰ฌ์šฐ๋ฏ€๋กœ ์‹ ๋ขฐ์„ฑ์ด ๊ฐœ์„ ๋˜๋ฉฐ,

์ƒํƒœ๋ฅผ ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๊ทœ๋ชจ ํ™•์žฅ์„ฑ์ด ๊ฐœ์„ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

3) Cacheable (์บ์‹œ ๊ฐ€๋Šฅ)

์บ์‹œ๊ฐ€ ๊ฐ€๋Šฅํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋ชจ๋“  ์„œ๋ฒ„ ์‘๋‹ต์€ ์บ์‹œ๊ฐ€ ๊ฐ€๋Šฅํ•œ์ง€ ๊ทธ๋ ‡์ง€ ์•„๋‹Œ์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. 

ํšจ์œจ, ๊ทœ๋ชจ ํ™•์žฅ์„ฑ, ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ์˜ ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.

 

4) Self-descriptiveness (์ž์ฒด ํ‘œํ˜„ ๊ตฌ์กฐ)

REST์˜ ๋˜ ๋‹ค๋ฅธ ํฐ ํŠน์ง• ์ค‘ ํ•˜๋‚˜๋Š” REST API ๋ฉ”์‹œ์ง€๋งŒ ๋ณด๊ณ ๋„ ์ด๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์ž์ฒด ํ‘œํ˜„ ๊ตฌ์กฐ๋กœ ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

5) Client - Server ๊ตฌ์กฐ

ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ์Šคํƒ€์ผ์€ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ๊ด€์‹ฌ(concern)์„ ๋ฐ์ดํ„ฐ ์ €์žฅ์— ๋Œ€ํ•œ ๊ด€์‹ฌ์œผ๋กœ๋ถ€ํ„ฐ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ

ํด๋ผ์ด์–ธํŠธ์˜ ์ด์‹์„ฑ๊ณผ ์„œ๋ฒ„์˜ ๊ทœ๋ชจํ™•์žฅ์„ฑ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

6) Layered System(๊ณ„์ธตํ˜• ๊ตฌ์กฐ)

REST ์„œ๋ฒ„๋Š” ๋‹ค์ค‘ ๊ณ„์ธต์œผ๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ณด์•ˆ, ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ, ์•”ํ˜ธํ™” ๊ณ„์ธต์„ ์ถ”๊ฐ€ํ•ด ๊ตฌ์กฐ์ƒ์˜ ์œ ์—ฐ์„ฑ์„ ๋‘˜ ์ˆ˜ ์žˆ๊ณ 

PROXY, ๊ฒŒ์ดํŠธ์›จ์ด ๊ฐ™์€ ๋„คํŠธ์›Œํฌ ๊ธฐ๋ฐ˜์˜ ์ค‘๊ฐ„๋งค์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

 

 

 

3. REST API ์„ค๊ณ„ ๊ฐ€์ด๋“œ

REST API ์„ค๊ณ„ ์‹œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํ•ญ๋ชฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

1) URI๋Š” ์ •๋ณด์˜ ์ž์›์„ ํ‘œํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

resource๋Š” ๋™์‚ฌ๋ณด๋‹ค๋Š” ๋ช…์‚ฌ๋ฅผ, ๋Œ€๋ฌธ์ž๋ณด๋‹ค๋Š” ์†Œ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

resource์˜ ๋„ํ๋จผํŠธ ์ด๋ฆ„์œผ๋กœ๋Š” ๋‹จ์ˆ˜ ๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

resource์˜ ์ปฌ๋ ‰์…˜ ์ด๋ฆ„์œผ๋กœ๋Š” ๋ณต์ˆ˜ ๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

resource์˜ ์Šคํ† ์–ด ์ด๋ฆ„์œผ๋กœ๋Š” ๋ณต์ˆ˜ ๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์˜ˆ : GET /members/1

 

2) ์ž์›์— ๋Œ€ํ•œ ํ–‰์œ„๋Š” HTTP Method (GET, POST, PUT, DELETE)๋กœ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.

 

3) URI์— HTTP Method๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ) GET /books/delete/1 (X)  -> DELETE /books/1 (O)

 

4) URI์— ํ–‰์œ„์— ๋Œ€ํ•œ ๋™์‚ฌ ํ‘œํ˜„์ด ๋“ค์–ด๊ฐ€๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

(์ฆ‰, CRUD ๊ธฐ๋Šฅ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์€ URI์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

์˜ˆ) GET /books/show/1 (X) -> GET /books/1  (O)

์˜ˆ) GET /books/insert/2 (X) -> POST /books/2  (O)

 

5) ๊ฒฝ๋กœ ๋ถ€๋ถ„ ์ค‘ ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„์€ ์œ ์ผํ•œ ๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

(์ฆ‰, id๋Š” ํ•˜๋‚˜์˜ ํŠน์ • resource๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ณ ์œ ๊ฐ’์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.)

์˜ˆ) book์„ ์ƒ์„ฑํ•˜๋Š” URI: POST /students

์˜ˆ) id=10 ์ธ book์„ ์‚ญ์ œํ•˜๋Š” URI: DELETE /students/10

 

6) ์Šฌ๋ž˜์‹œ ๊ตฌ๋ถ„์ž(/ )๋Š” ๊ณ„์ธต ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”๋ฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ) http://edwith.org/courses/java

 

7) URI ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋กœ ์Šฌ๋ž˜์‹œ(/ )๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ) http://edwith.org/courses/ (X)

 

8) URI์— ํฌํ•จ๋˜๋Š” ๋ชจ๋“  ๊ธ€์ž๋Š” ๋ฆฌ์†Œ์Šค์˜ ์œ ์ผํ•œ ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•˜๋ฉฐ 

URI๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์€ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์ด๊ณ , ์—ญ์œผ๋กœ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‹ค๋ฅด๋ฉด URI๋„ ๋‹ฌ๋ผ์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

9) ํ•˜์ดํ”ˆ(- )์€ URI ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š”๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

10) ๋ฐ‘์ค„( _ )์€ URI์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

11) URI ๊ฒฝ๋กœ์—๋Š” ์†Œ๋ฌธ์ž๊ฐ€ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

URI ๊ฒฝ๋กœ์— ๋Œ€๋ฌธ์ž ์‚ฌ์šฉ์€ ํ”ผํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. RFC 3986(URI ๋ฌธ๋ฒ• ํ˜•์‹)์€ URI ์Šคํ‚ค๋งˆ์™€ ํ˜ธ์ŠคํŠธ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š”

๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ณ„ํ•˜๋„๋ก ๊ทœ์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

12) ํŒŒ์ผ ํ™•์žฅ์ž๋Š” URI์— ํฌํ•จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Accept header๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ) http://edwith.org/files/java.jpg (X)

์˜ˆ) GET /files/jdk18.exe HTTP/1.1 Host: edwith.org Accept: image/jpg (O)

 

13) ๋ฆฌ์†Œ์Šค ๊ฐ„์— ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.

/๋ฆฌ์†Œ์Šค๋ช…/๋ฆฌ์†Œ์Šค ID/๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค๋ช…

์˜ˆ) GET : /books/{bookid}/viewers (์ผ๋ฐ˜์ ์œผ๋กœ ์†Œ์œ  ‘has’์˜ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•  ๋•Œ)

 

14) ์ž์›์„ ํ‘œํ˜„ํ•˜๋Š” ์ปฌ๋ ‰์…˜(Collection)๊ณผ ๋„ํ๋จผํŠธ(Document)

์ปฌ๋ ‰์…˜์€ ๊ฐ์ฒด์˜ ์ง‘ํ•ฉ, ๋„ํ๋จผํŠธ๋Š” ๊ฐ์ฒด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ปฌ๋ ‰์…˜๊ณผ ๋„ํ๋จผํŠธ ๋ชจ๋‘ ๋ฆฌ์†Œ์Šค๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ URI๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ) http://edwith.org/courses/1 

courses๋Š” ์ปฌ๋ ‰์…˜์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋ณต์ˆ˜๋กœ ํ‘œํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. courses/1 ์€ courses์ค‘์—์„œ id๊ฐ€ 1์ธ ๋„ํ๋จผํŠธ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

 

4. HTTP ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ

์ž˜ ์„ค๊ณ„๋œ REST API๋Š” URI๋งŒ ์ž˜ ์„ค๊ณ„๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ทธ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์‘๋‹ต๋„ ์ž˜ ํ‘œํ˜„๋˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

์ •ํ™•ํ•œ ์‘๋‹ต์˜ ์ƒํƒœ ์ฝ”๋“œ๋งŒ์œผ๋กœ๋„ ๋งŽ์€ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. 

์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” HTTP ์ƒํƒœ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. 

 

5. HATEOAS

์šฐ๋ฆฌ๋Š” ์›น ๊ฒŒ์‹œํŒ์„ ์ด์šฉํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฒŒ์‹œํŒ ๋ชฉ๋ก๋ณด๊ธฐ ํ™”๋ฉด์—์„œ ์ œ๋ชฉ์„ ๋ˆ„๋ฅด๋ฉด ์ƒ์„ธ ๋ณด๊ธฐ ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ธ ๋ณด๊ธฐ ํ™”๋ฉด์—์„œ ๊ธ€์“ฐ๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๊ธ€์“ฐ๊ธฐ ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์›น์ด๋ž€ ํ•˜์ดํผ ๋งํฌ๋ฅผ ํ†ตํ•ด ๊ด€๊ณ„๋œ URL๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

REST API๋ฅผ ์š”์ฒญํ•  ๊ฒฝ์šฐ, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ „๋‹ฌ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ๋Š” ๋ณดํ†ต JSONํ˜•ํƒœ๋กœ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์š”์ฒญ์„ ๋ณด๋ƒˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

GET /books/1

๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{
"id" : 1,
"title" : "hello spring",
"author" : "carami"
"price" : 5000
}



์ด๋ ‡๊ฒŒ ์š”์ฒญ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋‚ด์ค„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๊ฒฐ๊ณผ์— ๊ด€๋ จ๋œ REST API์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ HATEOAS๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค.

HATEOAS๋ž€ ‘Hypermedia As The Engine Of Application State’ ์˜ ์•ฝ์ž์ž…๋‹ˆ๋‹ค.

์•„๋ž˜์˜ JSON๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ‘_links’ ๋ถ€๋ถ„์ด ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์ด HATEOAS๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. 

์ž๊ธฐ ์ž์‹ ์˜ URL, book ์ปฌ๋ ‰์…˜๊ณผ ๊ด€๋ จ๋œ URL, book์ €์žฅ์„ ์œ„ํ•œ URL ๋“ฑ์ด ํ‘œํ˜„๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

{
   "id" : 1,
   "title" : "hello spring",
   "author" : "carami"
   "price" : 5000,
   "_links":{
       "self":{
       "href":"http://localhost:8080/books/1"
       },
       "query-books":{
       "href":"http://localhost/books"
       },
       "write-books":{
       "href":"http://localhost/books"
       }
   }
}

์ด๋ ‡๊ฒŒ, DATA์™€ ํ•จ๊ป˜ ๊ด€๋ จ๋œ URL์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์„ HATEOAS๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค.

 

 

6. REST์™€ ๊ด€๋ จ๋œ ๋…ผ๋ž€

REST API์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ํ‘œ์ค€์€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋ฌธ์ œ๋กœ REST API์™€ ๊ด€๋ จ๋˜์„œ ๋งŽ์€ ๋…ผ์Ÿ์ด ๋ฒŒ์–ด์ง‘๋‹ˆ๋‹ค.

REST API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋“ค์€ ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์„ ๋ชจ๋‘ ์ง€ํ‚ค๋Š” ๊ฒƒ์ด ํž˜๋“ค๊ฒŒ ์ƒ๊ฐํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‹ค๋ณด๋‹ˆ, ๋ชจ๋“  ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์„ ์ง€ํ‚ค์ง€ ์•Š๊ณ  ๊ฐœ๋ฐœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํŠนํžˆ REST์˜ HATEOAS์™€ ์ž์ฒด ํ‘œํ˜„ ๊ตฌ์กฐ(self-descriptiveness)๋ฅผ ๋งŒ์กฑ ๋ชปํ•˜๋„๋ก ๊ฐœ๋ฐœ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ REST API๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜์ง€ ๋ชปํ•  ๊ฒฝ์šฐ๋ฅผ Web API๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์‹œ๊ฐ„์—๋Š” Web API์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 


2) Web API๋ž€?

์ฝ”๋“œ ์‹ค์Šต ๋งํฌ: mvcexam04 

 

REST API ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์„ ์™„๋ฒฝํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜์ง€ ๋ชปํ•  ๊ฒฝ์šฐ ์ด๋ฅผ Web API๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค

 

์šฐ๋ฆฌ๋Š” ์•ž์—์„œ Spring MVC๋ฅผ ์ด์šฉํ•ด ๊ฐ„๋‹จํ•œ Web ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž‘์„ฑํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

http://localhost:8080/mvcexam/plusform ์ด๋ผ๋Š” URL์ฃผ์†Œ๋ฅผ ๋ธŒ๋ผ์šฐ์ €์˜ ์ฃผ์†Œ์ฐฝ์— ์ž…๋ ฅํ•˜๋ฉด, 

2๊ฐœ์˜ ๊ฐ’์„ ์ž…๋ ฅ๋ฐ›๋Š” ํผ(Form)์ด ๋ณด์—ฌ์กŒ๊ณ  ํ•ด๋‹น ํผ์— ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ณ  ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด 2๊ฐœ์˜ ์ˆซ์ž์˜ ํ•ฉ์ด ์ถœ๋ ฅ๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

mvcexam ํ”„๋กœ์ ํŠธ์— ๋ง์…ˆ์„ ๊ตฌํ•˜๋Š” Web API๋ฅผ ์ถ”๊ฐ€ํ•ด๋ด„์œผ๋กœ์จ Web API๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๊ฐ„๋‹จํžˆ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

1 PlusResult.java

PlusResultํด๋ž˜์Šค๋Š” 3๊ฐœ์˜ ์ •์ˆ˜ ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

 

2 PlusApiController.java

package kr.or.connect.mvcexam.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.or.connect.mvcexam.dto.PlusResult;

// Web Api
@Controller
public class PlusApiController {
	@GetMapping("/api/plus")
    @ResponseBody //ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋Š” ๋ทฐ์ด๋ฆ„์„ ๋ฆฌํ„ด(๋ณดํ†ต์€ ๊ทธ๋Ÿผ)ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋ฆฌํ„ดํ•œ ๊ฐ์ฒด๋ฅผ ์ถœ๋ ฅํ•˜๋ผ๋Š” ์˜๋ฏธ
    public PlusResult plus(@RequestParam("value1") int value1, @RequestParam("value2") int value2){
        PlusResult plusResult = new PlusResult();
        plusResult.setValue1(value1);
        plusResult.setValue2(value2);
        plusResult.setResult(value1 + value2);
        return plusResult;
    }
}

์šฐ๋ฆฌ๋Š” ์•ž์—์„œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค์–ด ๋ดค์Šต๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๊ฐ€์ง€๋Š” ๋ฉ”์†Œ๋“œ๋Š” String์„ ๋ฐ˜ํ™˜ํ–ˆ๋˜ ๊ฒƒ ๊ธฐ์–ตํ•˜์‹œ๋‚˜์š”?

์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์†Œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” String๊ฐ’์€ ๋ทฐ(View)์ด๋ฆ„์ด๋‚˜ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์˜๋ฏธํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, ์ง€๊ธˆ ์ž‘์„ฑํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋Š” String์ด ์•„๋‹Œ PlusResult ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

@ResponseBody

@ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น๋ฉ”์†Œ๋“œ๋Š” ๋ทฐ์ด๋ฆ„์„ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ(์ „๊นŒ์ง„ ๊ทธ๋Ÿผ)์ด ์•„๋‹ˆ๋ผ, 

๋ฆฌํ„ดํ•œ ๊ฐ์ฒด๋ฅผ ์ถœ๋ ฅํ•˜๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

 

 

์—ฌ๊ธฐ๊นŒ์ง€ ์ž‘์„ฑ์„ ํ•˜๊ณ  ์„œ๋ฒ„๋ฅผ ์žฌ์‹œ์ž‘ ํ•ฉ๋‹ˆ๋‹ค.

http://localhost:8080/mvcexam/api/plus?value1=10&value2=20

 

3. ์—๋Ÿฌ ๋ฐœ์ƒ

‘No converter found for return value of type: class kr.or.connect.webmvc.dto.PlusResult’

์—๋Ÿฌ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ฉด PlusResult์— ๋Œ€ํ•œ ์ปจ๋ฒ„ํ„ฐ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

DispathcerServlet์€ ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๊ฐ€ ๋ฆฌํ„ดํ•œ ๊ฐ์ฒด๋ฅผ ๋ณ€ํ™˜์‹œํ‚ค๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. 

๋ณ€ํ™˜์„ ์‹œํ‚ฌ ๋•Œ ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ(MessageConverter)๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๊ฐ€ Bean์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ์œ„์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์œ„์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋ ค๋ฉด MessageConverter๋ฅผ Bean์œผ๋กœ ๋“ฑ๋กํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

๋ณดํ†ต Web API๋Š” JSON, XML ๊ณผ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ์— ์•Œ๋งž์€ ํ˜•ํƒœ๋กœ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. 

4. pom.xml ํŒŒ์ผ์— jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ๋˜๋Š” JSON์„ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜์‹œํ‚ฌ ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 

PlusResult๋ฅผ JSON๋ฉ”์‹œ์ง€๋กœ ๋ณ€ํ™˜ํ•ด์ค๋‹ˆ๋‹ค.

 

http://localhost:8080/mvcexam/api/plus?value1=10&value2=20 ํ˜ธ์ถœ ์‹œ

5. {"value1":10,"value2":20,"result":30} - ์ถœ๋ ฅ!

 

๋‹ค์Œ ์‹œ๊ฐ„์—” ์ด๋Ÿฐ Web API๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์ข€ ๋” ์ž์„ธํžˆ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

'Spring > Boost Course Web' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

5.1 ์ƒํƒœ์œ ์ง€๊ธฐ์ˆ  - Cookie & Session  (0) 2020.11.19
4.5 Swagger  (0) 2020.11.19
4.4 Controller  (0) 2020.11.19
4.2 Layered Architecture  (0) 2020.11.19
4.1 Spring MVC  (0) 2020.11.19
3.3 Spring JDBC  (0) 2020.11.19