LUCATHREE.COM

← Back to list
🧐 TIL

JSON API

μž‘μ„±μΌ:
TILTerms

졜근 API κ·œκ²©λ“€μ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ˜ 쀑 JSON APIλΌλŠ” 것을 보게 λ˜μ—ˆλ‹€. REST APIκ°€ 이미 JSON 포맷을 μ‚¬μš©ν•˜κ³  μžˆλŠ”λ° JSON으둜 μ‘λ‹΅ν•˜λ©΄ 그게 JSON API인가 μ‹Άμ—ˆμ§€λ§Œ μ•Œμ•„λ³΄λ‹ˆ κ½€ ν₯λ―Έλ‘œμ›Œμ„œ 정리λ₯Ό ν•΄λ³Έλ‹€.

JSON API

정식 ν‘œκΈ°λŠ” JSON:API μΈλ“―ν•œ 이 ν”„λ‘œν† μ½œμ€ 이름 κ·ΈλŒ€λ‘œ JSON ν˜•μ‹μ„ μ‚¬μš©ν•˜λŠ” ν‘œμ€€ν™”λœ API κ·œκ²©μ΄λ‹€.
2013년에 처음 λ°œμ˜λœλ“―ν•œ ν•΄λ‹Ή ν”„λ‘œν† μ½œμ€ 2015년에 v1.0 이 μ™„μ„±λ˜κ³  2022년에 v1.1이 μ™„μ„±λ˜μ—ˆλ‹€κ³  ν•œλ‹€.
이미 λŒ€λΆ€λΆ„μ˜ μ›Ή API듀이 JSON을 μ‚¬μš©ν•˜κ³ λŠ” μžˆμ§€λ§Œ JSON 데이터 자체의 포맷은 κ°œλ°œμžλ“€λ§ˆλ‹€ λ‹€ λ‹€λ₯΄κ²Œ μ‚¬μš©ν•˜κ³  μžˆλŠ”λ° JSON:APIλŠ” κ·Έ ꡬ쑰와 κ·œμΉ™μ„ λͺ…ν™•ν•˜κ²Œ μ •μ˜ν•œ ν‘œμ€€μ„ μ œμ‹œν•œλ‹€.

JSON:API의 ꡬ쑰

일반적인 REST APIμ—μ„œλŠ” μ„œλ²„λ§ˆλ‹€ JSON 응닡 ν˜•νƒœκ°€ μ œκ°κ°μ΄μ§€λ§Œ JSON:APIλŠ” μ•„λž˜ ν•­λͺ©λ“€μ„ ν‘œμ€€ν™”ν•œλ‹€.
  • data: μ‹€μ œ λ¦¬μ†ŒμŠ€ 데이터
  • atrributes: λ¦¬μ†ŒμŠ€μ˜ 속성
  • relationships: λ‹€λ₯Έ λ¦¬μ†ŒμŠ€μ™€μ˜ 관계
  • included: 관계에 따라 ν¬ν•¨λ˜λŠ” λ‹€λ₯Έ λ¦¬μ†ŒμŠ€
  • meta, links, errors: λΆ€κ°€ 정보, 링크, μ—λŸ¬ 정보 λ“±

JSON:API 응닡 μ˜ˆμ‹œ

