Apidog

올인원 협업 API 개발 플랫폼

API 설계

API 문서

API 디버깅

API 모킹

자동화 테스트

JSON:API 완벽 가이드: JSON API 스펙 완전 정복

Rebecca Kovács

Rebecca Kovács

Updated on May 19, 2025

REST (Representational State Transfer)는 웹 서비스를 구축하기 위한 기본적인 아키텍처 스타일을 제공합니다. 하지만 요청 및 응답 형식의 많은 측면을 정의하지 않은 채로 남겨둡니다. 이러한 모호성은 불일치, 개발 오버헤드 증가, API 소비자의 학습 곡선 가파름으로 이어질 수 있습니다. 이때 JSON:API가 등장합니다. JSON:API는 JSON으로 API를 구축하기 위한 표준화되고 컨벤션 기반의 접근 방식을 제공하는 사양입니다.

이 종합 가이드는 JSON:API 사양에 대해 깊이 있게 탐구하며 핵심 개념, 구조 및 강력한 기능을 살펴봅니다. 리소스 가져오기, 생성, 업데이트, 삭제, 관계 관리, 오류 처리 및 데이터 전송 최적화를 위한 메커니즘을 분석하여 강력하고 효율적인 API를 설계하고 사용하는 데 필요한 지식을 갖추도록 지원합니다.

💡
멋진 API 문서를 생성하는 훌륭한 API 테스트 도구를 원하십니까?

최대 생산성으로 개발 팀이 함께 작업할 수 있는 통합 올인원 플랫폼을 원하십니까?

Apidog는 귀하의 모든 요구를 충족하며 훨씬 저렴한 가격으로 Postman을 대체합니다!
button

JSON:API를 사용해야 하는 이유: 설명

기술적인 복잡성에 들어가기 전에 JSON:API가 해결하고자 하는 문제를 이해하는 것이 중요합니다. 공유된 컨벤션이 없으면 API 개발자는 종종 상당한 시간을 들여 다음 사항에 대해 논쟁합니다.

  • 페이로드 구조: 리소스와 해당 속성은 어떻게 표현되어야 하는가?
  • 관계 표현: 서로 다른 리소스 간의 링크는 어떻게 전달되어야 하는가?
  • 데이터 가져오기 전략: 클라이언트는 특정 필드를 요청하고, 관련 리소스를 포함하고, 데이터를 정렬, 페이지네이션 및 필터링하는 방법은 무엇인가?
  • 오류 보고: 오류 메시지는 어떤 형식을 따라야 하는가?

JSON:API는 요청 및 응답에 대한 명확하고 일관된 형식을 정의함으로써 이러한 문제를 해결합니다. 이러한 표준화는 몇 가지 주요 이점을 제공합니다.

  • 불필요한 논쟁 감소 (Reduced Bikeshedding): 일반적인 설계 질문에 대한 답변을 제공함으로써 JSON:API는 팀이 API 설계의 사소한 부분에 대해 논쟁하는 대신 애플리케이션의 핵심 비즈니스 로직에 집중할 수 있도록 합니다.
  • 생산성 향상: 표준화된 형식은 API 생산자와 소비자 모두에게 사용자 지정 코드를 줄입니다. 클라이언트 라이브러리는 모든 JSON:API 준수 서비스와 상호 작용하는 데 필요한 많은 상용구 코드를 처리하도록 개발될 수 있습니다.
  • 향상된 검색 가능성 및 사용성: 일관된 링크 구조와 리소스 및 관계의 명확한 구분은 API를 더 쉽게 이해하고 탐색할 수 있도록 합니다.
  • 최적화된 데이터 전송: 스파스 필드셋(sparse fieldsets) 및 복합 문서(compound documents)와 같은 기능을 통해 클라이언트는 필요한 데이터만 요청하여 페이로드 크기를 최소화하고 HTTP 요청 수를 줄일 수 있습니다.
  • 쉬운 캐싱: 이 사양은 표준 HTTP 캐싱 메커니즘 사용을 권장합니다.
  • 언어 독립적: JSON 기반이기 때문에 본질적으로 언어 독립적이며 다양한 기술 스택에 걸쳐 광범위한 채택을 용이하게 합니다.

