RFC 10008 HTTP QUERY 메서드 2026년 6월
Reschke 외 표준 트랙 [페이지]
스트림:
인터넷 엔지니어링 태스크 포스(IETF)
RFC:
10008
범주:
표준 트랙
발행:
ISSN:
2070-1721
저자:
J. Reschke
greenbytes
J.M. Snell
Cloudflare
M. Bishop
Akamai

RFC 10008

HTTP QUERY 메서드

초록

이 명세는 HTTP의 QUERY 메서드를 정의합니다. QUERY는 요청 대상이 포함된 콘텐츠를 안전하고 멱등적인 방식으로 처리한 다음 해당 처리 결과로 응답하도록 요청합니다. 이는 POST 요청과 유사하지만, QUERY 요청은 부분적인 상태 변경을 우려하지 않고 자동으로 반복하거나 다시 시작할 수 있습니다.

이 메모의 상태

이 문서는 인터넷 표준 트랙 문서입니다.

이 문서는 인터넷 엔지니어링 태스크 포스 (IETF)의 산출물입니다. IETF 커뮤니티의 합의를 나타냅니다. 이 문서는 공개 검토를 거쳤으며 인터넷 엔지니어링 운영 그룹 (IESG)의 발행 승인을 받았습니다. 인터넷 표준에 관한 자세한 정보는 RFC 7841의 섹션 2에서 확인할 수 있습니다.

이 문서의 현재 상태, 정오표 및 이에 대한 피드백 제공 방법에 관한 정보는 https://www.rfc-editor.org/info/rfc10008에서 확인할 수 있습니다.

목차

1. 소개

이 명세는 대상 리소스가 요청을 처리하는 방법을 설명하는 표현을 포함하는 안전하고 멱등적인 요청([HTTP]의 섹션 9.2)을 수행하는 수단으로 HTTP QUERY 요청 메서드를 정의합니다.

일반적인 쿼리 패턴은 다음과 같습니다.

GET /feed?q=foo&limit=10&sort=-published HTTP/1.1
Host: example.org

그러나 전달되는 데이터가 요청 URI에 인코딩하기에 너무 많으면 이 패턴에는 문제가 생깁니다.

GET을 사용하는 대신, 많은 구현에서는 아래 예제에 나온 것처럼 HTTP POST 메서드를 사용하여 쿼리를 수행합니다. 이 경우 쿼리 작업의 입력은 요청 URI의 쿼리 구성 요소를 사용하는 대신 요청 콘텐츠로 전달됩니다.

쿼리를 요청하기 위한 HTTP POST의 일반적인 사용 예는 다음과 같습니다.

POST /feed HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded

q=foo&limit=10&sort=-published

그러나 이 변형에서는 요청이 전송되는 리소스와 서버에 대한 구체적인 지식이 없으면 안전하고 멱등적인 쿼리가 수행되고 있다는 사실을 쉽게 알 수 없습니다.

QUERY 메서드는 GET과 POST 사용 사이의 간극을 메우는 해결책을 제공하며, 위 예제는 다음과 같이 표현됩니다.

QUERY /feed HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded

q=foo&limit=10&sort=-published

POST와 마찬가지로 쿼리 작업의 입력은 요청 URI의 일부가 아니라 요청의 콘텐츠로 전달됩니다. 그러나 POST와 달리 이 메서드는 명시적으로 안전하고 멱등적이므로 캐싱 및 자동 재시도와 같은 기능을 사용할 수 있습니다.

중요한 리소스라면 URI로 식별되어야 한다는 설계 원칙을 고려하여, 이 명세는 서버가 나중에 GET 요청에서 사용할 수 있도록 쿼리 자체 또는 특정 쿼리 결과에 URI를 할당하는 방법을 설명합니다.

요약하면 다음과 같습니다.

표 1: 관련 메서드 속성 요약
GET QUERY POST
안전함 아닐 수 있음
멱등적 아닐 수 있음
쿼리 자체의 URI 예(정의상) 선택 사항(Location 응답 필드) 아니요
쿼리 결과의 URI 선택 사항(Content-Location 응답 필드) 선택 사항(Content-Location 응답 필드) 선택 사항(Content-Location 응답 필드)
캐시 가능 예, 단 향후 GET 또는 HEAD 요청에만 해당
콘텐츠(본문) "정의된 의미 체계 없음" 예상됨(의미 체계는 대상 리소스에 따름) 예상됨(의미 체계는 대상 리소스에 따름)

1.1. 용어

이 문서는 [HTTP]의 섹션 3에 정의된 용어를 사용합니다.

또한 URI의 쿼리 구성 요소([HTTP]의 섹션 4.2.2)에 있는 매개변수를 URI 쿼리 매개변수라고 하고, QUERY 요청의 요청 콘텐츠([HTTP]의 섹션 6.4)를 쿼리 콘텐츠라고 합니다.

1.2. 표기 규칙

이 문서의 핵심 단어 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY" 및 "OPTIONAL"은 여기에 표시된 것처럼 모두 대문자로 나타나는 경우에만 BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석해야 합니다.

2. QUERY 메서드

QUERY 메서드는 서버 측 쿼리를 시작하는 데 사용됩니다. 대상 URI로 식별되는 리소스의 표현을 요청하는 GET 메서드 ([HTTP]의 섹션 7.1에 정의됨)와 달리, QUERY 메서드는 대상 리소스에 해당 대상 리소스의 범위 내에서 쿼리 작업을 수행하도록 요청하는 데 사용됩니다.

