[api] RESTful 검색 / 필터링을 설계하는 방법은 무엇입니까? [닫은]

현재 PHP에서 RESTful API를 디자인하고 구현하고 있습니다. 그러나 초기 디자인을 구현하지 못했습니다.

GET /users # list of users
GET /user/1 # get user with id 1
POST /user # create new user
PUT /user/1 # modify user with id 1
DELETE /user/1 # delete user with id 1

지금까지 꽤 표준 적인가?

내 문제는 첫 번째 문제입니다 GET /users. 요청 본문에서 매개 변수를 보내 목록을 필터링하는 것을 고려하고있었습니다. 이것은 다음과 같이 슈퍼 긴 URL을 얻지 않고도 복잡한 필터를 지정할 수 있기를 원하기 때문입니다.

GET /users?parameter1=value1&parameter2=value2&parameter3=value3&parameter4=value4

대신 나는 다음과 같은 것을 원했습니다.

GET /users
# Request body:
{
    "parameter1": "value1",
    "parameter2": "value2",
    "parameter3": "value3",
    "parameter4": "value4"
}

훨씬 더 읽기 쉽고 복잡한 필터를 설정할 수 있습니다.

어쨌든 file_get_contents('php://input')요청에 대한 GET요청 본문을 반환하지 않았습니다 . 나는 또한 시도했지만 http_get_request_body(), 내가 사용하는 공유 호스팅에는 없습니다 pecl_http. 어쨌든 도움이 될지 확실하지 않습니다.

나는 이 질문을 발견 하고 GET이 요청 본문을 가지고 있지 않다는 것을 깨달았습니다. 그것은 결정적이지 못했지만 반대했습니다.

그래서 지금 무엇을 해야할지 모르겠습니다. RESTful 검색 / 필터링 기능을 어떻게 설계합니까?

나는 사용할 수 있다고 가정 POST하지만 그다지 RESTful하지는 않습니다.



답변

RESTful 검색을 구현하는 가장 좋은 방법은 검색 자체를 리소스로 간주하는 것입니다. 그런 다음 검색을 작성 중이므로 POST 동사를 사용할 수 있습니다. POST를 사용하기 위해 문자 그대로 데이터베이스에 무언가를 만들 필요는 없습니다.

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

Accept: application/json
Content-Type: application/json
POST http://example.com/people/searches
{
  "terms": {
    "ssn": "123456789"
  },
  "order": { ... },
  ...
}

사용자 관점에서 검색을 작성 중입니다. 이것의 구현 세부 사항은 관련이 없습니다. 일부 RESTful API는 지속성이 필요하지 않을 수도 있습니다. 그것은 구현 세부 사항입니다.


답변

GET 요청에서 요청 본문을 사용하는 경우 캐시 시스템은 URL 만 사용하므로 GET 요청을 캐시 할 수 없으므로 REST 원칙을 위반하는 것입니다.

더 나쁜 것은 URL에 사용자를이 페이지로 리디렉션하는 데 필요한 모든 정보가 포함되어 있지 않기 때문에 URL에 책갈피를 지정할 수 없습니다.

요청 본문 매개 변수 대신 URL 또는 쿼리 매개 변수를 사용하십시오.

예 :

/myapp?var1=xxxx&var2=xxxx
/myapp;var1=xxxx/resource;var2=xxxx

실제로 HTTP RFC 7231은 다음과 같이 말합니다.

GET 요청 메시지 내의 페이로드에는 정의 된 의미가 없습니다. GET 요청에서 페이로드 본문을 전송하면 일부 기존 구현에서 요청을 거부 할 수 있습니다.

자세한 내용은 여기참조하십시오


답변

리소스 필터링 / 검색은 RESTful 방식으로 구현 될 수있는 것 같습니다. 아이디어는 /filters/or 라는 새로운 엔드 포인트를 도입하는 것입니다 /api/filters/.

이 엔드 포인트 필터를 사용 하는 것은 자원으로 간주 될 수 있으므로 POST메소드 를 통해 작성됩니다 . 물론이 방법으로 body를 사용하여 모든 매개 변수를 전달할 수있을뿐만 아니라 복잡한 검색 / 필터 구조를 만들 수 있습니다.

이러한 필터를 만든 후 검색 / 필터 결과를 얻을 수있는 두 가지 가능성이 있습니다.

  1. 201 Created상태 코드 와 함께 고유 한 ID를 가진 새로운 리소스가 반환됩니다 . 그런 다음이 ID를 사용하여 다음 과 같은 GET요청을 할 수 있습니다 /api/users/.

    GET /api/users/?filterId=1234-abcd
    
  2. 를 통해 새 필터를 만든 후에는을 가리키는 헤더 와 함께 POST응답하지 않고 201 Created한 번에 응답 합니다 . 이 리디렉션은 기본 라이브러리를 통해 자동으로 처리됩니다.303 SeeOtherLocation/api/users/?filterId=1234-abcd

두 시나리오 모두 필터링 된 결과를 얻으려면 두 가지 요청이 필요합니다. 이는 특히 모바일 애플리케이션의 단점으로 간주 될 수 있습니다. 모바일 애플리케이션의 경우 단일 POST호출을 사용 합니다 /api/users/filter/.

생성 된 필터를 유지하는 방법?

그것들은 DB에 저장되어 나중에 사용할 수 있습니다. 또한 일부 임시 저장소 (예 : redis)에 저장할 수 있으며 TTL이 만료 된 후 만료되어 제거됩니다.