핵심 개념: JSON:API 문서의 구성 요소

JSON:API의 핵심은 리소스(resources) 개념을 중심으로 돌아갑니다. 리소스는 "아티클", "사용자" 또는 "제품"과 같은 특정 유형의 개별 레코드입니다. 요청이든 응답이든 모든 JSON:API 문서는 특정 구조를 따릅니다.

문서 구조: 최상위 멤버

JSON:API 문서는 다음 최상위 멤버 중 하나 이상을 반드시 포함해야 하는 JSON 객체입니다.

  • data: 문서의 "기본 데이터"입니다. 다음 중 하나일 수 있습니다.
  • 단일 리소스 객체(resource object) (예: 특정 아티클을 가져올 때).
  • 리소스 객체의 배열 (예: 아티클 컬렉션을 가져올 때).
  • 단일 리소스 식별자 객체(resource identifier object) (일대일(to-one) 관계를 나타낼 때).
  • 리소스 식별자 객체의 배열 (일대다(to-many) 관계를 나타낼 때).
  • null (예: 일대일 관계가 비어 있거나 존재하지 않는 단일 리소스에 대한 요청인 경우).
  • 빈 배열 [] (예: 일대다 관계가 비어 있거나 컬렉션 요청 결과가 없는 경우).
  • errors: 처리 오류에 대한 세부 정보를 제공하는 오류 객체(error object)의 배열입니다. errors 멤버가 있는 경우 data 멤버는 없어야 합니다.
  • meta: 사양의 나머지 부분에 맞지 않는 비표준 메타 정보를 포함하는 메타 객체(meta object)입니다.

또한 문서는 다음 최상위 멤버를 포함할 수도 있습니다.

  • jsonapi: 서버 구현을 설명하는 객체입니다. version (지원되는 최고 JSON:API 버전), ext (적용된 확장 기능의 URI 배열), profile (적용된 프로필의 URI 배열)을 포함할 수 있습니다.
  • links: 기본 데이터와 관련된 링크 객체(links object)입니다. 여기에는 자체 링크(self-links), 관련 리소스 링크 및 페이지네이션 링크가 포함될 수 있습니다.
  • included: 기본 데이터 및/또는 서로 관련된 리소스 객체의 배열입니다. 관련 리소스를 사이드로딩하여 HTTP 요청 수를 줄이기 위한 "복합 문서(compound documents)"에 사용됩니다.

리소스 객체: 데이터 표현

리소스 객체는 JSON:API의 초석이며 다음을 반드시 포함해야 합니다.

  • type: 리소스 유형을 식별하는 문자열입니다 (예: "articles", "users"). 이는 리소스의 네임스페이스를 지정하고 서로 다른 유형 간의 ID 충돌을 방지하는 데 도움이 됩니다.
  • id: 해당 유형 내에서 리소스를 고유하게 식별하는 문자열입니다.

리소스 객체는 다음을 포함할 수도 있습니다.

  • attributes: 리소스에 특정한 데이터를 포함하는 속성 객체(attributes object)입니다. attributes 객체의 키는 리소스의 속성(예: 아티클의 "title", "body")을 나타냅니다. 관계는 attributes 객체에 표현되어서는 안 됩니다.
  • relationships: 리소스와 다른 리소스 간의 연결을 설명하는 관계 객체(relationships object)입니다.
  • links: 리소스의 정식 URL을 가리키는 self 링크와 같이 리소스와 관련된 링크를 포함하는 링크 객체입니다.
  • meta: 리소스에 대한 비표준 메타 정보를 포함하는 메타 객체입니다.

리소스 객체 예시:JSON

{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "JSON:API Unveiled",
    "body": "A deep dive into the specification...",
    "created_at": "2025-05-15T10:00:00Z",
    "updated_at": "2025-05-16T14:30:00Z"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "/articles/1/relationships/author",
        "related": "/articles/1/author"
      },
      "data": { "type": "users", "id": "42" }
    },
    "comments": {
      "links": {
        "self": "/articles/1/relationships/comments",
        "related": "/articles/1/comments"
      },
      "data": [
        { "type": "comments", "id": "5" },
        { "type": "comments", "id": "12" }
      ]
    }
  },
  "links": {
    "self": "/articles/1"
  }
}

