Kind of Magic
μ΄μ μ DAO λμ Spring Data JPA μ JpaRepository λ₯Ό μ¬μ©νμ¬ DAO λ₯Ό μ¬μ©ν¨μ λ°λΌ λ°μνλ boiler-plate code μ λ¬Έμ λ₯Ό ν΄κ²°νλ€. κ·Έλ°λ°, μ¬κΈ°μ λ ν° λ§λ²μ μνν μ μλ€.
REST Controller λ Spring Data REST μ μνμ¬ λ체λ μ μλ€.
Spring Data REST
Spring Data REST λ μλμ endpoints λ₯Ό μλμΌλ‘ expose ν΄μ€λ€.
| HTTP Method | URI | CRUD Action |
|---|---|---|
| POST | /employees | Create a new employee |
| GET | /employees | Read a list of employees |
| GET | /employees/{employeeId} | Read a single employee |
| PUT | /employees/{employeeId} | Update an existing employee |
| PATCH | /employees/{employeeId} | Partially update an employee |
| DELETE | /employees/{employeeId} | Delete an existing employee |
Spring Data REST λ κΈ°λ³Έμ μΌλ‘ simple plurailized form, μ¦ entity type μ 볡μνμ ννλ‘ endpoints λ₯Ό expose νλ€.
Spring Boot κ° μ€νλλ©΄, Spring Data REST κ° JPA Repository interface λ₯Ό μ€μΊνμ¬ μλμΌλ‘ REST Controller λ₯Ό Proxy ννλ‘ μμ±νλ€.
μ¬μ© λ°©λ²μ λ κ°λ¨νλ€. λ¨μν Maven POM file μ spring-boot-starter-data-rest λ₯Ό μΆκ°ν΄μ£Όλ©΄ λμ΄λ€. λ μ΄μμ code λ νμνμ§ μλ€.
κ²°κ³Όμ μΌλ‘ νλ©΄μ μΈ Application Architecture κ° λ€μκ³Ό κ°μ΄ κ°λ¨ν΄μ§λ€.

HATEOAS
Spring Data REST μμ μλμΌλ‘ μμ±λλ endpoints(REST API) λ HATEOAS μμΉμ μ€μνλ€.
HATEOAS(Hypermedia As The Engine Of Application State) λ REST API μ ν κ΅¬μ± μμλ‘,Β Server κ° Client μκ² data λΏλ§ μλλΌ κ·Έ data μ κ΄λ ¨λ μΆκ°μ μΈ νλ(λ€μμ νΈμΆν μ μλ API link λ±)μ λν μ 보λ₯Ό Hypermedia(link) ννλ‘ ν¨κ» μ 곡νλ κ°λ μ΄λ€.
μ¦, Client κ° Server μ response λ₯Ό λ°μ λ, λ¨μν data λ§ λ°λ κ²μ΄ μλλΌ κ·Έ μνμμ μ·¨ν μ μλ λ€λ₯Έ νλ(μ: update, delete, λ€μ νμ΄μ§ μ΄λ λ±)μ λν URI link λ ν¨κ» λ°μ, Client κ° λ³λμ API document λ₯Ό 보μ§μκ³ λ Server μ dynamic νκ² μνΈμμ©ν μ μκ² ν΄μ€λ€.
μλ₯Ό λ€μ΄, κΈ°μ‘΄μ REST reqest κ° λ€μκ³Ό κ°λ€λ©΄,
{
"id": 10,
"subject": "κ²μκΈ 10",
"content": "λ΄μ©"
}HATEOAS κ° μ μ©λ request λ
{
"id": 100,
"subject": "κ²μκΈ 10",
"content": "λ΄μ©",
"_links": {
"self": { "href": "https://api.example.com/articles/10" },
"next": { "href": "https://api.example.com/articles/11" },
"comment": { "href": "https://api.example.com/articles/10/comments"}
}
}
κ³Ό κ°κΈ° λλ¬Έμ, μ΄μ²λΌ request μ ν¬ν¨λ link λ₯Ό λ°λΌ Client κ° μ½κ² State Transition, μ¦ νμ΄μ§ λ΄μμ λ€λ₯Έ νλμ νλλ‘ λμμ€λ€.
Redirection νκ³ λ λ€λ₯Έ κ²μ΄, Redirection μ Server κ° Client λ₯Ό μλμΌλ‘ λ€λ₯Έ URL λ‘ μ΄λμν€λ, HATEOAS λ response μ link(href) λ₯Ό ν¬ν¨μμΌ Client κ° μ§μ μ΄λνκ² νλ κ²μ΄λ€.
λ§μ½ GET /employees μ κ°μ΄ collection, μ¦ μ¬λ¬ κ°μ data λ₯Ό request νλ κ²μ λν response μλ κΈ°μ‘΄μ data λΏλ§ μλλΌ, page size, total elements, totalPages λ±μ meta-data λ response μ ν¬ν¨λλ€. μ΄λ Pagination(page μ΄λ, λ€μ/μ΄μ νμ΄μ§) μ ꡬννκ±°λ, μ 체 data μμ νμ
νλ λ° λμμ΄ λλ€.
Advanced Features
Spring Data REST μ advanced features λ λ€μκ³Ό κ°λ€.
- Pagination, sorting and searching
- Extending and adding custom quries with JPQL
- Query Domain Specific Language (Query DSL)
Spring Data REST - Test
μμ κ°μ΄ GET /employees endpoint κ° expose λ κ²μ λ³Ό μ μλ€.
application.properties μ λ€μ property λ₯Ό μΆκ°νμ¬ base path λ λ³κ²½ κ°λ₯νλ€.
spring.data.rest.base-path=/magic-api
μμ κ°μ΄ λ³κ²½λ base path μ λνμ¬ POST method λ μ μ μ©λλ€.
λν, PUT μ΄λ PATCH method λ₯Ό μ¬μ©ν λ, Spring Data REST λ id λ₯Ό μ€μ§ URL μμλ§ μ¬μ© κ°λ₯νλ€. λ§μ½ id κ°μ request body μ ν¬ν¨μν¨λ€λ©΄, μ΄μ λν μνμ±μ μ¬κΈ°μ νμΈ κ°λ₯νλ€. λ¨μνκ²λ§ μ€λͺ
νλ©΄, Client κ° κ³ μμ μΌλ‘λ μ€μλ‘ κΈ°μ‘΄ data λ₯Ό λ³κ²½μν¬ μ μκΈ° λλ¬Έμ΄λ€.
μμ κ°μ΄ PUT method λ μ μλνλ κ²μ λ³Ό μ μλ€.
PATCH λ μ μλνλ©°, μλμ κ°μ΄ DELETE λ μ±κ³΅μ μΌλ‘ μλνλ€.
DELETE μμ, μ΄μ μ Spring Boot version μμλ default λ‘ 204 No Content λ₯Ό return νμμ§λ§, μ΅κ·Όμ Spring Boot version μμλ 200 OK λ₯Ό default λ‘ return νλ€.
μ΅κ·Ό Spring Boot λ₯Ό κΈ°μ€μΌλ‘, request header μ Accept variable μ΄ μ‘΄μ¬νμ§ μμ λλ§ 204 No Content λ₯Ό return νκ±°λ λ³λμ configuration μ ν΅νμ¬ return κ°μ ν μ μλ€. λ³λμ configuration λ° λ μμΈν λ΄μ©μ μ¬κΈ°μ νμΈν μ μλ€.
Postman μ ν΅νμ¬ Accept variable μ μ€μ νμ§ μμΌλ©΄ μλμ κ°μ΄ 204 No Content κ° return λλ κ²μ λ³Ό μ μλ€.
