Sanity HTTP API

Sanity HTTP API

Sanity의 HTTP API는 Sanity Client, Studio 같은 앱들이 Content Lake와 상호작용할 때 실제로 쓰는 API를 그대로 노출해 주는 엔드포인트 집합이에요. 우리가 따로 클라이언트 라이브러리를 안 쓰고 curl이라든지 HTTP 요청만으로 데이터를 읽고, 만들고, 수정하고, 지울 수 있다는 뜻이에요. 다만 공식 문서에서도 강조하듯 가능하면 HTTP API를 직접 다루기보다는 공식 클라이언트 라이브러리를 쓰는 걸 권장해요 — 다만 API의 동작 방식 자체를 이해하면 클라이언트 라이브러리가 편하게 감춰 준 일들을 정확히 알 수 있어요.

기본적으로 프로젝트 ID, 데이터셋 이름, API 버전, 그리고 인증 토큰이 있으면 어떤 요청이든 바로 보낼 수 있어요. 이 문서에서는 참조 문서(Query API · Mutation API · Doc API)에서 쿼리와 문서 CRUD, 인증, 응답 형식에 해당하는 핵심 내용을 정리할게요.

출처: 문서

본문

인증과 기본 URL

대부분의 엔드포인트는 Bearer 토큰 인증(BearerAuth)을 요구해요. 특히 drafts, 버전, 또는 private 데이터셋에 대한 요청은 반드시 인증이 필요해요. 문서를 수정하는 Mutation API도 모든 요청이 인증을 요구하고, 해당 문서 타입에 대해 읽기+쓰기 권한(보통 Editor, Developer, Administrator 역할)이 있어야 해요.

기본 URL은 프로젝트 ID와 API 버전으로 구성돼요.

https://{projectId}.api.sanity.io/{apiVersion}
Variable Default Description
projectId projectId Project ID
apiVersion v2025-02-19 API version

Query API — GROQ로 데이터 읽기

Query API는 GROQ로 Content Lake를 조회하는 엔드포인트예요. 기본 쿼리 엔드포인트부터 살펴볼게요.

GET https://{projectId}.api.sanity.io/{apiVersion}/data/query/{dataset}

브라우저의 URL 길이 제한 때문에 GET 쿼리는 11KB로 상한이 있어요. URL이 더 길어지면 반드시 POST로 보내야 해요. 이 엔드포인트는 문서를 못 찾아도 GROQ가 어차피 값을 평가하므로 404를 반환하지 않는다는 점도 기억해 두세요.

  • *[_id == "missing"] 결과는 []
  • count(*[_type == "typoType"]) 결과는 0
  • *[_id == "missing"][0] 결과는 null
  • *[_id == "missing"][0].someProp 결과도 null

Query parameters

Name Type Required Description
query string Yes The GROQ query itself
explain boolean | string (enum) No Whether to include the query execution plan as plain text in an explain field
resultSourceMap boolean No If true, the query result will include content source map metadata
perspective string No Runs the query against the selected perspective: drafts, published, raw, or a comma-separated release stack
tag string No Request tags for filtering log data
returnQuery boolean No If false, the response will not include the submitted query. Default: true
$-prefixed string No GROQ parameter submitted as normal url-params (dollar-sign prefixed in query)

성공하면 200 응답으로 아래 형식의 QueryResponse가 와요.

Property Type Required Description
ms number Server-side processing time
query string Submitted query
result Query result (can be any valid JSON value)
syncTags string[]
{
  "ms": 12,
  "query": "*[_type == 'movie']",
  "result": [
    {
      "_id": "movie1",
      "title": "Inception"
    }
  ],
  "syncTags": [
    "movie1"
  ]
}

쿼리 문법이 틀리면 400과 함께 파싱 에러 정보를 돌려줘요.

{
  "error": {
    "query": "*[",
    "description": "Expected ']' following expression",
    "start": 1,
    "end": 2,
    "type": "queryParseError"
  }
}

POST 방식

POST https://{projectId}.api.sanity.io/{apiVersion}/data/query/{dataset}

11KB가 넘는 쿼리는 POST로 보내야 하고, POST로 보낸 쿼리는 CDN에도 캐시돼요. 이때는 JSON 바디에 query와 선택적으로 params를 담아요. JSON으로 보낼 때는 $ 접두사를 쓰지 않아요.

{
  "query": "*[_type == 'movie' && language == $language]",
  "params": {
    "language": "es"
  }
}

CDN을 써서 edge-cached 결과를 받으려면 apicdn 엔드포인트도 있어요.

https://{projectId}.apicdn.sanity.io/v{YYYY-MM-DD}/data/query/{dataset}

Mutation API — 문서 CRUD

Mutation API는 Content Lake에서 문서를 만들고, 수정하고, 삭제하는 저수준 인터페이스예요. 트랜잭션 방식이라 여러 mutation을 한 배열로 보내면 성공했을 때 모든 mutation이 실행됐다고 보장받을 수 있어요.

POST https://{projectId}.api.sanity.io/{apiVersion}/data/mutate/{dataset}