리소스 식별자 객체

리소스 식별자 객체는 typeid만 포함하는 리소스의 최소 표현입니다. 전체 리소스 객체를 포함하지 않고 다른 리소스로 연결하기 위해 관계 객체 내에서 사용됩니다.

리소스 식별자 객체 예시:JSON

{ "type": "users", "id": "42" }

링크 객체

링크 객체는 API 탐색을 위한 URL을 제공합니다. 일반적인 링크 멤버는 다음과 같습니다.

  • self: 리소스 또는 문서 자체를 나타내는 링크입니다.
  • related: 관련 리소스 또는 컬렉션에 대한 링크입니다. 실제 관련 데이터를 가져오기 위해 관계에서 자주 사용됩니다.
  • 페이지네이션 링크(Pagination Links): 페이지네이션된 컬렉션을 탐색하기 위한 first, last, prev, next.

링크는 다음과 같이 표현될 수 있습니다.

  • URL을 포함하는 단순 문자열.
  • href (문자열 URL)를 반드시 포함해야 하며 선택적으로 rel (관계 유형), describedby (설명 문서 링크), title, type (대상 미디어 유형), hreflangmeta 객체를 포함할 수 있는 링크 객체.

링크 객체 예시 (관계 내):JSON

"links": {
  "self": "http://example.com/articles/1/relationships/author",
  "related": "http://example.com/articles/1/author"
}

메타 객체

메타 객체는 비표준 메타 정보를 포함할 수 있도록 합니다. 이는 임의의 키-값 쌍이 될 수 있습니다. 예를 들어, meta 객체는 데이터와 관련된 저작권 정보 또는 타임스탬프를 포함할 수 있습니다.

메타 객체 예시:JSON

"meta": {
  "copyright": "Copyright 2025 Example Corp.",
  "authors": ["John Doe"]
}

콘텐츠 협상: 올바른 언어로 소통하기

JSON:API는 자체 미디어 유형인 application/vnd.api+json을 정의합니다.

  • Accept 헤더: 클라이언트는 JSON:API 준수 응답을 기대함을 나타내기 위해 application/vnd.api+json 미디어 유형과 함께 이 헤더를 반드시 보내야 합니다. 서버가 Accept 헤더의 어떤 미디어 유형도 만족시킬 수 없는 경우 406 Not Acceptable 상태로 응답해야 합니다.
  • Content-Type 헤더: 클라이언트와 서버는 본문에 JSON:API 문서를 포함하는 모든 요청 및 응답에 대해 application/vnd.api+json 미디어 유형과 함께 이 헤더를 반드시 사용해야 합니다. 요청이 application/vnd.api+json (또는 서버가 지원하는 다른 등록된 미디어 유형) 이외의 Content-Type을 지정하고 본문을 포함하는 경우, 서버는 415 Unsupported Media Type 상태로 응답해야 합니다. 요청이 Content-Type: application/vnd.api+json을 지정했지만 본문이 유효한 JSON:API 문서가 아닌 경우, 서버는 400 Bad Request로 응답해야 합니다.

서버는 표준 콘텐츠 협상을 통해 application/vnd.api+json과 함께 다른 미디어 유형을 지원할 수 있습니다.

데이터 가져오기: 리소스 및 컬렉션 검색

JSON:API는 클라이언트가 필요에 따라 데이터를 정확하게 검색할 수 있는 강력한 메커니즘을 제공합니다.

개별 리소스 가져오기

단일 리소스를 가져오려면 클라이언트는 해당 리소스를 나타내는 엔드포인트에 GET 요청을 보냅니다.

요청:

GET /articles/1

Accept: application/vnd.api+json

성공적인 응답 (200 OK):JSON

{
  "links": {
    "self": "/articles/1"
  },
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API Rocks!"
    }
    // ... other attributes and relationships
  }
}