요청 콘텐츠와 해당 미디어 유형이 쿼리를 정의합니다. 오리진 서버는 대상 리소스를 기반으로 작업 범위를 결정합니다.

Content-Type 요청 필드([HTTP], 섹션 8.3)가 없거나 요청 콘텐츠와 일치하지 않으면 서버는 요청을 MUST 실패 처리해야 합니다.

모든 HTTP 메서드와 마찬가지로 대상 URI의 쿼리 부분은 쿼리 대상 리소스를 식별하는 데 관여합니다. 이것이 쿼리 결과에 직접 영향을 미치는지 여부와 그 방식은 리소스에 따라 다르며 이 명세의 범위를 벗어납니다.

QUERY 요청은 대상 리소스에 대해 안전합니다 ([HTTP], 섹션 9.2.1). 즉, 클라이언트는 대상 리소스의 상태 변경을 요청하거나 기대하지 않습니다. 그렇다고 해서 서버가 추가 정보를 검색할 수 있는 추가 HTTP 리소스를 생성하지 못하는 것은 아닙니다(섹션 2.32.4 참조).

또한 QUERY 요청은 멱등적입니다 ([HTTP], 섹션 9.2.2). 예를 들어 연결 실패 후와 같이 필요할 때 다시 시도하거나 반복할 수 있습니다.

[HTTP]의 섹션 15.3에 따라, 2xx(성공) 응답 코드는 요청이 성공적으로 수신되고 이해되었으며 수락되었음을 나타냅니다.

특히 200(OK) 응답은 쿼리가 성공적으로 처리되었으며 그 처리 결과가 응답 콘텐츠에 포함되어 있음을 나타냅니다.

2.1. 미디어 유형 및 콘텐츠 협상

QUERY 요청의 의미 체계는 요청 콘텐츠와 미디어 유형([HTTP], 섹션 8.3.1) 같은 관련 메타데이터 모두에 따라 달라집니다. 일반적으로 콘텐츠와 메타데이터가 일치하지 않는 요청의 모든 문제는 4xx(클라이언트 오류) 응답([HTTP], 섹션 15.5)으로 MUST 거부해야 합니다.

아래 목록에서는 다양한 실패 사례를 설명하고 특정 상태 코드를 권장합니다.

  • 요청에 미디어 유형 정보가 없으면 정의상 잘못된 요청이므로 400(클라이언트 오류)과 같은 4xx 상태 코드로 실패해야 합니다.
  • 미디어 유형이 지정되었지만 리소스에서 지원하지 않는 경우에는 415(지원되지 않는 미디어 유형)가 적절합니다. 여기에는 특히 미디어 유형 자체는 알려져 있지만 대상 리소스에 대한 QUERY에 특화된 의미 체계가 없는 경우가 포함됩니다. 두 경우 모두 Accept-Query 응답 필드(섹션 3)를 사용하여 지원되는 미디어 유형을 클라이언트에 알릴 수 있습니다.
  • 미디어 유형이 지정되었지만 실제 요청 콘텐츠와 일치하지 않으면 400(Bad Request)을 반환할 수 있습니다. 즉, 서버는 요청 콘텐츠에서 미디어 유형을 추론한 다음 누락되었거나 "잘못된" 값을 재정의할 수 없습니다 (즉, "콘텐츠 스니핑").
  • 미디어 유형이 지정되고 이해되었으며 콘텐츠도 실제로 해당 유형과 일치하지만 쿼리의 실제 내용 때문에 쿼리를 처리할 수 없는 경우에는 422(처리할 수 없는 콘텐츠) 상태를 사용할 수 있습니다. 예를 들어 구문상 올바르지만 존재하지 않는 테이블을 식별하는 SQL 쿼리가 이에 해당합니다.
  • 클라이언트가 Accept 필드([HTTP], 섹션 12.5.1)를 사용하여 리소스에서 지원하지 않는 특정 응답 미디어 유형을 요청하는 경우 406(Not Acceptable) 상태 코드가 적절합니다.

2.2. 동등한 리소스

특정 QUERY 요청의 동등한 리소스는 GET 요청에 응답하고, 해당 QUERY 요청과 그 대상을 나타내며, 메시지 콘텐츠와 메타데이터 모두를 고려하는 리소스입니다([HTTP]의 섹션 6). 특히 여기에는 콘텐츠의 미디어 유형과 같은 표현 메타데이터([HTTP]의 섹션 8)가 포함됩니다.

다시 말해 동등한 리소스는 요청 콘텐츠를 포함함으로써 QUERY를 구현하는 리소스에서 파생됩니다.

동등한 리소스라는 용어는 선택된 표현과 같은 다른 HTTP 측면의 동작을 정의하기 위한 수단으로 사용됩니다. 서버는 이러한 리소스에 URI를 할당할 수 있지만 반드시 할당할 필요는 없습니다( [URI]의 섹션 1.1 참조). URI를 할당하면 이러한 리소스는 GET 요청으로 접근할 수 있게 됩니다.

2.3. Content-Location 응답 필드

성공 응답(2xx, [HTTP]의 섹션 15.3)에는 작업 결과에 해당하는 리소스의 식별자를 포함하는 Content-Location 헤더 필드가 포함될 수 있습니다. 자세한 내용은 [HTTP]의 섹션 8.7을 참조하십시오. 이는 클라이언트가 표시된 URI에 GET 요청을 보내 방금 수행한 쿼리 작업의 결과를 검색할 수 있다는 서버의 주장을 나타냅니다. 표시된 리소스는 임시일 수 있습니다.

예제는 부록 A.4.1을 참조하십시오.

