복잡한 RESTful 검색 방법을 수행하는 적절한 방법은 무엇입니까?


44

REST 원칙에 따라 일부 기준을 사용하여 검색하고 결과를 클라이언트에 반환하는 API에 대한 GET 메소드를 작성하려고합니다. 문제는 기준이 최대 14 개의 매개 변수를 가질 수 있다는 것입니다. 그 중 하나는 복잡한 개체의 목록이므로 ...

  • 이 복잡한 객체를 URL 매개 변수로 / URL 매개 변수로 인코딩 / 디코딩 할 수 있는지조차 모르겠습니다.

  • URL이 얼마나 오래 걸릴 수 있는지 계산하지 않았지만 URL이 충분히 길고 URL 길이 제한에 도달 할 것이라고 확신합니까?

또한 검색에는 결과가 "실시간"으로 표시되어야합니다. 즉, 사용자가 검색 양식에서 무언가를 변경할 때마다 "검색"버튼을 누르지 않아도 새로운 결과를 볼 수 있어야합니다.

이러한 요점을 분명히 설명해 주시고 많은 매개 변수를 사용하여 편안한 검색 방법을 만드는 것이 좋습니다.


3
제쳐두고 (저는 글을 쓰는 시점에서 두 답변 중 어느 것도 실시간 부분을 언급하지 않음), 실시간 검색은 일반적으로 업데이트 된 요청을 계속 반복해서 보내야합니다. 예, 당신있는 거 입력하는 동안, 당신은 같은 물건에 대한 요청을 보낼 것 search?q=t, search?q=te, search?q=test, 등. 서버가 손상되지 않도록 쿼리 전송 빈도를 제한하십시오. 또는 많은 양의 정보를 반환하고 클라이언트 측에서 필터링을 수행 할 수도 있습니다. 사용자가 사물을 크게 좁힐 수있는 넓은 범주를 입력하면 잘 작동합니다.
Kat

2
솔루션에 관계없이 기술 중립 형식으로 데이터를 교환하십시오. 따라서 내부 표현을 사용하지 않으면 API에 대한 클라이언트를 작성하기가 더 어려워집니다.
Kwebble

필요에 따라이 라이브러리는 github.com/jirutka/rsql-parser 작업을 수행 할 수 있습니다. JPA를 사용하는 경우 확장명이 JPA이거나 검색 엔진의 API에 맵핑하기 위해 자체 방문자를 작성할 수 있습니다. 그리고 당신은 당신의 자신의 연산자를 추가 할 수 있습니다.
Walfrat

답변:


54

내 대답을 읽기 전에 @Neil에 동의했다고 말하고 싶습니다. 우리는 전투를 선택해야합니다. 우리는 보통 최선을 다하기를 원하지만 때로는 토론 할 여지가 너무 적으며 우리의 의지에 반하여 결정을 내려야합니다.

어쨌든, 닐의 대답에서 한 가지 더보고 싶습니다. 문서 . POST 요청 /search이 안전하다는 것을 개발자에게 알리기 위해 .

그렇습니다.

1. 기회를 줘

GET옵션을 먼저 고려하십시오 . 이 질문 URL의 최대 길이를 확인하십시오 . 가장 긴 쿼리 문자열이 2000자를 초과하는지 평가하십시오. 그렇지 않은 것으로 예상되지 않으면로 이동하십시오 GET. 그것은 추악하게 보일지 모르지만 적어도 URL을 북마크 할 수 있으며 물론 메소드 의미론 (idempotence, safe and caching)의 의미에서 파생 된 모든 장점이 있습니다.

1.1 쿼리 문자열을 인코딩하십시오

예를 들어, base 64에서 . javascript에서도 base 64 인코딩을 지원합니다 .

이것이 작동하는 방식입니다.

  1. 모든 필터로 JSON을 빌드하고 정규화하십시오.
  2. 문자열로 파싱
  3. 그것을 인코딩
  4. 인코딩 된 JSON을 요청 매개 변수 ( /search?q=SGVsbG8gV29ybGQh....) 로 보냅니다 .
  5. 서버 측에서 매개 변수 q를 디코딩하십시오 .
  6. JSON 문자열을 역 직렬화

이전에는 가능한 가장 긴 JSON 문자열을 만들고 인코딩하여 길이를 가져옵니다. 인코딩 된 문자열이 URL에 맞는지 평가하십시오. 테스트를 위해 Fiddle.js 에 다음 스 니펫을 구현했습니다 . (나는 여전히 작동 희망) 1

Base 64 인코딩은 결정적이고 가역적이므로 충돌 가능성이 없습니다.

인코딩 된 쿼리를 사용하면 DB에 검색을 저장하고 URL을 북마크에 추가하고 링크를 공유하는 등의 작업을 수행 할 수 있습니다. 물론 문자열을 이스케이프 / 이스케이프 할 필요도 없습니다.

1.2 별칭으로 시도

REST API를 디자인하는 방법에 대한 이 블로그 를 읽으 면서 한 가지 대안을 더 기억했습니다. 일반적인 쿼리의 별칭 .