리소스가 존재하지 않는 경우 서버는 404 Not Found를 반환해야 합니다. 일대일 관련 리소스 링크를 가져왔는데 관계가 비어 있는 경우 기본 데이터는 null이 됩니다.

리소스 컬렉션 가져오기

리소스 컬렉션을 가져오려면 클라이언트는 해당 컬렉션을 나타내는 엔드포인트에 GET 요청을 보냅니다.

요청:

GET /articles

Accept: application/vnd.api+json

성공적인 응답 (200 OK):JSON

{
  "links": {
    "self": "/articles",
    "next": "/articles?page[offset]=10",
    "last": "/articles?page[offset]=50"
  },
  "data": [
    {
      "type": "articles",
      "id": "1",
      "attributes": { "title": "Article 1" }
      // ...
    },
    {
      "type": "articles",
      "id": "2",
      "attributes": { "title": "Article 2" }
      // ...
    }
    // ... more articles
  ]
}

컬렉션이 비어 있는 경우 data 멤버는 빈 배열 []이 됩니다.

관계: 리소스 연결

관계는 대부분의 데이터 모델에서 기본적인 부분입니다. JSON:API는 관계를 정의하고 상호 작용하는 명확한 방법을 제공합니다.

관계 표현

관계는 리소스의 relationships 객체 내에서 정의됩니다. relationships 객체의 각 항목은 고유한 관계("author", "comments" 등)를 나타냅니다.

관계 객체는 다음 중 하나 이상을 반드시 포함해야 합니다.

  • links: selfrelated 링크를 포함합니다.
  • self 링크 (관계 URL)는 관계 자체를 조작할 수 있도록 합니다 (예: 일대다 관계에서 항목 추가/제거). 가져오면 관련 리소스에 대한 리소스 식별자 객체를 반환합니다.
  • related 링크 (관련 리소스 URL)는 관련 리소스 객체를 직접 가져올 수 있도록 합니다.
  • data: 리소스 연결(resource linkage) (리소스 식별자 객체)을 포함합니다.
  • 일대일(to-one) 관계의 경우: 단일 리소스 식별자 객체 또는 null.
  • 일대다(to-many) 관계의 경우: 리소스 식별자 객체의 배열 또는 빈 배열 [].
  • meta: 관계에 대한 비표준 정보를 위한 메타 객체입니다.

"author" (일대일) 및 "comments" (일대다) 관계 예시:JSON

"relationships": {
  "author": {
    "links": {
      "self": "/articles/1/relationships/author",
      "related": "/articles/1/author"
    },
    "data": { "type": "users", "id": "42" }
  },
  "comments": {
    "links": {
      "self": "/articles/1/relationships/comments",
      "related": "/articles/1/comments"
    },
    "data": [
      { "type": "comments", "id": "5" },
      { "type": "comments", "id": "12" }
    ]
  }
}

관계 가져오기

클라이언트는 제공된 링크를 사용하여 관계 자체 또는 관련 리소스에 대한 정보를 가져올 수 있습니다.

관계 연결 가져오기 (self link):

GET /articles/1/relationships/comments

Accept: application/vnd.api+json

이는 아티클 "1"과 관련된 댓글에 대한 리소스 식별자 객체 컬렉션을 반환합니다.

관련 리소스 가져오기 (related link):

GET /articles/1/comments

Accept: application/vnd.api+json

이는 아티클 "1"과 관련된 전체 댓글 리소스 객체 컬렉션을 반환합니다.

데이터 검색 최적화

JSON:API는 대역폭을 최소화하고 클라이언트 측 성능을 향상시키기 위해 데이터 검색 방법을 최적화하는 여러 기능을 제공합니다.

복합 문서: include를 사용하여 HTTP 요청 줄이기

관련 리소스를 가져오기 위해 서버에 여러 번 왕복하는 것을 방지하기 위해 JSON:API는 클라이언트가 include 쿼리 매개변수를 사용하여 관련 리소스를 기본 응답에 포함하도록 요청할 수 있도록 합니다. 그러면 서버는 이러한 리소스를 최상위 included 배열에 사이드로딩합니다.