{ "links": { "self": "http://example.com/articles", "next": "http://example.com/articles?page[offset]=2", "last": "http://example.com/articles?page[offset]=10" }, "data": [{ "type": "articles", "id": "1", "attributes": { "title": "JSON:API paints my bikeshed!" }, "relationships": { "author": { "links": { "self": "http://example.com/articles/1/relationships/author", "related": "http://example.com/articles/1/author" }, "data": { "type": "people", "id": "9" } }, "comments": { "links": { "self": "http://example.com/articles/1/relationships/comments", "related": "http://example.com/articles/1/comments" }, "data": [ { "type": "comments", "id": "5" }, { "type": "comments", "id": "12" } ] } }, "links": { "self": "http://example.com/articles/1" } }], "included": [{ "type": "people", "id": "9", "attributes": { "firstName": "Dan", "lastName": "Gebhardt", "twitter": "dgeb" }, "links": { "self": "http://example.com/people/9" } }, { "type": "comments", "id": "5", "attributes": { "body": "First!" }, "relationships": { "author": { "data": { "type": "people", "id": "2" } } }, "links": { "self": "http://example.com/comments/5" } }, { "type": "comments", "id": "12", "attributes": { "body": "I like XML better" }, "relationships": { "author": { "data": { "type": "people", "id": "9" } } }, "links": { "self": "http://example.com/comments/12" } }] }
μœ„ μ˜ˆμ‹œλŠ” https://jsonapi.org/ μ—μ„œ λ³΄μ—¬μ£ΌλŠ” κ°€μƒμ˜ λΈ”λ‘œκ·Έ μ‘λ‹΅μœΌλ‘œ articles λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ μš”μ²­ κ²°κ³Όλ‹€. 기본적으둜 νƒ€μž…κ³Ό idλ₯Ό ν¬ν•¨ν•˜κ³ , article 객체에 λŒ€ν•œ 속성 μ •λ³΄λŠ” attributes ν•­λͺ© μ•ˆμ— ν¬ν•¨λ˜μ–΄ μžˆλ‹€.
articles와 μ—°κ΄€λœ λ¦¬μ†ŒμŠ€ νƒ€μž…μœΌλ‘œλŠ” author와 commentsκ°€ μžˆλŠ” 것 같은데, ν•΄λ‹Ή λ¦¬μ†ŒμŠ€λ“€μ˜ 속성은 included ν•­λͺ© μ•„λž˜μ— ν¬ν•¨λ˜μ–΄ λ°˜ν™˜λ˜κ³  μžˆλ‹€.
이렇듯 JSON:APIλŠ” μ—°κ΄€ λ°μ΄ν„°λ“€μ˜ 정보λ₯Ό ν¬ν•¨ν•˜μ—¬ λ°˜ν™˜ν•¨μœΌλ‘œμ¨ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 반볡적인 μš”μ²­μ„ 보내지 μ•Šμ•„λ„ λ˜λ„λ‘ ν•˜κ³  있으며 λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ 정보 및 관계 ꡬ쑰도 μΌκ΄€μ μœΌλ‘œ μ „λ‹¬ν•˜κΈ° λ•Œλ¬Έμ— ν΄λΌμ΄μ–ΈνŠΈ μͺ½ κ΅¬ν˜„μ„ λ‹¨μˆœν™” ν•΄μ€€λ‹€.

JSON:API의 μ£Όμš” κ·œμΉ™

JSON:APIλŠ” 데이터 ꡬ쑰에 λŒ€ν•œ μ •μ˜ 뿐만 μ•„λ‹ˆλΌ API κ·œκ²©μœΌλ‘œμ„œ μ§€μΌœμ•Ό ν•  κ·œμΉ™λ“€μ— λŒ€ν•΄μ„œλ„ λͺ…μ„Έν•˜κ³  μžˆλ‹€.

HTTP λ©”μ†Œλ“œ

기본적으둜 REST 원칙을 μ€€μˆ˜ν•˜μ—¬ μš”μ²­μ— 따라 GET, POST, PATCH, DELETE λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λ„λ‘ ν•˜λ©°, 처리 결과에 따라 μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” HTTP Status Code에 λŒ€ν•œ μ‚¬ν•­κΉŒμ§€ μ •μ˜ν•˜κ³  μžˆλ‹€.

Content-Type

JSON:APIλŠ” 자체 MIME νƒ€μž…μ„ IANA에 λ“±λ‘ν•˜μ—¬ 항상 application/vdn.api+json 을 μ‚¬μš©ν•˜λ„λ‘ ν•˜κ³  μžˆλ‹€.

쿼리 νŒŒλΌλ―Έν„° νŒ¨λ°€λ¦¬