다음과 같은 이유로 이것들이 흥미로워집니다

  • 쿼리 문자열 길이를 줄이십시오. API를 더 깨끗하고 사용자 친화적으로 만듭니다.

    GET / tickets /? status = closed & closedAt = xxx GET / tickets / 최근 폐쇄 /

  • 더 많은 별칭 또는 더 많은 요청 매개 변수와 결합 할 수 있습니다.

    GET / tickets /? status = closed & closedAt = xxx & within = 30 분 vs GET / tickets / 최근 폐쇄 /? with == 30 분

  • 별칭을 인코딩 된 쿼리 문자열과 결합 할 수 있습니다

    GET / tickets /? status = closed & closedAt = xxx & in = 30 분 vs GET / tickets / 최근 폐쇄 /? q = SGVsbG8g ...


1 : JSON을 사용했지만 서버 측에서 직렬화를 해제하는 즉시 다른 형식을 사용할 수 있습니다.


2
이것은 실용적이고 정확합니다. 또한 대부분의 프로그래밍 언어가 해시를 쿼리 문자열로 변환하는 것이 쉽지 않으므로 GET 작업으로 시작하는 것이 매우 쉽다는 점도 주목할 가치가 있습니다.
Aluan Haddad

1
Spring stackoverflow.com/questions/16942193/…을 좋아 합니다. 첫 번째 시도에서 작동했다고 믿을 수 없습니다 : D. URL 길이는 1k 미만이지만 사양을 반복해야합니다.
anat0lius

그런 다음 GET과 함께하십시오. 단순성을 위해. Spring MVC를 사용하면 GET과 동일한 매핑을 달성 할 수 있습니다. Spring의 WebArgumentResolver를 찾으십시오 ;-)
Laiv

Base64는 페이로드 크기를 약 4/3로 팽창시킵니다. urlencoding은 특수 문자의 경우 3/1로 만들 수 있지만 대부분 안전한 문자를 가진 쿼리는 동일한 크기를 유지합니다. base64를 사용해야하는 다른 이유가 있습니까?
villasv

실제로는 아닙니다. 나는 단지 URL을 탈출하는 것을 싫어한다. 페이로드의 오버 와트는 여기에서 절충점입니다. 여전히 요청 당 GET의 최대 크기에 맞아야합니다. 그래서 스 니펫을 만들었습니다. 사용자가 시도하십시오. 대답을 쓸 때 구현 세부 사항보다 웹 의미를 우선 순위로 지정했습니다. 대답의 요점은 "GET으로 계속 노력하십시오"입니다. 당신의 길을 찾거나 내가 당신과 공유하는 것들을 사용하십시오.
Laiv

13

당신이 가진 전부 망치라면, 모든 것이 못처럼 보입니다. 여기서 문제는 검색 페이지를 RESTful 페이지로 변환하려고 시도하는 것이므로 RESTful 디자인이 해결하는 일반적인 패턴은 거의 없습니다.

백엔드에서 필요한 정보를 얻으려면 사용자가 제공 한 매개 변수와 함께 POST 요청을 수행하면됩니다. 검색을 수행하는 것 외에 다른 작업을 수행 할 필요가 없다고 가정하므로이 페이지를 통해 삽입 할 필요는 없습니다. 그냥 / A를 추가 당신이 당신의 / 사용자 페이지와 충돌로 실행하는 위험을 감수하지 않아도 당신의 URL의 끝에 검색 편안하고합니다.


2
@LiLou_ :이 요구 사항에는 두 가지 현실적인 가능성이 있습니다. 1. 모든 데이터를 프런트 엔드로 읽고 필터링을 수행하십시오. 필요한 메모리 양에서는 금지 될 수 있습니다. 2. 검색 기준이 변경 될 때마다 서버에 새로 요청하십시오. 이것이 POST 또는 GET 요청인지는 중요하지 않지만, 관련된 네트워크 대기 시간은 사용자의 "실시간"업데이트 감각에 지장을 줄 수 있습니다.
Bart van Ingen Schenau

2
동의하지 않을 것에 동의합니다. POST는 의미 상 다른 것을 의미합니다. 매개 변수가 너무 많으면 응용 프로그램 수준에서 오류가 발생하면 GET을 사용하여 쿼리 매개 변수의 모든 필터 데이터를 전달하는 것이 좋습니다.
CodeYogi

2
@CodeYogi 고객은 때때로 토론의 여지를주지 않습니다. 나는 자체 필터를 사용하여 각각 40-50 열로 Excel과 같은보기 페이지를 구현했습니다. 물론 정렬 가능합니다. 어쨌든 여전히 GET으로 가능하지만 너무
멋지지는

1
이 경우 @Laiv는 POST가 서버 상태 변경을위한 것이기 때문에 진지한 논의가 필요합니다. 이와 같은 사용 사례는 예외적이지 않으므로 해킹없이 처리해야합니다.
CodeYogi

2
이러한 경우 문서 는 필수입니다. 고객의 응용 프로그램 사용성에 대해 진지하게 논의했습니다. 나중에 최종 사용자가 나와 동의했기 때문에 옳은 것으로 판명되었습니다. 그러나 때로는 전투를 선택해야합니다.
Laiv

0

그것은 당신의 API 모델이 무엇인지에 전적으로 달려 있습니다 : 없음 또는 동사.

API가 none이면 다음과 같이 객체 목록을 얻을 수 있습니다.

GET: /api/v1/objects

이 경우 데이터를 요청 매개 변수로 보내야합니다. 따라서 매개 변수를 간단한 키-값 목록으로 설명해야합니다.

GET: /api/v1/objects

key1 : val1
key2.key1 : val 21
key2.key2 : val 22
....

일부 플랫폼은 커스텀 파라미터 리졸버 (예 : Spring MVC)를 지원합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.