긴 쿼리 매개 변수 목록을 사용하여 RESTful 쿼리 API 디자인 [닫기]


153

몇 가지 필터를 기반으로 일련의 객체를 반환하는 RESTful 쿼리 API를 설계해야합니다. 이에 대한 일반적인 HTTP 메소드는 GET입니다. 유일한 문제는 적어도 12 개의 필터를 가질 수 있으며 모든 필터를 쿼리 매개 변수로 전달하면 URL이 상당히 길어질 수 있습니다 (방화벽에 의해 차단 될만큼 길다).

매개 변수 수를 줄이는 것은 옵션이 아닙니다.

내가 생각할 수있는 한 가지 대안은 URI에서 POST 메소드를 사용하고 POST 본문의 일부로 필터를 보내는 것입니다. RESTfull (데이터를 쿼리하기 위해 POST 호출하기)과 반대입니다.

더 나은 디자인 제안이 있습니까?


2
짧은 (1-char 등) 매개 변수 이름을 사용 하시겠습니까?
Madbreaks

2
진정으로 충분하지는 않지만 GET 및 POST와 관련하여 실용적이어야한다고 생각합니다. 보낼 변수가 많고 줄일 수 없다면 POST합니다. URL을 과도하게 채우는 것을 좋아하지 않지만 그저 나뿐입니다.
Doug Dawson