2.4. Location 응답 필드

서버는 QUERY 요청의 동등한 리소스(섹션 2.2)에 URI를 할당할 수 있습니다. 서버가 그렇게 하는 경우 해당 리소스의 URI를 2xx 응답의 Location 헤더 필드에 포함할 수 있습니다([HTTP]의 섹션 10.2.2 참조). 이는 클라이언트가 표시된 URI에 GET 요청을 보내 쿼리 콘텐츠를 다시 보내지 않고도 방금 수행한 쿼리 작업을 반복할 수 있다는 주장을 나타냅니다. 이 리소스의 URI는 임시일 수 있으며, 이후 요청이 실패하면 클라이언트는 원래 QUERY 요청 대상과 이전에 제출한 콘텐츠를 사용하여 다시 시도할 수 있습니다.

예제는 부록 A.4.2를 참조하십시오.

2.5. 리디렉션

경우에 따라 서버는 사용자 에이전트를 다른 URI로 리디렉션하여 QUERY 요청에 간접적으로 응답하도록 선택할 수 있습니다( [HTTP]의 섹션 15.4 참조).

상태 코드 301(Moved Permanently, [HTTP], 섹션 15.4.2) 또는 308(Permanent Redirect, [HTTP], 섹션 15.4.9) 중 하나가 있는 응답은 대상 리소스가 Location 응답 필드([HTTP], 섹션 10.2.2)에서 참조하는 다른 URI로 영구적으로 이동했음을 나타냅니다. 마찬가지로 상태 코드 302(Found, [HTTP], 섹션 15.4.3) 또는 307(Temporary Redirect, [HTTP], 섹션 15.4.8) 중 하나가 있는 응답은 대상 리소스가 일시적으로 이동했음을 나타냅니다. 네 경우 모두 서버는 사용자 에이전트가 Location에서 참조하는 새 대상 URI로 유사한 QUERY 요청을 보내 원래 QUERY 요청을 수행할 수 있음을 제안합니다.

301 또는 302 응답 후 POST를 GET 요청으로 리디렉션하는 예외는 QUERY 요청에 적용되지 않는다는 점에 유의하십시오.

상태 코드 303(See Other, [HTTP]의 섹션 15.4.4)이 있는 QUERY 응답은 원래 쿼리를 Location 응답 필드([HTTP], 섹션 10.2.2)에서 참조하는 URI에 대한 일반적인 검색 요청을 통해 수행할 수 있음을 나타냅니다. HTTP에서는 부록 A.4.3의 예제처럼 새 대상 URI로 GET 요청을 보내는 것을 의미합니다.

2.6. 조건부 요청

QUERY 요청의 선택된 표현([HTTP]의 섹션 3.2)은 해당 QUERY 요청의 동등한 리소스(섹션 2.2)에 대한 GET 요청의 표현과 동일합니다.

조건부 QUERY는 선택된 표현(즉, 콘텐츠 협상 이후의 쿼리 결과)을 [HTTP]의 섹션 13에 정의된 조건부 헤더 필드에서 설명하는 상황에서만 응답으로 반환하도록 요청합니다.

예제는 부록 A.5를 참조하십시오.

2.7. 캐싱

QUERY 메서드에 대한 응답은 캐시할 수 있으며, 캐시는 MAY [HTTP-CACHING]의 섹션 4에 따라 이후 QUERY 요청을 충족하는 데 사용할 수 있습니다.

QUERY 요청의 캐시 키([HTTP-CACHING]의 섹션 2)에는 요청 콘텐츠([HTTP-CACHING]의 섹션 6)와 관련 메타데이터([HTTP]의 섹션 8)가 MUST 포함되어야 합니다.

캐시 효율성을 높이기 위해 캐시는 MAY 먼저 요청 콘텐츠와 관련 메타데이터에서 의미상 중요하지 않은 차이를 제거할 수 있습니다. 예를 들면 다음과 같습니다.

  • 콘텐츠 인코딩 제거([HTTP]의 섹션 8.4).
  • 요청의 Content-Type 필드에 있는 미디어 하위 유형 접미사(예: "+json"; [RFC6838]의 섹션 4.2.8 참조)가 나타내는 형식 규칙에 대한 지식을 기반으로 정규화.
  • 요청의 Content-Type 필드가 나타내는 콘텐츠 자체의 의미 체계에 대한 지식을 기반으로 정규화.

이러한 변환은 전적으로 캐시 키 생성 목적으로만 수행되며, 요청 자체를 변경하지 않는다는 점에 유의하십시오.

클라이언트는 "no-transform" 캐시 지시문([HTTP-CACHING]의 섹션 5.2.1.6)을 사용하여 이러한 변환이 발생하지 않기를 원한다는 것을 나타낼 수 있습니다(다만 이 지시문은 권고적일 뿐이라는 점에 유의하십시오).

QUERY 메서드 응답의 캐싱은 캐시 키를 결정하기 위해 요청 콘텐츠를 완전히 읽어야 하므로 본질적으로 GET 응답을 캐싱하는 것보다 더 복잡하다는 점에 유의하십시오. QUERY 응답이 동등한 리소스(섹션 2.2)의 URI를 나타내기 위해 Location 응답 필드(섹션 2.4)를 제공하는 경우 클라이언트는 이후 요청에 GET을 사용하여 처리를 단순화할 수 있습니다.

2.8. 범위 요청

QUERY의 범위 요청 의미 체계는 [HTTP]의 섹션 14에 정의된 GET의 의미 체계와 동일합니다. 그러나 바이트 범위 요청(작성 시점에 정의된 유일한 범위 단위)은 QUERY 요청의 결과에는 거의 가치가 없습니다.