쿼리 νŒŒλΌλ―Έν„° μ‚¬μš©μ‹œ, 곡톡 관심사λ₯Ό κ°–λŠ” 쿼리 νŒŒλΌλ―Έν„°λ₯Ό ν•˜λ‚˜μ˜ 그룹으둜 ν‘œν˜„ν•˜λŠ” 쿼리 νŒŒλΌλ―Έν„° νŒ¨λ°€λ¦¬λΌλŠ” κ°œλ…μ„ μ‚¬μš©ν•˜λ„λ‘ μ œμ•ˆν•˜κ³  μžˆλ‹€.
예λ₯Όλ“€μ–΄ νŽ˜μ΄μ§•μ΄ ν•„μš”ν•œ 경우 νŽ˜μ΄μ§€ λ²ˆν˜Έμ™€ νŽ˜μ΄μ§€ λ‹Ή λ¦¬μ†ŒμŠ€ 개수λ₯Ό 별도 νŒŒλΌλ―Έν„°λ‘œ λΆ„λ¦¬ν•˜λŠ” λŒ€μ‹  μ•„λž˜μ™€ 같은 ꡬ쑰둜 pageλΌλŠ” κ°€μ‘± κ°œλ… μ•„λž˜μ— ν•˜μœ„ 속성듀을 λ‚˜νƒ€λ‚΄μ–΄ μ‚¬μš©ν•œλ‹€.
/?page[offset]=0&page[limit]=10

URL λ””μžμΈ

λ°˜λ“œμ‹œ λ”°λΌμ•Όν•˜λŠ” κ·œμΉ™μ€ μ•„λ‹ˆμ§€λ§Œ JSON:API μ‚¬μš©μ‹œ URL λ””μžμΈμ€ μ–΄λ–»κ²Œ ν•˜λŠ” 것이 쒋은지에 λŒ€ν•œ 지침듀이 ν¬ν•¨λ˜μ–΄ μžˆλ‹€. κΈ°λ³Έμ μœΌλ‘œλŠ” url λ˜ν•œ λ¦¬μ†ŒμŠ€λ₯Ό μ€‘μ‹¬μœΌλ‘œ μ„€κ³„ν•˜μ—¬ 관계λ₯Ό ν‘œν˜„ν•˜λ„λ‘ μΆ”μ²œν•œλ‹€.
// κΈ°λ³Έ λ¦¬μ†ŒμŠ€ 경둜 GET /articles GET /articles/1 // 관계 데이터 직접 쑰회 경둜 GET /articles/1/relationships/author // ν¬ν•¨λœ λ¦¬μ†ŒμŠ€ 쑰회 GET /articles/1/author // 쀑첩 관계 GET /articles/1/comments/2

μ—λŸ¬ 응닡

μš”μ²­μ„ μ œλŒ€λ‘œ μ²˜λ¦¬ν•  수 μ—†μ–΄ μ—λŸ¬λ₯Ό λ°˜ν™˜ν•΄μ•Ό ν•  κ²½μš°μ— λŒ€ν•΄μ„œλ„ JSON:APIλŠ” κ·œμΉ™μ„ μ œμ‹œν•˜κ³  μžˆλ‹€.
기본적으둜 μ΅œμƒμœ„μ— errors ν‚€λ₯Ό 두고 λ°°μ—΄λ‘œ ꡬ쑰화 된 μ—λŸ¬ 정보λ₯Ό ν¬ν•¨μ‹œν‚€λ„λ‘ ν•œλ‹€.
{ "errors": [ { "status": "400", "title": "Invalid Attribute", "detail": "First name must contain at least three characters." } ] }
각 였λ₯˜ κ°μ²΄λŠ” λ‹€μŒ ν•„λ“œλ₯Ό μ„ νƒμ μœΌλ‘œ 포함할 수 μžˆλ‹€.
  • id: μ—λŸ¬ νŠΈλž˜ν‚Ήμ„ μœ„ν•œ 였λ₯˜ μ‹λ³„μž
  • links: 였λ₯˜ μ—°κ΄€ λ¬Έμ„œ 링크
  • status: HTTP μƒνƒœ μ½”λ“œ
  • code: μ„œλ²„ λ‚΄λΆ€μ—μ„œ μ •μ˜ν•œ μ—λŸ¬ μ½”λ“œ
  • title: 였λ₯˜μ˜ 짧은 μš”μ•½
  • detail: 였λ₯˜μ˜ ꡬ체적인 μ„€λͺ…
  • source: 였λ₯˜κ°€ λ°œμƒν•œ 원인 μœ„μΉ˜
  • meta: 좔가적인 μ»¨ν…μŠ€νŠΈ 데이터