아티클을 가져오고 해당 작성자 및 댓글을 포함하는 요청:

GET /articles/1?include=author,comments

Accept: application/vnd.api+json

응답 (200 OK):JSON

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": { "title": "..." },
    "relationships": {
      "author": {
        "data": { "type": "users", "id": "42" }
      },
      "comments": {
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    }
  },
  "included": [
    {
      "type": "users",
      "id": "42",
      "attributes": { "name": "John Doe" }
    },
    {
      "type": "comments",
      "id": "5",
      "attributes": { "body": "Great article!" }
    },
    {
      "type": "comments",
      "id": "12",
      "attributes": { "body": "Very informative." }
    }
  ]
}
  • include 매개변수는 쉼표로 구분된 관계 경로 목록을 사용합니다.
  • 점 표기법(예: include=comments.author)을 사용하여 중첩된 관계를 포함할 수 있습니다.
  • 엔드포인트가 include를 지원하지 않으면 400 Bad Request반드시 반환해야 합니다.
  • 서버는 요청되지 않은 리소스를 included 섹션에 포함해서는 안 됩니다.

스파스 필드셋: 필요한 필드만 가져오기

클라이언트는 fields[TYPE] 쿼리 매개변수를 사용하여 주어진 유형의 리소스에 대해 특정 필드(속성 및 관계)만 반환되도록 요청할 수 있습니다. 이는 페이로드 크기를 줄입니다.

아티클을 가져오되 제목과 작성자 관계만 가져오는 요청:

GET /articles?fields[articles]=title,author

Accept: application/vnd.api+json

응답 (200 OK):JSON

{
  "data": [
    {
      "type": "articles",
      "id": "1",
      "attributes": {
        "title": "Article 1"
      },
      "relationships": {
        "author": {
          "data": { "type": "users", "id": "42" }
        }
      }
    }
    // ... other articles with only title and author
  ]
}
  • idtype은 항상 포함됩니다.
  • 클라이언트가 존재하지 않는 필드를 요청하는 경우 서버는 이를 반드시 무시해야 합니다.
  • 클라이언트가 관계인 필드만 요청하는 경우 attributes 멤버는 생략될 수 있습니다.

정렬

클라이언트는 sort 쿼리 매개변수를 사용하여 기본 데이터를 정렬하도록 요청할 수 있습니다.

생성 날짜(내림차순) 및 제목(오름차순)으로 정렬된 아티클을 가져오는 요청:

GET /articles?sort=-created_at,title

Accept: application/vnd.api+json

  • 선행 하이픈(-)은 내림차순을 나타냅니다. 그렇지 않으면 오름차순입니다.
  • 서버는 정렬에 사용할 수 있는 속성을 정의합니다. 지원되지 않는 속성에 대한 정렬 요청은 400 Bad Request를 반환해야 합니다.

페이지네이션

JSON:API는 다양한 페이지네이션 전략을 지원합니다. 사양은 최상위 links 객체에 페이지네이션 링크(first, prev, next, last)가 어떻게 나타나야 하는지를 정의합니다. 실제 페이지네이션 전략(예: 페이지 기반, 오프셋 기반, 커서 기반)은 page[number], page[size], page[offset], page[limit] 또는 page[cursor]와 같은 쿼리 매개변수를 사용하여 서버에 의해 결정됩니다.

페이지 기반 페이지네이션 링크 예시:JSON

"links": {
  "self": "/articles?page[number]=2&page[size]=10",
  "first": "/articles?page[number]=1&page[size]=10",
  "prev": "/articles?page[number]=1&page[size]=10",
  "next": "/articles?page[number]=3&page[size]=10",
  "last": "/articles?page[number]=5&page[size]=10"
}

클라이언트는 자체 페이지네이션 URL을 구성하는 대신 제공된 링크를 사용해야 합니다.

필터링

사양은 데이터 필터링을 위해 filter 쿼리 매개변수를 예약합니다. 하지만 특정 필터링 전략을 의무화하지는 않습니다. 서버는 filter[attribute]=value와 같은 전략 또는 더 복잡한 표현식 기반 필터링을 구현할 수 있습니다.