쿼리 형식은 흔히 SQL의 "FETCH FIRST ... ROWS ONLY"와 같이 결과 집합을 제한하거나 페이지 단위로 처리하는 자체 방식을 정의합니다. 이러한 내장 기능이 HTTP 범위 요청 대신 사용될 것으로 예상됩니다.

3. Accept-Query 헤더 필드

"Accept-Query" 응답 헤더 필드는 리소스에서 사용할 수 있는 특정 쿼리 형식 미디어 유형을 식별하면서 QUERY 메서드 지원을 직접 알리는 데 사용할 수 있습니다.

Accept-Query에는 "Structured Fields" 구문 [STRUCTURED-FIELDS]을 사용하는 미디어 범위([HTTP]의 섹션 12.5.1) 목록이 포함됩니다. 미디어 범위는 매개변수가 없는 미디어 범위 값을 포함하는 Token 또는 String의 List Structured Header Field로 표현됩니다.

미디어 유형 매개변수가 있는 경우 String 또는 Token 유형의 Structured Field Parameter에 매핑됩니다. Token과 String 중 어느 것을 선택하는지는 의미상 중요하지 않습니다. 즉, 수신자는 MAY Token을 String으로 변환할 수 있지만, 수신된 유형에 따라 다르게 처리해서는 MUST NOT 안 됩니다.

미디어 유형은 Token에 정확히 매핑되지 않습니다. 예를 들어 선행 숫자를 허용합니다. 이러한 경우에는 String 형식을 사용해야 합니다.

지원되는 와일드카드 사용은 모든 유형과 일치하는 "*/*" 또는 표시된 유형의 모든 하위 유형과 일치하는 "xxxx/*"뿐입니다.

필드 값에 나열된 유형의 순서는 중요하지 않습니다.

Accept-Query 필드의 값은 동일한 경로를 공유하는 서버의 모든 URI에 적용됩니다. 다시 말해 쿼리 구성 요소는 무시됩니다. 동일한 리소스에 대한 요청이 서로 다른 Accept-Query 값을 반환하는 경우 가장 최근에 수신한 유효한 값( [HTTP-CACHING]의 섹션 4.2에 따름)을 사용합니다.

예를 들면 다음과 같습니다.

Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"

이 필드의 구문이 "Accept"([HTTP]의 섹션 12.5.1) 같은 다른 필드와 유사해 보이지만, 이 필드는 Structured Field이므로 [STRUCTURED-FIELDS]의 섹션 4에 지정된 대로 MUST 처리해야 합니다.

4. 보안 고려 사항

QUERY 메서드는 [HTTP]에 설명된 모든 HTTP 메서드와 동일한 일반적인 보안 고려 사항의 적용을 받습니다.

요청 정보를 URI(예: 쿼리 구성 요소)에 전달하는 대신 사용할 수 있습니다. URI는 요청 콘텐츠보다 중개자에 의해 로그에 기록되거나 다른 방식으로 처리될 가능성이 높기 때문에 일부 경우에는 이 방식이 선호됩니다. 쿼리에 민감한 정보가 포함된 다른 경우에는 URI가 로그에 기록될 가능성 때문에 GET보다 QUERY를 사용하는 것이 더 적합할 수 있습니다.

서버가 QUERY 요청의 결과를 나타내기 위해 임시 리소스를 생성하고 (예: Location 또는 Content-Location 필드에서 사용), 해당 리소스에 URI를 할당하며, 요청에 로그로 기록해서는 안 되는 민감한 정보가 포함되어 있다면 해당 URI는 원래 요청 콘텐츠의 민감한 부분을 포함하지 않도록 SHOULD 선택해야 합니다.

QUERY 콘텐츠를 잘못 정규화하거나 리소스가 콘텐츠를 처리하는 방식과 현저하게 다른 방식으로 정규화하는 캐시는 정규화 결과가 거짓 양성을 일으킬 경우 잘못된 응답을 반환할 수 있습니다.

Cross-Origin Resource Sharing(CORS)을 구현하는 사용자 에이전트의 QUERY 요청은 QUERY가 CORS 안전 목록 메서드 집합에 속하지 않으므로 "프리플라이트" 요청이 필요합니다 ([FETCH] 참조).

5. IANA 고려 사항

5.1. QUERY 메서드 등록

IANA는 <http://www.iana.org/assignments/http-methods>의 "Hypertext Transfer Protocol (HTTP) Method Registry"에 QUERY 메서드를 추가했습니다 ([HTTP]의 섹션 16.3.1 참조).

표 2: QUERY 메서드 정의
메서드 이름 안전함 멱등적 명세
QUERY RFC 10008의 섹션 2

5.2. Accept-Query 필드 등록

IANA는 <https://www.iana.org/assignments/http-fields>의 "Hypertext Transfer Protocol (HTTP) Field Name Registry"에 Accept-Query 필드를 추가했습니다 ([HTTP]의 섹션 16.1.1 참조).

표 3: Accept-Query 필드 정의
필드 이름 상태 구조화 유형 참조 설명
Accept-Query 영구 List RFC 10008의 섹션 3

6. 참고 문헌

6.1. 규범적 참고 문헌