감사. 이 질문은 끝났지 만 대답이 필요한 질문입니다. 나는 당신이 물어 다행입니다.
Casey Crookston (

답변:


142

REST API를 사용하면 모든 관점에서 문제가됩니다.

REST API의 두 가지 주요 개념은 엔드 포인트와 자원 (엔티티)입니다. 느슨하게 말하면, 엔드 포인트는 GET을 통해 자원을 리턴하거나 POST 및 PUT 등을 통해 자원을 승인합니다 (또는 위의 조합).

POST를 사용하면 전송하는 데이터가 새 리소스 및 관련 엔드 포인트를 생성하거나 생성하지 않을 수 있으며 이는 POST 된 URL 아래에 "라이브"되지 않을 가능성이 높습니다. 다시 말해 POST 할 때 처리 할 데이터를 어딘가에 보냅니다. POST 엔드 포인트는 일반적으로 자원을 찾을 수있는 위치가 아닙니다.

RFC 2616 에서 인용 (관련 부품은 생략하고 관련 부품은 강조 표시) :

9.5 POST

POST 메소드는 오리진 서버가 요청에 포함 된 엔티티를 요청 라인의 Request-URI에 의해 식별 된 자원의 새로운 하위 항목으로 승인하도록 요청하는 데 사용됩니다. POST는 균일 한 방법으로 다음 기능을 처리 할 수 ​​있도록 설계되었습니다.

  • ...
  • 양식 제출 결과와 같은 데이터 블록을 데이터 처리 프로세스에 제공하는 단계;
  • ...

...

POST 메소드에 의해 수행 된 조치 로 인해 URI로 식별 할 수있는 자원이 생성되지 않을 수 있습니다 . 이 경우 응답 에 결과를 설명하는 엔터티가 포함되는지 여부 에 따라 200 (OK) 또는 204 (No Content)가 적절한 응답 상태 입니다.

오리진 서버에서 리소스가 생성 된 경우 응답은 201 (생성)이어야합니다.

우리는 문제 영역이 지시하는 모든 것, 사용자, 메시지, 서적 등 '사물'또는 '데이터'를 나타내는 엔드 포인트 및 리소스에 익숙해졌습니다. 그러나 엔드 포인트는 다른 자원 (예 : 검색 결과)을 노출 할 수도 있습니다.

다음 예제를 고려하십시오.

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

일반적인 REST CRUD입니다. 그러나 우리가 추가 한 경우 :

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

이 엔드 포인트에 대해 신뢰할만한 것은 없습니다. 요청 본문의 형식으로 데이터 (엔티티)를 허용합니다. 이 데이터는 검색 기준 이며 다른 것과 마찬가지로 DTO입니다. 이 엔드 포인트는 요청에 대한 응답으로 자원 (엔티티)을 생성합니다. 검색 결과 . 검색 결과 리소스는 임시 리소스로 리디렉션없이 클라이언트에 즉시 제공되며 다른 정식 URL에 노출되지 않습니다.

엔티티가 서적이 아닌 경우를 제외하고 여전히 REST입니다. 요청 엔티티는 서적 검색 기준이고 응답 엔티티는 서적 검색 결과입니다.


DTO에 대한 몇 가지 클래스 명명 규칙을 제안 할 수 있습니까?
Kwadz

필자는 개인적으로 갈 것이라고 BooksSearchCriteriaDTO하고 BooksSearchResultsDTO.
Amir Abiri

이 POST / books / search 사례에 가장 적합한 HTTP 응답 코드는 무엇입니까? 201이 여전히 적용됩니까?
L. Holanda

9
201은 반대입니다. 즉 리소스가 생성되었음을 나타냅니다. 어딘가에 고유 한 URI가있을 것으로 예상되는 자원. 201은 POSTCRUD의 C 부분에 사용될 때 적합합니다 . 나는 빈 검색 결과를 위해 204와 함께 보통 오래된 200을 사용할 것입니다.
Amir Abiri 2012

@AmirAbiri 감사합니다.
mohamed-mhiri

84

많은 사람들이 너무 길거나 너무 복잡한 쿼리 문자열을 가진 GET (예 : 쿼리 문자열은 중첩 된 데이터를 쉽게 처리하지 못함) 대신 복잡한 본문 / 긴 데이터를 본문에 표시하여 POST로 전송할 수 있다는 관행을 받아 들였습니다. 요청의.

HTTP 스펙에서 POST 스펙을 찾으십시오. 엄청나게 넓습니다. (RES의 허점을 통해 전함을 항해하고 싶다면 POST를 사용하십시오.)

GET은 dem 등원이므로 자동 재시 도와 같은 GET 시맨틱의 이점 중 일부를 잃어 버릴 수 있지만 그와 함께 살 수 있다면 POST로 길거나 복잡한 쿼리를 처리하는 것이 더 쉬울 수 있습니다.

(Lol long digression ... 최근에 HTTP 사양에 따라 GET 에 문서 본문이 포함될 있음을 발견했습니다 . HTTP 저자가 그것에 대해 이야기하고있는 스레드를 검색하고 발견했으며 의도적으로 라우터와 다른 메시지를 구별 할 필요가 없었습니다. 많은 인프라 스트럭처 조각들이 GET의 몸체를 떨어 뜨릴 수 있으므로 POST와 같이 몸체에 표시된 필터로 GET을 사용할 수 있지만 주사위를 굴릴 수 있습니다.)


11
본문이있는 HTTP GET에 대한 자세한 내용은 질문을 참조하십시오 .
RickyA

6

간단히 말해서 : X-HTTP-Method-Override 헤더를 사용하여 POST를 작성하지만 HTTP 메소드를 대체하십시오 .

실제 요청

POST / 책

엔터티 본문

{ "title": "Ipsum", "year": 2017}

헤더

X-HTTP- 방법 재정의 : GET

서버 측에서 헤더 X-HTTP-Method-Override가 존재하는지 확인한 후 백엔드의 최종 엔드 포인트에 대한 라우트를 빌드하는 방법으로 해당 값을 사용하십시오. 또한 엔터티 본문을 쿼리 문자열로 사용하십시오. 백엔드 관점에서 요청은 단순한 GET이되었습니다.

이렇게하면 디자인을 REST 원칙과 조화롭게 유지할 수 있습니다.

편집 : 이 솔루션은 원래 일부 브라우저와 서버에서 PATCH 동사 문제를 해결하기위한 것이지만 질문에 설명 된 매우 긴 URL의 경우 GET 동사와 함께 작동합니다.


2
IETF는 X 접두사가 붙은 HTTP 헤더를 사용하지 않습니다 : tools.ietf.org/html/rfc6648
jannis


@jannis 연결하는 RFC는 1.4입니다. 기존 X-제거 및 1.5 에 대해서는 권장하지 않습니다 . 기존 사양을 무시하지 않습니다. ... X-IMO가 여기에 남아 있습니까?
Jan Molnar

-3

Java 및 JAX-RS로 개발하는 경우 @GET과 함께 @QueryParam을 사용하는 것이 좋습니다.

나는 목록을 살펴볼 필요가있을 때 같은 질문을했다.

예를보십시오 :

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService {

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) {
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    }
}

URI 패턴 : “poc / test? code = 1 & code = 2 & code = 3

@QueryParam 은 질의 매개 변수“orderBy = age & orderBy = name”을 java.util.List로 자동 변환합니다.


예를 설명하면 더 좋을 것입니다. 어떤 프로그래밍 언어로 작성 되었습니까?
Aleks Andreev

안녕하세요 @AleksAndreev. 당신의 의견에 감사드립니다. 나아 졌어? tks
acacio.martins

이 질문은 구현이 아니라 RESTful 서비스의 디자인에 관한 것입니다. 이 답변은 질문에 대답하지 않습니다.
Heretic Monkey

@ user1331413 IMHO 예, 이제 더 좋습니다. 노력해 주셔서 감사합니다 .. 그러나 Mike McCaughan이 말했듯이 질문은 구현이 아닌 REST 개념에 관한 것입니다.
Aleks Andreev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.