예시 (JSON:API에서 권장하지만 의무 사항은 아님):

GET /comments?filter[post]=1 (ID가 1인 게시물의 댓글 가져오기)

GET /comments?filter[post]=1,2&filter[author]=12 (게시물 1 또는 2의 댓글을 작성자 12가 작성한 것으로 가져오기)

클라이언트는 API의 문서를 참조하여 특정 필터링 기능을 이해해야 합니다.

데이터 수정: 리소스 생성, 업데이트 및 삭제

JSON:API는 데이터 조작 작업에 대한 명확한 프로토콜을 정의합니다.

리소스 생성

리소스를 생성하려면 클라이언트는 리소스 컬렉션을 나타내는 URL에 POST 요청을 보냅니다. 요청 본문은 type과 선택적으로 attributesrelationships를 포함하는 단일 리소스 객체를 반드시 포함해야 합니다. 클라이언트는 새 리소스에 대한 id를 제공해서는 안 됩니다 (클라이언트 생성 ID가 지원되고 활성화된 경우는 제외).

요청:

POST /articles

Accept: application/vnd.api+json

Content-Type: application/vnd.api+jsonJSON

{
  "data": {
    "type": "articles",
    "attributes": {
      "title": "New Article Title",
      "body": "Content of the new article."
    },
    "relationships": {
      "author": {
        "data": { "type": "users", "id": "42" }
      }
    }
  }
}

성공적인 응답:

  • 201 Created: 리소스가 성공적으로 생성된 경우. 응답은 새로 생성된 리소스의 URL을 식별하는 Location 헤더를 반드시 포함해야 합니다. 응답 본문은 서버 할당 id를 포함하여 새로 생성된 리소스를 포함해야 합니다.
  • 202 Accepted: 생성 요청이 처리를 위해 수락되었지만 처리가 아직 완료되지 않은 경우 (예: 비동기 작업). 응답에는 상태를 모니터링하기 위한 링크가 포함될 수 있습니다.
  • 204 No Content: 리소스가 성공적으로 생성되었지만 서버가 응답 본문에 리소스 표현을 반환하지 않기로 선택한 경우. Location 헤더는 여전히 필요합니다.

이미 존재하는 클라이언트 생성 ID로 리소스를 생성하려는 시도가 있고 서버가 POST를 통한 업데이트를 지원하지 않는 경우, 서버는 409 Conflict반드시 반환해야 합니다.

리소스 업데이트

리소스는 PATCH HTTP 메서드를 사용하여 업데이트됩니다. 요청에는 업데이트할 리소스의 id반드시 포함되어야 합니다. 요청 본문에는 type, id, 그리고 업데이트할 attributes 및/또는 relationships를 포함하는 리소스 객체가 포함됩니다.

아티클의 제목과 관계 중 하나를 업데이트하는 요청:

PATCH /articles/1

Accept: application/vnd.api+json

Content-Type: application/vnd.api+jsonJSON

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "Updated Article Title"
    },
    "relationships": {
      "tags": {
        "data": [
          { "type": "tags", "id": "3" },
          { "type": "tags", "id": "4" }
        ]
      }
    }
  }
}

업데이트의 주요 사항:

  • 부분 업데이트: PATCH 요청은 부분적이어야 합니다. 요청에 있는 필드만 업데이트되어야 합니다. 포함되지 않은 필드는 변경되지 않고 유지되어야 합니다.
  • 관계 업데이트:
  • 일대일(To-one): 관계의 data에 리소스 식별자 객체 또는 null을 제공합니다.
  • 일대다(To-many): 리소스 식별자 객체의 배열을 제공합니다. 이는 기존 관계 멤버를 완전히 대체합니다. 전체 세트를 대체하지 않고 멤버를 추가하거나 제거하려면 전용 관계 엔드포인트(/articles/1/relationships/tags)를 POST(추가), DELETE(제거) 또는 PATCH(전체 대체)와 함께 사용해야 합니다.
  • 서버는 요청에 지정되지 않은 속성 또는 관계를 업데이트해서는 안 됩니다.