[HTTP]
Fielding, R., 편집자, Nottingham, M., 편집자, 및 J. Reschke, 편집자, "HTTP 의미 체계", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/info/rfc9110>.
[HTTP-CACHING]
Fielding, R., 편집자, Nottingham, M., 편집자, 및 J. Reschke, 편집자, "HTTP 캐싱", STD 98, RFC 9111, DOI 10.17487/RFC9111, , <https://www.rfc-editor.org/info/rfc9111>.
[RFC2119]
Bradner, S., "요구 수준을 나타내기 위해 RFC에서 사용하는 핵심 단어", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC8174]
Leiba, B., "RFC 2119 핵심 단어의 대문자와 소문자 간 모호성", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[STRUCTURED-FIELDS]
Nottingham, M.P. Kamp, "HTTP의 구조화된 필드 값", RFC 9651, DOI 10.17487/RFC9651, , <https://www.rfc-editor.org/info/rfc9651>.
[URI]
Berners-Lee, T., Fielding, R., 및 L. Masinter, "통합 리소스 식별자 (URI): 일반 구문", STD 66, RFC 3986, DOI 10.17487/RFC3986, , <https://www.rfc-editor.org/info/rfc3986>.

6.2. 정보 제공 참고 문헌

[FETCH]
WHATWG, "FETCH", WHATWG 현행 표준, <https://fetch.spec.whatwg.org>. 커밋 스냅샷: <https://fetch.spec.whatwg.org/commit-snapshots/3bab31a55154bda73f25b45a23df718616f2f64e/>.
[RFC3253]
Clemm, G., Amsden, J., Ellison, T., Kaler, C., 및 J. Whitehead, "WebDAV (웹 분산 저작 및 버전 관리)의 버전 관리 확장", RFC 3253, DOI 10.17487/RFC3253, , <https://www.rfc-editor.org/info/rfc3253>.
[RFC4918]
Dusseault, L., 편집자, "웹 분산 저작 및 버전 관리(WebDAV)를 위한 HTTP 확장", RFC 4918, DOI 10.17487/RFC4918, , <https://www.rfc-editor.org/info/rfc4918>.
[RFC5323]
Reschke, J., 편집자, Reddy, S., Davis, J., 및 A. Babich, "웹 분산 저작 및 버전 관리(WebDAV) SEARCH", RFC 5323, DOI 10.17487/RFC5323, , <https://www.rfc-editor.org/info/rfc5323>.
[RFC6838]
Freed, N., Klensin, J., 및 T. Hansen, "미디어 유형 명세 및 등록 절차", BCP 13, RFC 6838, DOI 10.17487/RFC6838, , <https://www.rfc-editor.org/info/rfc6838>.
[RFC8259]
Bray, T., 편집자, "JavaScript Object Notation (JSON) 데이터 교환 형식", STD 90, RFC 8259, DOI 10.17487/RFC8259, , <https://www.rfc-editor.org/info/rfc8259>.
[RFC9535]
Gössner, S., 편집자, Normington, G., 편집자, 및 C. Bormann, 편집자, "JSONPath: JSON용 쿼리 표현식", RFC 9535, DOI 10.17487/RFC9535, , <https://www.rfc-editor.org/info/rfc9535>.
[URL]
WHATWG, "URL", WHATWG 현행 표준, <https://url.spec.whatwg.org>. 커밋 스냅샷: <https://url.spec.whatwg.org/commit-snapshots/52526653e848c5a56598c84aa4bc8ac9025fb66b/>.
[XSLT]
Kay, M., 편집자, "XSL 변환(XSLT) 버전 3.0", W3C 권고안, , <https://www.w3.org/TR/2017/REC-xslt-30-20170608/>. 최신 버전은 https://www.w3.org/TR/xslt-30/에서 확인할 수 있습니다.

부록 A. 예제

아래 예제는 설명을 위한 것일 뿐입니다. 실제로 이렇게 짧은 쿼리를 보내야 한다면 GET을 사용하는 것이 더 적합할 가능성이 높습니다.

대부분의 예제에서 사용되는 미디어 유형은 "application/x-www-form-urlencoded"입니다 (브라우저 사용자 클라이언트의 POST 요청에서 사용되며, [URL]"application/x-www-form-urlencoded"에 정의되어 있습니다). 간결성을 위해 Content-Length 필드는 생략했습니다.

A.1. 간단한 쿼리

다음은 직접 응답이 있는 간단한 쿼리입니다.

QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json

select=surname,givenname,email&limit=10&match=%22email=*@example.*%22

응답:

HTTP/1.1 200 OK
Content-Type: application/json

[
  { "surname": "Smith",
    "givenname": "John",
    "email": "smith@example.org" },
  { "surname": "Jones",
    "givenname": "Sally",
    "email": "sally.jones@example.com" },
  { "surname": "Dubois",
    "givenname": "Camille",
    "email": "camille.dubois@example.net" }
]

A.2. QUERY 지원 확인

QUERY 지원을 확인하는 간단한 방법은 OPTIONS ([HTTP]의 섹션 9.3.7) 메서드에서 제공됩니다.

OPTIONS /contacts HTTP/1.1
Host: example.org

응답:

HTTP/1.1 200 OK
Allow: GET, QUERY, OPTIONS, HEAD

Allow 응답 필드([HTTP]의 섹션 10.2.1)는 지정된 리소스에서 지원되는 메서드 집합을 나타냅니다.

OPTIONS를 사용하는 것 외에도 다른 방법이 있습니다. 예를 들어 서버 지원 여부를 미리 알지 못한 상태에서 QUERY 요청을 시도할 수 있습니다. 그러면 서버는 요청을 처리하거나, Allow 응답 필드를 포함하여 405(Method Not Allowed, [HTTP]의 섹션 15.5.6) 같은 4xx 상태로 응답할 수 있습니다.

A.3. QUERY 형식 확인