νŽ˜μ΄λ„€μ΄μ…˜

κ°€μž₯ 처음 보여쀀 μ˜ˆμ‹œμ—μ„œ λ‚˜νƒ€λ‚˜λ“― νŽ˜μ΄μ§€λ„€μ΄μ…˜ 적용 μ‹œ links ν•„λ“œλ₯Ό μ‚¬μš©ν•΄μ„œ λ¦¬μ†ŒμŠ€ νŽ˜μ΄μ§€λ„€μ΄μ…˜ 링크λ₯Ό μ„ νƒμ μœΌλ‘œ μ œκ³΅ν•  수 μžˆλ‹€. νŽ˜μ΄μ§€λ„€μ΄μ…˜ 링크 제곡 μ‹œμ—λŠ” λ°˜λ“œμ‹œ self, first, last, prev, next ν‚€λ₯Ό μ‚¬μš©ν•΄μ„œ μ œκ³΅ν•΄μ•Ό ν•œλ‹€.
{ "links": { "self": "http://example.com/articles", "next": "http://example.com/articles?page[offset]=2", "last": "http://example.com/articles?page[offset]=10" } }

JSON:API의 μž₯단점

μž₯점

  • ν‘œμ€€ν™”λœ 응닡 ꡬ쑰: λͺ¨λ“  APIκ°€ 같은 ν˜•νƒœλ₯Ό κ°€μ§€λ―€λ‘œ, ν΄λΌμ΄μ–ΈνŠΈ κ΅¬ν˜„μ΄ 쉽닀.
  • λΆˆν•„μš”ν•œ μš”μ²­ κ°μ†Œ: included ν•„λ“œλ‘œ κ΄€λ ¨ 데이터λ₯Ό ν•œ λ²ˆμ— 전달할 수 μžˆλ‹€.
  • κ΄€κ³„ν˜• 데이터 ν‘œν˜„μ΄ 용이: relationshipsλ₯Ό 톡해 관계λ₯Ό λͺ…ν™•νžˆ ν‘œν˜„ν•œλ‹€.
  • μ—λŸ¬ 처리 일관성: errors 포맷을 톡해 κ΅¬μ‘°ν™”λœ μ—λŸ¬λ₯Ό μ „λ‹¬ν•œλ‹€.

단점

  • ꡬ쑰가 λ³΅μž‘ν•˜λ‹€: λ¦¬μ†ŒμŠ€ 관계가 λ³΅μž‘ν•˜μ§€ μ•Šμ€ κ°„λ‹¨ν•œ APIμ—λŠ” κ³Όν•  수 μžˆλ‹€.
  • 초기 μ„€μ • λΆ€λ‹΄: μ œμ‹œν•˜λŠ” ν‘œμ€€μ— 맞좰 응닡을 ν¬λ§·νŒ… ν•˜κΈ°κ°€ λΆ€λ‹΄μŠ€λŸ¬μšΈ 수 μžˆλ‹€.
  • μœ μ—°μ„± μ œν•œ: κ·œμΉ™μ„ λͺ¨λ‘ μ€€μˆ˜ν•˜λ©° μ»€μŠ€ν…€ 응닡 ꡬ쑰λ₯Ό λ§Œλ“€κΈ°κ°€ μ–΄λ €μšΈ 수 μžˆλ‹€.

JSON:API ν™œμš©μ΄ 도움이 될 수 μžˆλŠ” 상황

  • μ—¬λŸ¬ μ’…λ₯˜μ˜ ν΄λΌμ΄μ–ΈνŠΈ(μ›Ή, λͺ¨λ°”일, API ν΄λΌμ΄μ–ΈνŠΈ)κ°€ 동일 APIλ₯Ό μ‚¬μš©ν•˜λŠ” 경우
  • κ΄€κ³„ν˜• 데이터(예: μ‚¬μš©μž ↔ κ²Œμ‹œκΈ€ ↔ λŒ“κΈ€)κ°€ λ§Žμ€ 경우
  • ν”„λ‘ νŠΈμ—”λ“œκ°€ GraphQL처럼 κ΄€κ³„ν˜• μš”μ²­μ„ 많이 ν•˜λŠ” 경우
Β