성공적인 응답:

  • 200 OK: 업데이트가 성공적이고 서버가 업데이트된 리소스의 표현을 반환하는 경우.
  • 202 Accepted: 업데이트 요청이 처리를 위해 수락되었지만 아직 완료되지 않은 경우.
  • 204 No Content: 업데이트가 성공적이지만 서버가 표현을 반환하지 않기로 선택한 경우.

업데이트할 리소스가 존재하지 않는 경우 서버는 404 Not Found반드시 반환해야 합니다.

관계를 직접 업데이트하기

JSON:API는 기본 리소스의 속성에 영향을 주지 않고 관계를 관리하는 특정 방법을 제공합니다.

  • 일대일 관계 업데이트:PATCH /articles/1/relationships/authorContent-Type: application/vnd.api+jsonJSON
{
  "data": { "type": "users", "id": "24" } // Assign new author or null to clear
}
  • 일대다 관계 업데이트 (완전 대체):PATCH /articles/1/relationships/commentsContent-Type: application/vnd.api+jsonJSON
{
  "data": [
    { "type": "comments", "id": "101" },
    { "type": "comments", "id": "102" }
  ]
}
  • 일대다 관계에 추가:POST /articles/1/relationships/commentsContent-Type: application/vnd.api+jsonJSON
{
  "data": [
    { "type": "comments", "id": "103" }
  ]
}
  • 일대다 관계에서 제거:DELETE /articles/1/relationships/commentsContent-Type: application/vnd.api+jsonJSON
{
  "data": [
    { "type": "comments", "id": "5" }
  ]
}

관계 업데이트가 성공하면 일반적으로 200 OK 또는 204 No Content를 반환합니다.

리소스 삭제

리소스를 삭제하려면 클라이언트는 해당 리소스의 엔드포인트에 DELETE 요청을 보냅니다.

요청:

DELETE /articles/1

Accept: application/vnd.api+json

성공적인 응답:

  • 204 No Content: 삭제가 성공적이고 응답 본문이 반환되지 않은 경우.
  • 200 OK: 서버가 삭제에 대한 메타 정보를 반환하는 경우.
  • 202 Accepted: 삭제 요청이 처리를 위해 수락된 경우.

리소스가 존재하지 않는 경우 서버는 404 Not Found를 반환해야 합니다. 사양은 삭제 시 관련 리소스 또는 관계가 어떻게 처리되어야 하는지(예: 연쇄 삭제) 지시하지 않습니다. 이는 구현 세부 사항입니다.

오류 처리

오류가 발생하면 서버는 적절한 HTTP 상태 코드(클라이언트 오류의 경우 4xx, 서버 오류의 경우 5xx)를 반드시 사용해야 합니다. 응답 본문은 JSON:API 오류 문서를 포함해야 합니다.

오류 문서는 오류 객체 배열인 최상위 errors 멤버를 포함합니다. 각 오류 객체는 다음을 포함할 수 있습니다.

  • id: 이 특정 문제 발생에 대한 고유 식별자입니다.
  • links: 다음을 포함하는 링크 객체입니다.
  • about: 이 특정 문제 발생에 대한 추가1 세부 정보로 연결되는 링크입니다.
  • type: 이 특정 오류가 인스턴스인 오류 유형을 식별하는 링크입니다.
  • status: 이 문제에 적용 가능한 HTTP 상태 코드이며 문자열로 표현됩니다.
  • code: 애플리케이션별 오류 코드이며 문자열로2 표현됩니다.
  • title: 문제에 대한 짧고 사람이 읽을 수 있는 요약입니다.3
  • detail: 이 특정 문제 발생에 대한 사람이 읽을 수 있는 설명입니다.
  • source: 요청 문서에서 오류 소스에 대한 참조를 포함하는 객체입니다.4
  • pointer: 요청 문서의 관련 엔티티에 대한 JSON 포인터 [RFC6901]입니다.
  • parameter: 오류를 발생시킨 URI 쿼리 매개변수를 나타내는 문자열입니다.
  • header:5 오류를 발생시킨 단일 요청 헤더의 이름을 나타내는 문자열입니다.
  • meta: 오류에 대한 비표준 메타 정보를 포함하는 메타 객체입니다.