QUERY에서 지원되는 미디어 유형은 Accept-Query 응답 필드(섹션 3)를 통해 확인할 수 있습니다.

HEAD /contacts HTTP/1.1
Host: example.org

응답:

HTTP/1.1 200 OK
Content-Type: application/xhtml
Accept-Query: application/x-www-form-urlencoded, application/sql

어떤 요청 메서드에 대한 응답에 Accept-Query가 포함되는지는 접근 중인 리소스에 따라 달라집니다.

Accept-Query를 확인하는 대신 QUERY 요청을 수행한 뒤, 415 응답(Unsupported Media Type, [HTTP]의 섹션 15.5.16) 같은 4xx 상태가 발생한 경우 Accept 응답 필드([HTTP]의 섹션 12.5.1)를 검사할 수도 있습니다.

HTTP/1.1 415 Unsupported Media Type
Content-Type: application/xhtml
Accept: application/x-www-form-urlencoded, application/sql

A.4. Content-Location, Location 및 간접 응답

섹션 2.32.4에 설명된 대로, 성공 응답의 Content-Location 및 Location 응답 필드 (2xx, [HTTP]의 섹션 15.3)는 수신한 요청 결과 또는 동일한 작업을 수행하기 위한 이후 요청에 대해 GET 요청에 응답할 대체 리소스를 식별하는 방법을 제공합니다. 부록 A.1의 예제로 돌아가면 다음과 같습니다.

QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json

select=surname,givenname,email&limit=10&match=%22email=*@example.*%22

응답:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Location: /contacts/stored-results/17
Location: /contacts/stored-queries/42
Last-Modified: Sat, 25 Aug 2012 23:34:45 GMT
Date: Sun, 17 Nov 2024, 16:10:24 GMT

[
  { "surname": "Smith",
    "givenname": "John",
    "email": "smith@example.org" },
  { "surname": "Jones",
    "givenname": "Sally",
    "email": "sally.jones@example.com" },
  { "surname": "Dubois",
    "givenname": "Camille",
    "email": "camille.dubois@example.net" }
]

A.4.1. Content-Location 사용

위에서 수신한 Content-Location 응답 필드는 해당 QUERY 응답의 결과를 보유하는 리소스를 식별합니다.

GET /contacts/stored-results/17 HTTP/1.1
Host: example.org
Accept: application/json

응답:

HTTP/1.1 200 OK
Last-Modified: Sat, 25 Aug 2012 23:34:45 GMT
Date: Sun, 17 Nov 2024, 16:10:25 GMT

[
  { "surname": "Smith",
    "givenname": "John",
    "email": "smith@example.org" },
  { "surname": "Jones",
    "givenname": "Sally",
    "email": "sally.jones@example.com" },
  { "surname": "Dubois",
    "givenname": "Camille",
    "email": "camille.dubois@example.net" }
]

서버가 이 리소스를 무기한 구현할 것이라는 보장은 없으므로, 오류 응답 후 클라이언트는 새로운 대체 위치를 얻기 위해 원래 QUERY 요청을 다시 수행해야 한다는 점에 유의하십시오.

A.4.2. Location 사용

Location 응답 필드는 원래 QUERY 요청과 동일한 프로세스와 매개변수에 대한 현재 결과로 GET에 응답할 리소스를 식별합니다.

GET /contacts/stored-queries/42 HTTP/1.1
Host: example.org
Accept: application/json

이 예제에서는 Last-Modified 필드에 표시된 대로 2024-11-17T16:12:01Z에 항목 하나가 제거되었으므로 응답에는 항목이 두 개만 포함됩니다.

HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Sun, 17 November 2024, 16:12:01 GMT
ETag: "42-1"
Date: Sun, 17 Nov 2024, 16:13:17 GMT

[
  { "surname": "Smith",
    "givenname": "John",
    "email": "smith@example.org" },
  { "surname": "Dubois",
    "givenname": "Camille",
    "email": "camille.dubois@example.net" }
]

서버가 여전히 해당 리소스를 노출하고 있고 쿼리 결과에 변경이 없다고 가정하면, 다음 내용을 포함한 이후 조건부 GET 요청은 다음과 같습니다.

If-None-Match: "42-1"

이는 304(Not Modified) 응답([HTTP]의 섹션 15.4.5)으로 이어집니다.

A.4.3. 간접 응답

서버는 상태 코드 303(See Other, [HTTP]의 섹션 15.4.4)을 사용하여 "간접" 응답(섹션 2.5)을 보낼 수 있습니다.

부록 A.4 시작 부분의 요청이 주어지면 서버는 다음과 같이 응답할 수 있습니다.

HTTP/1.1 303 See Other
Content-Type: text/plain
Date: Sun, 17 Nov 2024, 16:13:17 GMT
Location: /contacts/stored-queries/42

저장된 쿼리는 "/contacts/stored-queries/42"에 있습니다.

이는 직접 응답에 Location을 포함하는 것과 유사하지만 쿼리 결과가 반환되지 않는다는 점이 다릅니다. 이를 통해 서버는 대체 리소스만 생성하거나 재사용할 수 있습니다. 이후 이 리소스는 부록 A.4.2에 표시된 대로 사용할 수 있습니다.

A.5. 조건부 요청

"application/sql" 및 "application/xslt+xml" [XSLT]를 요청 미디어 유형으로 지원하고, "text/csv" 형식의 응답을 생성할 수 있는 QUERY 구현 리소스를 생각해 보겠습니다. 쿼리 대상 데이터 집합에는 RFC 문서 정보가 포함되어 있으며 쿼리는 10년 단위로 그룹화된 정보를 반환합니다.

