μ΄ νμ΄μ§λ HATEOASμ μν€νΌλμ νλͺ©μ HTMLμ μ¬μ©ν΄ μ¬κ΅¬μ±ν κ²μ λλ€. μ΄ μ€λͺ μ JSON APIμ λΉκ΅νλ©΄μ κ°λ μ μ€λͺ νλ©°, μν€νΌλμμ μ ν©ν μ€λ¦½μ μΈ μ€λͺ 보λ€λ λ€μ μκ²¬μ΄ λ€μ΄κ° μ€λͺ μ΄μ§λ§, μ°λ¦¬μ κ΄μ μμλ λ μ ννλ€κ³ μκ°ν©λλ€.
μ ν리μΌμ΄μ μνμ μμ§μΌλ‘μμ νμ΄νΌλ―Έλμ΄(Hypermedia as the Engine of Application State, HATEOAS)λ REST μ ν리μΌμ΄μ μν€ν μ²μ μ μ½ μ€ νλλ‘, μ΄λ₯Ό λ€λ₯Έ λ€νΈμν¬ μ ν리μΌμ΄μ μν€ν μ²μ κ΅¬λΆ μ§μ΅λλ€.
HATEOASμμλ ν΄λΌμ΄μΈνΈκ° μ ν리μΌμ΄μ μλ²κ° λμ μΌλ‘ μ 곡νλ νμ΄νΌλ―Έλμ΄λ₯Ό ν΅ν΄ λ€νΈμν¬ μ ν리μΌμ΄μ κ³Ό μνΈμμ©ν©λλ€. REST ν΄λΌμ΄μΈνΈλ νμ΄νΌλ―Έλμ΄μ λν μΌλ°μ μΈ μ΄ν΄ μ΄μΈμλ μ ν리μΌμ΄μ μ΄λ μλ²μ μνΈμμ©νλ λ°©λ²μ λν΄ κ±°μ λλ μ ν μ¬μ μ§μμ΄ νμνμ§ μμ΅λλ€.
λ°λ©΄μ μ€λλ μ JSON κΈ°λ° μΉ ν΄λΌμ΄μΈνΈλ μ£Όλ‘ μ€μ¨κ±°(swagger)μ κ°μ λꡬλ₯Ό ν΅ν΄ λ¬Έμνλ κ³ μ λ μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μνΈμμ©ν©λλ€.
HATEOASκ° λΆκ³Όνλ μ μ½μ ν΄λΌμ΄μΈνΈμ μλ²λ₯Ό λΆλ¦¬μμΌ μ€λλ€. μ΄λ μλ² κΈ°λ₯μ΄ λ 립μ μΌλ‘ λ°μ ν μ μκ² ν΄μ€λλ€.
HTTPλ₯Ό ꡬνν μ¬μ©μ μμ΄μ νΈκ° κ°λ¨ν URLμ ν΅ν΄ REST μλν¬μΈνΈμ HTTP μμ²μ 보λ λλ€. μ¬μ©μ μμ΄μ νΈκ° μνν μ μλ λͺ¨λ νμ μμ²μ κ° μμ²μ λν νμ΄νΌλ―Έλμ΄ μλ΅μμ λ°κ²¬λ©λλ€. μ΄λ¬ν ννμ μ¬μ©λλ λ―Έλμ΄ νμ κ³Ό κ·Έλ€μ΄ ν¬ν¨ν μ μλ λ§ν¬ κ΄κ³λ νμ€νλμ΄ μμ΅λλ€. ν΄λΌμ΄μΈνΈλ νμ΄νΌλ―Έλμ΄ νν λ΄μ λ§ν¬λ₯Ό μ ννκ±°λ ν΄λΉ λ―Έλμ΄ νμ μ΄ μ 곡νλ λ€λ₯Έ λ°©λ²μΌλ‘ ννμ μ‘°μν¨μΌλ‘μ¨ μ ν리μΌμ΄μ μνλ₯Ό μ νν©λλ€.
μ΄λ κ² RESTful μνΈμμ©μ μΈλΆ μ λ³΄κ° μλ νμ΄νΌλ―Έλμ΄μ μν΄ κ΅¬λλ©λλ€.
ꡬ체μ μΈ μλ₯Ό ν΅ν΄ μ΄λ₯Ό λͺ νν ν΄λ³΄κ² μ΅λλ€. μΉ λΈλΌμ°μ κ° μν κ³μ’ 리μμ€λ₯Ό κ°μ Έμ€λ GET μμ²μ λ°ννλ€κ³ κ°μ ν΄ λ΄ μλ€:
GET /accounts/12345 HTTP/1.1
Host: bank.example.com
μλ²λ HTMLμ μ¬μ©ν νμ΄νΌλ―Έλμ΄ ννμΌλ‘ μλ΅ν©λλ€:
HTTP/1.1 200 OK
<html>
<body>
<div>κ³μ’ λ²νΈ: 12345</div>
<div>μμ‘: $100.00 USD</div>
<div>λ§ν¬:
<a href="/accounts/12345/deposits">μ
κΈ</a>
<a href="/accounts/12345/withdrawals">μΆκΈ</a>
<a href="/accounts/12345/transfers">μ΄μ²΄</a>
<a href="/accounts/12345/close-requests">κ³μ’ νμ μμ²</a>
</div>
<body>
</html>
μ΄ μλ΅μλ λ€μκ³Ό κ°μ κ°λ₯ν νμ μμ μ΄ ν¬ν¨λμ΄ μμ΅λλ€: μ κΈ, μΆκΈ, μ΄μ²΄λ₯Ό μν΄ UIλ‘ μ΄λνκ±°λ κ³μ’ νμ μμ²μ ν μ μμ΅λλ€.
λμ€μ κ³μ’κ° μ΄κ³Ό μΈμΆλ νμ μν©μ μκ°ν΄ λ΄ μλ€. μ΄μ μ΄ κ³μ’ μν λ³νλ‘ μΈν΄ μ¬μ© κ°λ₯ν λ§ν¬ μΈνΈκ° λ¬λΌμ§λλ€.
HTTP/1.1 200 OK
<html>
<body>
<div>κ³μ’ λ²νΈ: 12345</div>
<div>μμ‘: -$50.00 USD</div>
<div>λ§ν¬:
<a href="/accounts/12345/deposits">μ
κΈ</a>
</div>
<body>
</html>
μ΄μ μ¬μ© κ°λ₯ν λ§ν¬λ νλλΏμ λλ€: λ λ§μ λμ μ κΈνλ λ§ν¬μ λλ€. νμ¬ μ΄κ³Ό μΈμΆ μνμ κ³μ’μμλ λ€λ₯Έ μμ μ μνν μ μμΌλ©°, μ΄ μ¬μ€μ νμ΄νΌλ―Έλμ΄μ λ΄ν¬λμ΄ μμ΅λλ€. μΉ λΈλΌμ°μ λ μ΄κ³Ό μΈμΆ κ³μ’μ κ°λ μ΄λ κ³μ’κ° λ¬΄μμΈμ§μ‘°μ°¨ μμ§ λͺ»ν©λλ€. λ¨μ§ νμ΄νΌλ―Έλμ΄ ννμ μ¬μ©μμκ² νμνλ λ°©λ²λ§ μκ³ μμ λΏμ λλ€.
λ°λΌμ μ°λ¦¬λ μ ν리μΌμ΄μ μνμ μμ§μΌλ‘μμ νμ΄νΌλ―Έλμ΄λΌλ κ°λ μ κ°κ² λ©λλ€. 리μμ€μ μνκ° λ³ν¨μ λ°λΌ κ°λ₯ν μμ μ΄ λ¬λΌμ§λ©°, μ΄ μ 보λ νμ΄νΌλ―Έλμ΄μ μΈμ½λ©λ©λλ€.
μμ HTML μλ΅κ³Ό μΌλ°μ μΈ JSON APIλ₯Ό λΉκ΅ν΄λ³΄λ©΄, JSON APIλ λμ κ³μ’μ μν νλλ₯Ό ν¬ν¨νλ ννμ λ°νν κ²μ λλ€:
HTTP/1.1 200 OK
{
"account": {
"account_number": 12345,
"balance": {
"currency": "usd",
"value": -50.00
},
"status": "overdrawn"
}
}
μ¬κΈ°μ ν΄λΌμ΄μΈνΈλ status
νλμ κ°μ΄ 무μμ μλ―Ένλμ§, μ΄κ²μ΄ μ¬μ©μ μΈν°νμ΄μ€μ λ λλ§μ μ΄λ€ μν₯μ λ―ΈμΉ μ§μ λν΄ λͺ
νν μκ³ μμ΄μΌ ν©λλ€.
ν΄λΌμ΄μΈνΈλ λν μλ΅μ μΈμ½λ©λμ§ μμ 리μμ€λ₯Ό μ‘°μνκΈ° μν URLλ μκ³ μμ΄μΌ ν©λλ€. μ΄λ μΌλ°μ μΌλ‘ JSON APIμ λν λ¬Έμλ₯Ό μ°Έμ‘°νμ¬ μ΄λ£¨μ΄μ§λλ€.
μ΄λ κ² μΈλΆ μ λ³΄κ° νμν μ μ΄ μ΄ JSON APIλ₯Ό HATEOASλ₯Ό ꡬννλ RESTful APIμ κ΅¬λΆ μ§λ μμμ λλ€.
μ΄ μμλ λ κ°μ§ μ κ·Ό λ°©μμ ν΅μ¬μ μΈ μ°¨μ΄λ₯Ό 보μ¬μ€λλ€: RESTful, HATEOAS HTML ννμμλ λͺ¨λ μμ μ΄ μλ΅μ μ§μ μΈμ½λ©λ©λλ€. λ°λ©΄ JSON API μμμμλ μ격 리μμ€λ₯Ό μ²λ¦¬νκ³ μμ νλ λ° μΈλΆ μ λ³΄κ° νμν©λλ€.
HATEOAS μ μ½μ Roy Fieldingμ λ°μ¬ λ Όλ¬Έμ μ μλ RESTμ βν΅μΌλ μΈν°νμ΄μ€β κΈ°λ₯μ νμμ μΈ λΆλΆμ λλ€. Fieldingμ λ Όλ¬Έμ μ£Όλ‘ HTMLκ³Ό HTTPλ‘ κ΅¬μ±λ μ΄κΈ° μΉ μν€ν μ²μ λν λ Όμμμ΅λλ€.
Fieldingμ μμ μ λΈλ‘κ·Έμμ νμ΄νΌλ―Έλμ΄μ κ°λ κ³Ό κ·Έ μ€μν μꡬ μ¬νμ λν΄ λ μμΈν μ€λͺ νμ΅λλ€.
μ°Έκ³ : μ΄ μΉμ μ μ€λ¦½μ μΈ μ΄μ‘°λ λ Όμμ μ¬μ§κ° μμ΅λλ€.
2000λ λ μ΄λ°μ REST κ°λ μ μ΄κΈ° μΉμ μ€λͺ μΌλ‘μμ κ°λ μ νκ²½μμ λ²μ΄λ XML API κ°λ°(μ£Όλ‘ SOAPμ μ¬μ©) λ° JSON API κ°λ°κ³Ό κ°μ λ€λ₯Έ μΉ κ°λ° λΆμΌλ‘ λμ λμμ΅λλ€. μ΄λ XMLμ΄λ JSONμ΄ HTMLκ³Ό κ°μ μμ°μ€λ¬μ΄ νμ΄νΌλ―Έλμ΄κ° μλμλ λΆκ΅¬νκ³ μ΄λ£¨μ΄μ‘μ΅λλ€.
μ΄ μλ‘μ΄ μμμμ RESTμ λν μ€μ μμ€μ νΉμ§μ§κΈ° μν΄ λ¦¬μ²λμ¨ μ±μλ λͺ¨λΈμ΄ μ μλμμ΅λλ€. μ΄ λͺ¨λΈμ κ°μ₯ λμ μμ€(Level 3)μ βνμ΄νΌλ―Έλμ΄ μ»¨νΈλ‘€βλ‘ κ΅¬μ±λ©λλ€.
JSONμ μμ°μ€λ¬μ΄ νμ΄νΌλ―Έλμ΄κ° μλλ―λ‘, νμ΄νΌλ―Έλμ΄ κ°λ μ JSON μμ κ°μ λ‘ μΆκ°λ μλ°μ μμ΅λλ€. 리μ²λμ¨ μ±μλ λͺ¨λΈμ Level 3μ μΆ©μ‘±νλ €λ JSON μμ§λμ΄λ μμ μν κ³μ’ μμμ ν΄λΉνλ λ€μ JSONμ λ°νν μ μμ΅λλ€:
HTTP/1.1 200 OK
{
"account": {
"account_number": 12345,
"balance": {
"currency": "usd",
"value": 100.00
},
"links": {
"deposits": "/accounts/12345/deposits",
"withdrawals": "/accounts/12345/withdrawals",
"transfers": "/accounts/12345/transfers",
"close-requests": "/accounts/12345/close-requests"
}
}
}
μ¬κΈ°μμ βνμ΄νΌλ―Έλμ΄ μ»¨νΈλ‘€βμ κ³μ κ°μ²΄μ links
μμ±μ μΈμ½λ©λμ΄ μμ΅λλ€.
νμ§λ§ μ΄ APIμ ν΄λΌμ΄μΈνΈλ μ¬μ ν μλΉν μΆκ° μ 보λ₯Ό μμμΌ ν©λλ€:
GET
μμ²μ 보λ΄μ ν΄λΉ λ³κ²½ μ¬νμ ννμ λ°μ μ μλκ°?POST
μμ²μ ν μ μλ€λ©΄, μ΄λ€ κ°λ€μ΄ κΈ°λλλκ°?μμ JSONμ 첫 λ²μ§Έ HTML μμμ μλ /accounts/12345/deposits
λ§ν¬λ₯Ό ν΄λ¦ν ν λΈλΌμ°μ μμ κ°μ Έμ¨ λ€μ HTTP μλ΅κ³Ό λΉκ΅ν΄ 보μΈμ:
HTTP/1.1 200 OK
<html>
<body>
<form method="post" action="/accounts/12345/deposits">
<input name="amount" type="number" />
<button>Submit</button>
</form>
<body>
</html>
μ΄ HTML μλ΅μ κ³μ’ μμ‘μ μ
λ°μ΄νΈνλ λ° νμν λͺ¨λ μ 보λ₯Ό μΈμ½λ©νκ³ μμΌλ©°, form
μμμ method
μ action
μμ±μ΄ ν¬ν¨λμ΄ μμΌλ©°,
리μμ€λ₯Ό μ¬λ°λ₯΄κ² μ
λ°μ΄νΈνλ λ° νμν μ
λ ₯ νλλ₯Ό μ 곡ν©λλ€.
JSON ννμλ HTML ννμμμ κ°μ μ체 ν¬ν¨λ βν΅μΌλ μΈν°νμ΄μ€βκ° μμ΅λλ€.
JSON APIκ° RESTful κ°λ μμ μΌλ§λ λ©λ¦¬ λ²μ΄λλλΌλ, μ΄λ₯Ό βRESTβλΌκ³ λΆλ₯΄λ κ²μ λν΄ Roy Fieldingμ λ€μκ³Ό κ°μ΄ λ§νμ΅λλ€:
HTTP κΈ°λ°μ λͺ¨λ μΈν°νμ΄μ€λ₯Ό REST APIλΌκ³ λΆλ₯΄λ μ¬λλ€μ΄ λ무 λ§μμ§λ©΄μ λλ μ μ μ’μ νκ³ μμ΅λλ€. μ€λμ μμλ SocialSite REST APIμ λλ€. κ·Έκ²μ RPCμ λλ€. μμ ν RPCλ‘ λ³΄μ λλ€. λ무 λ§μ κ²°ν©μ΄ λλ¬λ μμ΄μ X λ±κΈμ λ°μμΌ ν μ λμ λλ€.
JSON APIμ λ 볡μ‘ν νμ΄νΌλ―Έλμ΄ μ»¨νΈλ‘€μ λμ νλ €λ μλκ° μμμ§λ§, μ λ°μ μΌλ‘ μ κ³λ HATEOASμ RESTful μν€ν μ²μ λ€λ₯Έ μμλ€μ ν¬κΈ°νκ³ λ κ°λ¨ν RPC μ€νμΌμ APIλ₯Ό μ νΈνμ΅λλ€.
μ΄ μ¬μ€μ HTMLκ³Ό κ°μ μμ°μ€λ¬μ΄ νμ΄νΌλ―Έλμ΄κ° RESTful μμ€ν μ ꡬμΆνλ λ° μ€μ§μ μΌλ‘ νμμ μ΄λΌλ μ£Όμ₯μ κ°λ ₯ν λ·λ°μΉ¨ν©λλ€.