이 아이디어의 장점은 무엇입니까?

필터, 필터링 된 결과는 캐시 가능하며 북마크가 가능합니다.


답변

요청 매개 변수를 사용해야하지만 원하는 HTTP 헤더가 없으면 원하는 작업을 수행해야합니다. HTTP 사양은 명시 적으로 GET은 몸을 가질 수 없습니다, 말을하지 않습니다. 그러나이 백서 에서는 다음과 같이 설명합니다.

관례 적으로 GET 메소드를 사용할 때 자원을 식별하는 데 필요한 모든 정보가 URI로 인코딩됩니다. 클라이언트가 URI의 쿼리 부분이 아닌 HTTP 엔터티 본문에서 서버에 데이터를 제공하는 안전한 상호 작용 (예 : 검색)에 대한 HTTP / 1.1의 규칙은 없습니다. 이는 안전한 작업을 위해 URI가 길 수 있음을 의미합니다.


답변

laravel / php 백엔드를 사용함에 따라 다음과 같은 경향이 있습니다.

/resource?filters[status_id]=1&filters[city]=Sydney&page=2&include=relatedResource

PHP는 []매개 변수를 자동으로 배열로 변환 하므로이 예제 $filter에서는 페이지 및 필자가로드하려는 관련 리소스와 함께 필터의 배열 / 객체를 보유하는 변수로 끝납니다 .

다른 언어를 사용하는 경우 이는 여전히 좋은 규칙 일 수 있으며 구문 분석기를 작성 []하여 배열 로 변환 할 수 있습니다 .


답변

초기 API가 완전히 RESTful인지 아닌지 (특히 알파 단계에있을 때) 너무 걱정하지 마십시오. 백엔드 배관을 먼저 작동 시키십시오. 광범위한 종류의 테스트 ( “베타”)를 위해 충분히 안정적인 것을 얻을 때까지 반복해서 수정하여 URL 변환 / 재 작성을 수행 할 수 있습니다.

URI에 대한 위치 및 규칙에 따라 매개 변수가 인코딩되는 URI를 정의 할 수 있으며, 항상 무언가에 맵핑 할 경로가 앞에 붙습니다. PHP를 모르지만 그러한 기능이 존재한다고 가정합니다 (웹 프레임 워크가있는 다른 언어로 존재 함).

즉. 상점 # 1의 i = 1..4에 대해 param [i] = value [i]를 사용하여 “사용자”검색 유형을 수행하십시오 (URI 쿼리 매개 변수의 약어로 value1, value2, value3, … 사용).

1) GET /store1/search/user/value1,value2,value3,value4

또는

2) GET /store1/search/user,value1,value2,value3,value4

또는 다음과 같이 (추천하지는 않지만 나중에 자세히 설명)

3) GET /search/store1,user,value1,value2,value3,value4

옵션 1을 사용하면 접두사가 붙은 모든 URI /store1/search/user를 검색 처리기 (또는 PHP 지정)에 기본적으로 매핑 하여 store1에서 자원을 검색하도록 기본 설정합니다 (와 동일) /search?location=store1&type=user.

API에 의해 문서화되고 시행되는 규칙에 따라 매개 변수 값 1-4는 쉼표로 구분되어 순서대로 표시됩니다.

옵션 2는 검색 유형 (이 경우 user)을 위치 매개 변수 # 1로 추가합니다. 어느 쪽이든 옵션은 단지 외관상의 선택입니다.

옵션 3도 가능하지만 마음에 들지 않습니다. 특정 리소스 내에서 검색 기능은 검색 자체보다 URI 자체에 표시되어야한다고 생각합니다 (URI에서 검색이 리소스 내에서 특정적임을 명확하게 나타내는 것처럼).

URI에서 매개 변수를 전달하는 것보다이 방법의 장점은 검색이 URI의 일부라는 것입니다 (따라서 검색은 자원, 시간이 지남에 따라 내용이 변할 수있는 자원으로 처리됩니다). 매개 변수 순서는 필수라는 단점이 있습니다. .

이와 같은 작업을 수행하면 GET을 사용할 수 있으며 읽기 전용 리소스가됩니다 (POST 또는 PUT을 사용할 수 없기 때문에 GET을 수행하면 업데이트 됨). 호출 될 때만 존재하는 자원이기도합니다.

또한 일정 시간 동안 결과를 캐싱하거나 DELETE를 사용하여 캐시를 삭제함으로써 더 많은 의미를 추가 할 수 있습니다. 그러나 이것은 사람들이 일반적으로 DELETE를 사용하는 것과 반대가 될 수 있습니다 (사람들은 일반적으로 캐싱 헤더로 캐싱을 제어하기 때문에).

어떻게 결정 하느냐는 디자인 결정일 것이지만, 이것이 내가 갈 길입니다. 완벽하지는 않으며, 이렇게하는 것이 최선의 방법이 아닌 경우가있을 것입니다 (특히 매우 복잡한 검색 기준).


답변

참고 :이 내용은 약간 늦었지만 관심있는 사람에게는 적합합니다. RESTful 방법에 따라 HTTP 사양이 명확하지 않으므로 자체 필터링 전략을 구현해야합니다. 모든 필터 매개 변수를 URL 인코딩으로 제안하고 싶습니다.

GET api/users?filter=param1%3Dvalue1%26param2%3Dvalue2

나는 그것이 추악하다는 것을 알고 있지만 그것을하는 가장 편안한 방법이라고 생각하고 서버 측에서 쉽게 파싱해야합니다. 🙂