QUERY /rfc-index.xml HTTP/1.1
Host: example.org
Date: Sun, 7 Sep 2025, 00:00:00 GMT
Content-Type: application/xslt+xml
Accept: text/csv

...XSLT를 사용하는 쿼리 콘텐츠...

응답:

HTTP/1.1 200 OK
Date: Sun, 7 Sep 2025, 00:00:00 GMT
Location: /stored-queries/4815162342
Content-Type: text/csv
Accept-Query: "application/sql", "application/xslt+xml"
Last-Modified: Sun, 31 Aug 2025, 08:44:00 GMT
Vary: Accept-Query, Content-Encoding, Content-Type

decade, total, with errata, % with errata, average page count
1960, 26, 5, 19.2, 5.3
1970, 666, 18, 2.7, 6.1
1980, 376, 44, 11.7, 23.4
1990, 1593, 269, 16.9, 25.5
2000, 2888, 1048, 36.3, 27.3
2010, 2954, 895, 30.3, 26.1
2020, 1133, 230, 20.3, 26.2

여기서 서버는 이후 GET과 함께 사용하기 위해 동등한 리소스(섹션 2.4)에 "/stored-queries/4815162342" 경로를 할당했습니다.

나중에 클라이언트는 쿼리를 반복하지만 결과가 변경된 경우에만 반환되도록 지정합니다.

QUERY /rfc-index.xml HTTP/1.1
Host: example.org
Date: Mon, 8, Sep 2025, 11:00:00 GMT
Content-Type: application/sql
Accept: text/csv
If-Modified-Since: Sun, 31 Aug 2025, 08:44:00 GMT
Vary: Accept-Query, Content-Type

...동일한 쿼리이지만 SQL을 사용...

쿼리 대상 데이터가 변경되지 않았으므로 서버는 다음과 같이 응답합니다.

HTTP/1.1 304 Not Modified
Date: Mon, 8 Sep 2025, 11:00:00 GMT
Content-Type: text/csv
Location: /stored-queries/4815162342
Accept-Query: "application/sql", "application/xslt+xml"
Last-Modified: Sun, 31 Aug 2025, 08:44:00 GMT
Vary: Accept-Query, Content-Type

서버가 동등한 리소스의 URI를 식별했으므로 해당 리소스에는 GET으로 접근할 수 있습니다. 특히 이를 통해 쿼리 요청의 콘텐츠를 다시 보낼 필요가 없습니다.

GET /stored-queries/4815162342 HTTP/1.1
Host: example.org
Date: Sun, 21, Sep 2025, 12:08:00 GMT
Accept: text/csv
If-Modified-Since: Sun, 31 Aug 2025, 00:00:00 GMT

여기서는 데이터 집합의 상태가 실제로 변경되었으므로 새 콘텐츠가 반환됩니다.

HTTP/1.1 200 OK
Date: Sun, 21, Sep 2025, 12:08:00 GMT
Content-Type: text/csv
Last-Modified: Thu, 18 Sep 2025, 19:56:00 GMT
Vary: Accept-Query, Content-Encoding, Content-Type

decade, total, with errata, % with errata, average page count
1960, 26, 5, 19.2, 5.3
1970, 666, 18, 2.7, 6.1
1980, 376, 44, 11.7, 23.4
1990, 1593, 269, 16.9, 25.5
2000, 2888, 1048, 36.3, 27.3
2010, 2954, 895, 30.3, 26.1
2020, 1133, 230, 20.3, 26.2

(이 10년 구간의 행에 변경이 있음을 확인하십시오.)

아래 다이어그램은 조건부 요청의 사용과 동등한 리소스에 URI가 할당된 경우 (그리고 클라이언트가 이를 활용하는 경우) 어떻게 달라질 수 있는지를 보여줍니다. 가상의 필드 이름 "Validator"는 설명 목적으로 사용됩니다.

클라이언트 리소스 콘텐츠가 있는 QUERY 200 OK Validator: foo 콘텐츠가 있는 QUERY ('foo'를 조건으로 함) 304 Not Modified Validator: foo 상태 변경 콘텐츠가 있는 QUERY ('foo'를 조건으로 함) 200 OK Validator: bar
그림 1: QUERY만 사용하는 데이터 흐름
클라이언트 리소스 콘텐츠가 있는 QUERY 동등한 리소스 (/xyz 생성) 200 OK Validator: foo Location: /xyz GET ('foo'를 조건으로 함) 304 Not Modified Validator: foo 상태 변경 GET ('foo'를 조건으로 함) 200 OK Validator: bar
그림 2: 동등한 리소스에 GET을 사용하는 데이터 흐름

A.6. 추가 쿼리 형식

다음 예제는 RFC 정오표의 JSON 형태 [RFC8259] 데이터베이스에 대한 요청을 보여줍니다.

아래 요청은 eXtensible Stylesheet Language Transformations(XSLT)을 사용하여 연도별 및 정의된 정오표 유형별로 요약된 정오표 정보를 추출합니다.

QUERY /errata.json HTTP/1.1
Host: example.org
Content-Type: application/xslt+xml
Accept: application/xml, text/csv