오류 응답 예시 (422 Unprocessable Entity):JSON

{
  "errors": [
    {
      "status": "422",
      "source": { "pointer": "/data/attributes/email" },
      "title": "Invalid Attribute",
      "detail": "The email address is not valid."
    },
    {
      "status": "422",
      "source": { "pointer": "/data/relationships/author" },
      "title": "Invalid Relationship Value",
      "detail": "Author with ID '999' does not exist."
    }
  ]
}

서버 측 고려 사항 및 모범 사례

핵심 사양은 포괄적이지만 JSON:API는 URL 설계 및 멤버 명명과 같은 측면에 대한 권장 사항도 제공합니다.

URL 설계

  • 리소스 컬렉션에는 복수 명사를 사용합니다 (예: /articles).
  • 개별 리소스에는 /articles/{id}를 사용합니다.
  • 관계 자체 링크에는 /articles/{id}/relationships/{relationshipName}를 사용합니다.
  • 관련 리소스 링크에는 /articles/{id}/{relationshipName}를 사용합니다.

멤버 명명

  • 멤버 이름(키)은 카멜 케이스(예: firstName)이거나 단어 구분 기호로 하이픈/밑줄을 사용해야 합니다 (예: first-name 또는 first_name). API 내에서 일관성이 중요합니다. 사양 자체는 자체 쿼리 매개변수에 대해 케밥 케이스(kebab-case)를 사용합니다 (예: page[number]).
  • 멤버 이름은 ASCII 영숫자, 하이픈 및 밑줄만 포함해야 합니다.

사양 확장: 확장 기능 및 프로필

JSON:API는 진화하는 요구 사항과 특정 사용 사례를 충족하도록 확장 가능하게 설계되었습니다.

확장 기능

확장 기능은 기본 사양에서 다루지 않는 새로운 기능을 도입할 수 있습니다. 예를 들어, "Atomic Operations" 확장 기능은 단일 원자적 요청으로 여러 작업(생성, 업데이트, 삭제)을 수행할 수 있도록 합니다. 클라이언트와 서버 모두 확장 기능을 사용하려면 이해해야 합니다. 서버가 지원되지 않는 확장 기능을 포함하는 요청을 받으면 적절한 오류로 반드시 응답해야 합니다.

프로필

프로필은 특정 사용 사례(예: 타임스탬프를 처리하는 특정 방법 또는 일반적인 meta 속성 집합)에 대해 기본 사양 위에 일련의 컨벤션을 정의합니다. 확장 기능과 달리 프로필은 한쪽에서 이해하지 못해도 안전하게 무시할 수 있습니다. 이는 핵심 사양을 변경하거나 보편적인 지원을 의무화하지 않고도 일반적인 패턴에 대한 상호 운용성을 촉진하기 위한 것입니다.

서버는 최상위 jsonapi 객체에서 지원되는 확장 기능 및 프로필을 광고할 수 있습니다. 이를 통해 클라이언트는 이러한 기능을 검색하고 그에 따라 요청을 조정할 수 있습니다.

JSON:API의 미래

JSON:API는 커뮤니티의 기여와 새로운 API 설계 과제를 해결해야 하는 필요성에 의해 계속 발전하고 있습니다. 설정보다 컨벤션, 효율성 및 개발자 경험에 대한 초점은 최신 API 구축을 위한 선도적인 표준으로서의 입지를 굳혔습니다. JSON:API를 채택함으로써 개발 팀은 모호성을 크게 줄이고 상호 운용성을 향상시키며 API 개발 및 소비 속도를 가속화할 수 있습니다.

이 상세한 탐구는 JSON:API 사양의 대부분을 다룹니다. 이러한 원칙을 이해하고 구현함으로써 개발자는 기능적일 뿐만 아니라 깔끔하고 일관적이며 작업하기 즐거운 API를 만들 수 있으며, 궁극적으로 보다 생산적이고 협력적인 API 생태계를 조성할 수 있습니다.