Query parameters

Name Type Required Description
returnIds boolean No If true, the id's of modified documents are returned. Default: false
returnDocuments boolean No If true, the entire content of changed documents is returned. Default: false
autoGenerateArrayKeys boolean No Adds a _key attribute to array items so each can be addressed uniquely. Default: false
transactionId string No Set your own transaction ID (must be unique in the dataset)
skipCrossDatasetReferencesValidation boolean No Treat cross-dataset references as weak. Default: false
visibility string No sync, async, or deferred. Default: "sync"
dryRun boolean No If true, the mutation will be validated but not executed
tag string No Request tags for filtering log data

Mutation 타입

지원하는 mutation은 다섯 가지예요.

  • create — 지정 또는 자동 생성된 ID로 새 문서를 만들어요. 이미 존재하면 실패.
  • createOrReplace — 새로 만들거나 기존 문서를 교체해요.
  • createIfNotExists — 없을 때만 만들고, 있으면 조용히 무시해요.
  • delete — ID 또는 GROQ 쿼리로 문서를 삭제해요.
  • patchset, setIfMissing, unset, inc, dec, insert, diffMatchPatch 같은 연산으로 기존 문서를 업데이트해요. 문서가 없으면 실패.

여러 patch를 함께 넣으면 실행 순서는 set → setIfMissing → unset → inc → dec → insert 순서예요.

Mutation 예시

{
  "mutations": [
    {
      "create": {
        "_id": "123",
        "_type": "cms.article",
        "title": "An article"
      }
    },
    {
      "createOrReplace": {
        "_id": "456",
        "_type": "cms.article",
        "title": "Another article"
      }
    },
    {
      "delete": {
        "id": "789"
      }
    },
    {
      "patch": {
        "id": "123",
        "set": {
          "title": "Updated title"
        },
        "inc": {
          "viewCount": 1
        }
      }
    }
  ]
}

deletepatch는 ID 대신 GROQ 쿼리로 대상 문서를 고를 수도 있어요. 쿼리로 여러 문서를 지울 때는 최대 10,000개까지 동작하고, 더 큰 집합은 여러 트랜잭션으로 나누는 걸 권장해요. 또 _id로 페이지네이션하는 패턴(*[_type == "article" && _id > $lastId])을 추천해요. 낙관적 잠금이 필요하면 ifRevisionID로 현재 revision과 일치하지 않으면 실패하게 만들 수도 있어요.

{
  "delete": {
    "query": "*[_type == 'feature' && viewCount < $views]",
    "params": {
      "views": 5
    }
  }
}
{
  "patch": {
    "query": "*[_type == 'person' && points >= $threshold]",
    "params": {
      "threshold": 100
    },
    "dec": {
      "points": 100
    },
    "inc": {
      "bonuses": 1
    }
  }
}

Mutation 응답 (200)

Property Type Required Description
transactionId string Unique identifier for the transaction
results MutationResult[] Results of each mutation
results[].operation string The type of mutation performed
results[].documentId string The ID of the affected document
{
  "transactionId": "txn_123456",
  "results": [
    {
      "operation": "create",
      "documentId": "123"
    },
    {
      "operation": "createOrReplace",
      "documentId": "456"
    },
    {
      "operation": "delete",
      "documentId": "789"
    },
    {
      "operation": "patch",
      "documentId": "123"
    }
  ]
}

Doc API — 캐시를 우회한 단건 조회

Doc API는 문서를 ID로 조회하면서 캐싱 레이어를 우회하는 엔드포인트예요. 백엔드가 알고 있는 최신 버전을 확실하게 가져오고 싶을 때 쓰지만, 캐싱을 우회하면 예상치 못한 사용량이 생길 수 있어서 조심해서 써야 해요. 일반적인 조회는 캐시가 되는 Query API를 쓰는 게 좋아요.

GET https://{projectId}.api.sanity.io/{apiVersion}/data/doc/{dataset}/{documentId}

Query parameter Type Required Description
includeAllVersions boolean No If true, include all versions of the document, including drafts and releases. Default: false

성공하면 documents 배열에 Sanity 문서 모양의 객체(모든 비-null 필드 포함)를 돌려줘요.

Property Type Required Description
documents object[]
documents[]._id string
documents[]._type string

실무 팁

  • HTTP API를 직접 쓰는 대신 가급적 공식 클라이언트 라이브러리를 쓰는 걸 권장해요. 번거로운 인증과 직렬화를 안전하게 처리해 줘요.
  • GET 쿼리는 11KB 제한이 있으니 긴 GROQ는 POST로 보내고, POST 쿼리는 CDN 캐시를 함께 노리면 좋아요.
  • Mutation은 트랜잭션이라 한 번에 묶어 보내면 부분 적용 걱정 없이 안전해요. 대량 쓰기는 visibility=deferred가 가장 빠른 방식이에요.
  • 다만 위 내용은 참조 문서 발췌 정리라, 정확하고 최신 엔드포인트·응답은 공식 문서를 확인하는 게 좋아요.

더 알아보기 (Learn more)