<transform xmlns="http://www.w3.org/1999/XSL/Transform"
  xmlns:j="http://www.w3.org/2005/xpath-functions"
  version="3.0">

  <output method="text"/>

  <param name="input"/>

  <variable name="json"
    select="json-to-xml(unparsed-text($input))"/>

  <variable name="sc">errata_status_code</variable>
  <variable name="sd">submit_date</variable>

  <template match="/">
    <text>year, total, rejected, verified, hdu, reported</text>
    <text>&#10;</text>
    <variable name="en" select="$json//j:map"/>
    <for-each-group select="$en"
      group-by="substring-before(j:string[@key=$sd],'-')">
      <sort select="current-grouping-key()"/>
      <variable name="year" select="current-grouping-key()"/>
      <variable name="errata" select=
        "$en[$year=substring-before(j:string[@key=$sd],'-')]"/>
      <value-of select="concat(
        $year,
        ', ',
        count($errata),
        ', ',
        count($errata['Rejected'=j:string[@key=$sc]]),
        ', ',
        count($errata['Verified'=j:string[@key=$sc]]),
        ', ',
        count(
          $errata['Held for Document Update'=j:string[@key=$sc]]),
        ', ',
        count($errata['Reported'=j:string[@key=$sc]]),
        '&#10;')"/>
    </for-each-group>
  </template>

</transform>

응답:

HTTP/1.1 200 OK
Content-Type: text/csv
Accept-Query: "application/jsonpath", "application/xslt+xml"
Date: Wed, 19 Feb 2025, 17:10:01 GMT

year, total, rejected, verified, hdu, reported
2000, 14, 0, 14, 0, 0
2001, 72, 1, 70, 1, 0
2002, 124, 8, 104, 12, 0
2003, 63, 0, 61, 2, 0
2004, 89, 1, 83, 5, 0
2005, 156, 10, 96, 50, 0
2006, 444, 54, 176, 214, 0
2007, 429, 48, 188, 193, 0
2008, 423, 52, 165, 206, 0
2009, 331, 39, 148, 144, 0
2010, 538, 80, 232, 222, 4
2011, 367, 47, 170, 150, 0
2012, 348, 54, 149, 145, 0
2013, 341, 61, 169, 106, 5
2014, 342, 73, 180, 72, 17
2015, 343, 79, 145, 89, 30
2016, 295, 46, 122, 82, 45
2017, 303, 46, 120, 84, 53
2018, 350, 61, 118, 98, 73
2019, 335, 47, 131, 94, 63
2020, 387, 68, 117, 123, 79
2021, 321, 44, 148, 63, 66
2022, 358, 37, 198, 40, 83
2023, 262, 38, 121, 33, 70
2024, 322, 33, 125, 23, 141
9999, 1, 0, 0, 1, 0

다른 쿼리 형식인 JSONPath [RFC9535]도 지원됨을 나타내는 Accept-Query 응답 필드에 유의하십시오. 아래 요청은 2024년 이후 제출된 모든 거부된 정오표의 식별자를 보고합니다.

QUERY /errata.json HTTP/1.1
Host: example.org
Content-Type: application/jsonpath
Accept: application/json

$..[
     ?@.errata_status_code=="Rejected"
     && @.submit_date>"2024"
   ]
   ["doc-id"]

응답:

HTTP/1.1 200 OK
Content-Type: application/json
Accept-Query: "application/jsonpath", "application/xslt+xml"
Date: Thu, 20 Feb 2025, 09:55:42 GMT
Last-Modified: Thu, 20 Feb 2025 06:10:01 GMT

[
  "RFC1185","RFC8407","RFC6350","RFC8467","RFC1157","RFC9543",
  "RFC9076","RFC7656","RFC2822","RFC9460","RFC2104","RFC6797",
  "RFC9499","RFC9557","RFC2131","RFC2328","RFC9001","RFC3325",
  "RFC9438","RFC2526","RFC2985","RFC7643","RFC9132","RFC6376",
  "RFC9110","RFC9460","RFC7748","RFC9497","RFC8463","RFC4035",
  "RFC7239","RFC9083","RFC9537","RFC9537","RFC9420","RFC9000",
  "RFC9656","RFC9110","RFC2324","RFC2549","RFC6797","RFC2549",
  "RFC8894"
]

부록 B. 메서드 이름 'QUERY' 선택

"Hypertext Transfer Protocol (HTTP) Method Registry"(<http://www.iana.org/assignments/http-methods>)에는 이미 "안전함"과 "멱등적" 속성을 가진 세 가지 다른 메서드가 있습니다. "PROPFIND" [RFC4918], "REPORT" [RFC3253], 그리고 "SEARCH" [RFC5323]입니다.

이들 중 하나를 재사용하고 이 명세에서 새로운 메서드 "QUERY"로 정의하는 내용과 일치하도록 업데이트하는 것도 가능했습니다. 실제로 이 명세의 초기 단계에서는 "SEARCH"를 사용했습니다.

최종적으로 "QUERY"라는 메서드 이름을 선택한 이유는 다음과 같습니다.

감사의 말

아이디어, 검토 및 피드백을 제공해 주신 HTTP 워킹 그룹의 모든 구성원께 감사드립니다.

다음 분들께 특별히 감사드립니다. Carsten Bormann, Mark Nottingham, Martin Thomson, Michael Thornburgh, Roberto Polli, Roy Fielding, 그리고 Will Hawkins.

기여자

Ashok Malhotra는 이 명세로 이어진 초기 논의에 참여했습니다.

Ashok Malhotra

이 HTTP 메서드에 대한 논의는 2019년 HTTP 워크숍에서 Asbjørn Ulsberg에 의해 다시 시작되었습니다.

Asbjørn Ulsberg

저자 주소

Julian Reschke
greenbytes GmbH
Hafenweg 16
48155 Münster
독일
James M Snell
Cloudflare
Mike Bishop
Akamai