검색을위한 RESTful URL 디자인


427

검색을 RESTful URL로 표현할 수있는 합리적인 방법을 찾고 있습니다.

설정 : 차가 차고에있을 수있는 두 가지 모델 인 Cars and Garages가 있습니다. 그래서 내 URL은 다음과 같습니다.

/car/xxxx
  xxx == car id
  returns car with given id

/garage/yyy
  yyy = garage id
  returns garage with given id

자동차는 자체적으로 존재할 수 있으므로 (/ car) 차고에 존재할 수 있습니다. 주어진 차고에있는 모든 차를 대표하는 올바른 방법은 무엇입니까? 다음과 같은 것 :

/garage/yyy/cars     ?

차고 yyy와 zzz에서 자동차를 결합하는 것은 어떻습니까?

특정 속성을 가진 자동차를 검색하는 올바른 방법은 무엇입니까? 4 개의 문이있는 모든 파란색 세단 형 자동차를 보여주세요.

/car/search?color=blue&type=sedan&doors=4

아니면 대신 / cars 여야합니까?

"검색"을 사용하는 것은 부적절한 것 같습니다. 더 나은 방법 / 용어는 무엇입니까? 그냥 있어야 :

/cars/?color=blue&type=sedan&doors=4

검색 매개 변수가 PATHINFO 또는 QUERYSTRING의 일부 여야합니까?

간단히 말해 교차 모델 REST URL 디자인 및 검색에 대한 지침을 찾고 있습니다.

[업데이트] 저스틴의 대답이 마음에 들지만 멀티 필드 검색 사례를 다루지 않습니다.

/cars/color:blue/type:sedan/doors:4

또는 그런 것. 우리는 어떻게 가나 요

/cars/color/blue

여러 현장 사건에?


16
그것은 혼합, 영어 잘 보이지만 /cars과 /car의미 론적 때문에 나쁜 생각이 아니다. 해당 범주에 둘 이상의 항목이있을 때는 항상 복수형을 사용하십시오.
— Zaz

4
이것들은 나쁜 대답입니다. 검색은 쿼리 문자열을 사용해야합니다. 쿼리 문자열은 올바르게 사용될 때 (예 : 검색) 100 % RESTful입니다.
— pbreitenbach

답변:


435

검색하려면 querystrings를 사용하십시오. 이것은 완벽하게 편안합니다.

/cars?color=blue&type=sedan&doors=4

일반 쿼리 문자열의 장점은 표준이며 널리 이해되며 form-get에서 생성 될 수 있다는 것입니다.


42
맞습니다. 쿼리 문자열의 요점은 검색과 같은 작업을 수행하는 것입니다.
— aehlke

22
실제로 이는 RFC3986 에 따라 경로 및 쿼리 문자열이 리소스를 식별하므로 정확 합니다. 또한 적절한 이름 지정은 간단합니다 /cars?color=whatever.
— Lloeki 2016 년

35
비교기 (>, <, <=,> =)를 원하는 경우는 어떻습니까? / cars? rating <= 3?
— Jesse

3
쿼리 문자열 아래에 중첩 된 리소스에 액세스하려면 어떻게합니까? 예 : /cars?color=blue&type=sedan&doors=4/engines작동하지 않습니다
— Abe Voelker

9
@mjs /cars?param=value는 자동차 목록에 대한 간단한 필터링 을 /cars/search?param=value위한 것으로 검색 결과, 검색 등이 포함될 수 있는 검색 ( 영구 없이) 을 생성하기위한 것 /cars/search/mysearch입니다. 그것을보십시오 : stackoverflow.com/a/18933902/1480391
— Yves M.

121

편안하고 꽤 URL 설계 구조에 따라 자원을 표시에 관한 것입니다 (디렉토리 같은 구조, 날짜 : 기사 / 5분의 2,005 / 13 객체와 그것의 속성은, ..), 슬래시는 /계층 구조를 나타냅니다의를 사용하는 -id대신.

계층 적 구조

나는 개인적으로 선호합니다 :

/garage-id/cars/car-id
/cars/car-id   #for cars not in garages

사용자가 /car-id부품을 제거하면 cars직관적으로 미리보기가 표시됩니다. 사용자는 자신이 나무의 어디에 있는지, 무엇을보고 있는지 정확하게 알고 있습니다. 그는 첫 번째 모습에서 차고와 자동차가 관련되어 있음을 알고 있습니다. /car-id또한 서로 달리 속함을 나타냅니다 /car/id.

수색

검색어는 그대로입니다 . 선호하는 항목 만 있습니다. 재미있는 부분은 검색에 참여할 때 나타납니다 (아래 참조).

/cars?color=blue;type=sedan   #most prefered by me
/cars;color-blue+doors-4+type-sedan   #looks good when using car-id
/cars?color=blue&doors=4&type=sedan   #I don't recommend using &*

또는 기본적으로 위에서 설명한대로 슬래시가 아닌 모든 것.
공식 : /cars[?;]color[=-:]blue[,;+&], * &는 처음에는 텍스트에서 인식 할 수 없으므로 기호를 사용하지 않습니다 .

** URI에서 JSON 객체를 전달하는 것이 RESTful이라는 것을 알고 있습니까? **

옵션 목록

/cars?color=black,blue,red;doors=3,5;type=sedan   #most prefered by me
/cars?color:black:blue:red;doors:3:5;type:sedan
/cars?color(black,blue,red);doors(3,5);type(sedan)   #does not look bad at all
/cars?color:(black,blue,red);doors:(3,5);type:sedan   #little difference

가능한 기능?

검색 문자열 부정 (!)
모든 차량을 검색하지만 검은 색 과 빨간색은 검색하지 않습니다 .
?color=!black,!red
color:(!black,!red)

가입 검색
검색 빨간색 또는 파란색 또는 검은 색 으로 자동차 3 차고 아이디에 문을 1..20 또는 101..103 또는 999 만 하지 5 /garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
그런 다음 더 복잡한 검색 쿼리를 구성 할 수 있습니다. ( 하위 문자열 일치 에 대한 아이디어는 CSS3 속성 일치 를 보십시오 . 예를 들어 "bar"를 포함하는 사용자 검색 user*=bar)

결론

그냥 마음에 계속, 결국처럼 그러나 당신이 그것을 할 수 있기 때문에 어쨌든, 이것은 당신을위한 가장 중요한 부분이 될 수있는 편안하고 URI 쉽게 예를 들어, 디렉토리와 같은 이해할 수있는 구조를 나타내며 /directory/file, /collection/node/item날짜가 /articles/{year}/{month}/{day}.. 그리고 당신은 생략하는 경우를 마지막 세그먼트 중 하나라도 즉시 얻을 수 있습니다.

따라서이 모든 문자는 인코딩되지 않은 상태 로 허용됩니다 .

  • 예약되지 않음 : a-zA-Z0-9_.-~
    일반적으로 인코딩 및 인코딩이 모두 허용되며 두 가지 용도가 동일합니다.
  • 특수 문자: $-_.+!*'(),
  • reserved : ;/?:@=&
    그들이 나타내는 목적으로 인코딩되지 않은 상태로 사용될 수 있으며, 그렇지 않으면 인코딩되어야합니다.
  • 안전하지 않은 : 안전하지 않은 <>"#%{}|\^~[]`
    이유와 암호화해야하는 이유 : RFC 1738 2.2 참조

    더 많은 문자 클래스 는 RFC 1738 # page-20 을 참조하십시오 .

RFC 3986 2.2 참조
내가 이전에 말한에도 불구하고, 여기에 몇 가지가 있다는 것을 의미, 분리 문자의 일반적인 구분이다 "입니다" 다른 사람보다 더 중요합니다.

  • 일반 삼각근 : :/?#[]@
  • 서브 델리 미터 : !$&'()*+,;=

더 읽기 :
계층 구조 : 2.3를 참조 , 1.2.3 참조
URL 경로 매개 변수 구문
CSS3 속성 일치
IBM을 : RESTful 웹 서비스 - 기본 사항
참고 : RFC 1738, RFC 3986에 의해 업데이트 된


3
쿼리 문자열에 JSON을 사용하지 않았다고 생각합니다. 내가 사용하지 않고 복잡한 검색 구조에 직면 한 문제에 대한 답 POST이다. 또한, 당신이 대답 한 다른 아이디어들도 높이 평가할 수 있습니다. 매우 감사합니다!
— gustavohenke

4
@ Qwerty : 좋은 게시물! 궁금한 점이 있습니다. ;반대로 사용하는 유일한 이유 &는 가독성입니까? 그렇다면 &더 일반적인 구분 기호이므로 실제로 선호하는 것 같습니다 ... 맞습니까? :) 감사!
— Flo

3
@Flo Yes 정확히 :)이지만 &구분 기호는 개발자에게만 알려져 있습니다. 부모, 조부모 및 교육을받지 않은 인구는 일반 텍스트로 사용되는 구분 기호를 사용할 수 있습니다.
— Qwerty

17
쿼리 문자열이 잘 이해되고 표준 일 때 왜 비표준 체계를 구성합니까?
— pbreitenbach

1
@Qwerty / search? cars = red, blue, green & garages = 1,2,3에서 멈추지 않거나 <multiselect> 양식을 사용하는 경우 : / search? cars = red & cars = blue &
— garages

36

경로에 매개 변수를 사용하면 몇 가지 장점이 있지만 IMO에는 몇 가지 중요한 요소가 있습니다.

  • 검색 쿼리에 필요한 모든 문자가 URL에 허용되는 것은 아닙니다. 대부분의 문장 부호 및 유니 코드 문자는 쿼리 문자열 매개 변수로 URL 인코딩되어야합니다. 나는 같은 문제로 씨름하고 있습니다. URL에서 XPath를 사용하고 싶지만 모든 XPath 구문이 URI 경로와 호환되는 것은 아닙니다. 따라서 간단한 경로 의 경우 운전자 도어 XML 문서에서 /cars/doors/driver/lock/combination' combination'요소 를 찾는 것이 적절합니다 . 그러나 /car/doors[id='driver' and lock/combination='1234']그렇게 친절하지 않습니다.

  • 속성 중 하나를 기반으로 리소스를 필터링하는 것과 리소스를 지정하는 것에는 차이가 있습니다.

    예를 들어

    /cars/colors 모든 자동차의 모든 색상 목록을 반환합니다 (반환 된 리소스는 색상 개체의 모음입니다).

    /cars/colors/red,blue,green 자동차 컬렉션이 아닌 빨강, 파랑 또는 녹색의 색상 개체 목록을 반환합니다.

    차를 반환하려면 경로는

    /cars?color=red,blue,green 또는 /cars/search?color=red,blue,green

  • 이름 / 값 쌍이 이름 / 값 쌍이 아닌 나머지 경로와 분리되지 않으므로 경로의 매개 변수를 읽기가 더 어렵습니다.

마지막 의견. 나는 단수와 복수 사이의 경로를 바꾸지 않기 때문에 /garages/yyy/cars(항상 복수형)을 선호 합니다 /garage/yyy/cars(아마도 원래 답변에서는 오타 일 것입니다). 's'가 추가 된 단어의 경우 변경이 그렇게 나쁘지는 않지만로 변경 /person/yyy/friends하는 /people/yyy것은 번거로운 것 같습니다.


2
예, 동의합니다 ... 외에도 URL 경로 구조에는 엔티티 간의 자연 관계, 차고에 많은 차가 있고 차가 차고에 속하는 것처럼 내 리소스의 일종의 맵이 반영되어야합니다 ... 필터 매개 변수, 우리가 말하고있는 원인, 쿼리 문자열을 쿼리하기 위해 ... 어떻게 생각하십니까?
— 2009 년

31

Peter의 답변을 넓히려면 검색을 일류 자원으로 만들 수 있습니다.

POST    /searches          # create a new search
GET     /searches          # list all searches (admin)
GET     /searches/{id}     # show the results of a previously-run search
DELETE  /searches/{id}     # delete a search (admin)

검색 리소스에는 색상, 모델, 차고 상태 등의 필드가 있으며 XML, JSON 또는 기타 형식으로 지정할 수 있습니다. Car and Garage 리소스와 마찬가지로 인증을 기반으로 검색에 대한 액세스를 제한 할 수 있습니다. 동일한 검색을 자주 실행하는 사용자는 자신의 프로필에 저장하여 다시 만들 필요가 없습니다. URL은 많은 경우 이메일을 통해 쉽게 거래 할 수있을 정도로 짧습니다. 이러한 저장된 검색은 사용자 정의 RSS 피드 등의 기초가 될 수 있습니다.

검색을 리소스로 생각할 때 검색을 사용할 가능성이 많이 있습니다.

아이디어는이 Railscast 에서 더 자세히 설명됩니다 .


6
이 접근 방식이 불안한 프로토콜로 작업한다는 생각에 어긋나지 않습니까? 내 말은, DB에 대한 검색을 유지하는 것은 일종의 상태 저장 연결을 갖는 것입니다.
— 2009 년

5
상태 저장 서비스를받는 것과 같습니다. 또한 새로운 차량 또는 차고를 추가 할 때마다 서비스 상태가 변경됩니다. 검색은 전체 HTTP 동사와 함께 사용할 수있는 또 다른 리소스입니다.
— Rich Apodaca

2
위의 URI 규칙은 어떻게 정의됩니까?
— Rich Apodaca

3
REST는 예쁜 URI 또는 ​​URI 중첩 등과 관련이 없습니다. URI를 API의 일부로 정의하면 REST가 아닙니다.
— aehlke

2
나는 이것을 전에 주장했다. 이것은 상태가 좋지는 않지만 끔찍한 것입니다. 검색의 '삭제'가 명확하지는 않습니다. 여기서 검색 엔티티를 삭제한다고 말하고 있지만 해당 검색을 통해 찾은 결과를 삭제하고 싶습니다. '검색어'를 리소스로 추가하지 마십시오.
— thecoshman

12

Justin의 대답은 아마도 갈 길이지만 일부 응용 프로그램에서는 명명 된 저장된 검색을 지원하려는 경우와 같이 특정 검색을 자체 리소스로 간주하는 것이 좋습니다.

/search/{searchQuery}

또는

/search/{savedSearchName}

11
아니. 행동이 자원이되는 것은 결코 의미가 없습니다.
— thecoshman

3
위의 의견에서 언급했듯이 @thecoshman은 검색도 명사입니다.
— andho

6

검색을 구현하기 위해 두 가지 접근 방식을 사용합니다.

1) 가장 간단한 경우, 관련 요소를 쿼리하고 탐색합니다.

    /cars?q.garage.id.eq=1

이는 차고 ID가 1 인 자동차를 쿼리합니다.

보다 복잡한 검색을 만들 수도 있습니다.

    /cars?q.garage.street.eq=FirstStreet&q.color.ne=red&offset=300&max=100

빨간색이 아닌 FirstStreet의 모든 차고에있는 차량 (3 페이지, 페이지 당 100 요소).

2) 복잡한 쿼리는 생성되어 복구 할 수있는 일반 리소스로 간주됩니다.

    POST /searches  => Create
    GET  /searches/1  => Recover search
    GET  /searches/1?offset=300&max=100  => pagination in search

검색 작성을위한 POST 본문은 다음과 같습니다.

    {  
       "$class":"test.Car",
       "$q":{
          "$eq" : { "color" : "red" },
          "garage" : {
             "$ne" : { "street" : "FirstStreet" }
          }
       }
    }

Grails (기준 DSL)를 기반으로합니다. http://grails.org/doc/2.4.3/ref/Domain%20Classes/createCriteria.html


5

REST가 아닙니다. API 내부의 리소스에 대한 URI를 정의 할 수 없습니다. 자원 탐색은 하이퍼 텍스트 중심이어야합니다. 예쁜 URI와 많은 양의 커플 링을 원한다면 RESTful 아키텍처의 제약 조건을 직접 위반하기 때문에 REST라고 부르지 마십시오.

REST 발명가 가이 기사 를 참조하십시오 .


28
REST가 아닌 것이 정확하고 RESTful 시스템의 URL 디자인입니다. 그러나 RESTful 아키텍처를 위반한다고 말하는 것은 잘못되었습니다. REST의 하이퍼 텍스트 제한 조건은 RESTful 시스템의 올바른 URL 디자인과 직교합니다. 몇 년 전 REST 목록에서 Roy T. Fielding과의 대화가 있었음을 기억합니다. 다른 방법으로 하이퍼 텍스트 및 URL 디자인이 가능합니다. RESTful 시스템의 URL 디자인은 프로그래밍의 들여 쓰기와 같습니다. 필수는 아니지만 매우 좋은 아이디어 (Python 등 무시)
— MikeSchinkel

2
죄송합니다. 맞습니다. 방금 OP에서 고객이 URL을 구성하는 방법을 알게 할 것이라는 인상을 받았습니다. 그는 API의 URL "레이아웃"을 만들 것입니다. 즉 REST의 위반이 될 것입니다.
— aehlke

@aehlke, 귀하의 의견과 일치하도록 답변을 업데이트해야합니다.
— James McMahon

1
레벨 2 Richardson 성숙 모델을 준수합니다. 레벨 3을 언급하고 있습니다. REST를 점진적으로 채택 할 수있는 것으로 받아들이십시오.
— Jules Randolph

1
@Jules Randolph-사과합니다. 제 답변은 Richardson 성숙 모델이 처음 만들어지고 마틴 파울러 (Martin Fowler)와 다른 저술가들이 대중화하기 전에 수개월 만에 작성되었습니다. :) 실제로 따라야 할 교훈적인 모델입니다. 답변을 자유롭게 편집하십시오.
— aehlke

1

저스틴의 반응이 마음에 들지만 검색보다는 필터를 더 정확하게 표현한다고 생각합니다. 캠으로 시작하는 이름을 가진 자동차에 대해 알고 싶다면 어떻게해야합니까?

내가 보는 방식으로 특정 리소스를 처리하는 방식으로 빌드 할 수 있습니다.
/ cars / cam *

또는 필터에 간단히 추가 할 수 있습니다.
/ cars / doors / 4 / name / cam * / colors / red, blue, green

개인적으로, 나는 후자를 선호하지만, 결코 REST 전문가가 아닙니다 (2 주 전쯤에 처음 들어 본 적이 있습니다 ...)


: 이것처럼/cars?name=cam*
— DanMan

1

RESTful은 URL의 / cars / search에서 동사를 사용하지 않는 것이 좋습니다. API를 필터링 / 검색 / 페이지 매김하는 올바른 방법은 쿼리 매개 변수를 사용하는 것입니다. 그러나 규범을 어기는 경우가 있습니다. 예를 들어 여러 리소스를 검색하는 경우 / search? q = query와 같은 것을 사용해야합니다.

http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/ 를 통해 RESTful API 설계를위한 모범 사례를 이해할 수 있습니다.


1
검색도 명사입니다 😀
— jith912

1

또한 나는 또한 제안 할 것이다 :

/cars/search/all{?color,model,year}
/cars/search/by-parameters{?color,model,year}
/cars/search/by-vendor{?vendor}

여기서 Search자원의 하위 자원으로 간주됩니다 Cars.


1

귀하의 경우에 좋은 옵션이 많이 있습니다. 여전히 POST 본문 사용을 고려해야합니다.

쿼리 문자열은 예제에 적합하지만 임의의 긴 항목 목록 또는 부울 조건과 같이 더 복잡한 것이 있으면 게시물을 문서로 정의하여 클라이언트가 POST를 통해 전송하도록 할 수 있습니다.

이는 서버 URL 길이 제한을 피할뿐만 아니라보다 유연한 검색 설명을 허용합니다.


-4

내 조언은 다음과 같습니다.

/garages
  Returns list of garages (think JSON array here)
/garages/yyy
  Returns specific garage
/garage/yyy/cars
  Returns list of cars in garage
/garages/cars
  Returns list of all cars in all garages (may not be practical of course)
/cars
  Returns list of all cars
/cars/xxx
  Returns specific car
/cars/colors
  Returns lists of all posible colors for cars
/cars/colors/red,blue,green
  Returns list of cars of the specific colors (yes commas are allowed :) )

편집하다:

/cars/colors/red,blue,green/doors/2
  Returns list of all red,blue, and green cars with 2 doors.
/cars/type/hatchback,coupe/colors/red,blue,green/
  Same idea as the above but a lil more intuitive.
/cars/colors/red,blue,green/doors/two-door,four-door
  All cars that are red, blue, green and have either two or four doors.

잘하면 그것은 당신에게 아이디어를 제공합니다. 본질적으로 Rest API는 쉽게 검색 할 수 있어야하고 데이터를 탐색 할 수 있어야합니다. 쿼리 문자열이 아닌 URL을 사용하는 또 다른 장점은 웹 서버에 존재하는 기본 캐싱 메커니즘을 사용하여 HTTP 트래픽을 이용할 수 있다는 것입니다.

REST에서 쿼리 문자열의 악을 설명하는 페이지에 대한 링크는 다음과 같습니다. http://web.archive.org/web/20070815111413/http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful

일반 페이지가 나를 위해 작동하지 않기 때문에 Google의 캐시를 사용했습니다 .http : //rest.blueoxen.net/cgi-bin/wiki.pl? QueryStringsConsideredHarmful


1
자세한 답변 주셔서 감사합니다. 마지막으로 색상과 문 수를 모두 검색하려면 어떻게해야합니까? / cars / colors / red, blue, green / doors / 4 맞지 않는 것 같습니다.
— Parand

2
URL의 쉼표는 나에게 맞지 않지만 여전히 유효한 휴식입니다. 나는 그것이 단지 패러다임 전환이라고 생각합니다.
— 저스틴 Bozonier

21
이 제안이 마음에 들지 않습니다. 당신은 어떻게 차이 알 것 /cars/colors/red,blue,green와 /cars/colors/green,blue,red? URI의 경로 요소는 계층 구조이어야하며 실제로는 그렇지 않습니다. 이것이 쿼리 문자열이 가장 적합한 상황이라고 생각합니다.
— troelskn

62
이것은 나쁜 대답입니다. 실제로 검색을 구현하는 올바른 방법은 쿼리 문자열을 사용하는 것입니다. 쿼리 문자열은 올바르게 사용될 때 사소한 것이 아닙니다. 인용 된 기사는 검색을 언급하지 않습니다. 제시된 예는 분명히 고문을 받고 더 많은 매개 변수를 잘 견디지 못합니다.
— pbreitenbach

4
쿼리 문자열은 기본적으로 여러 매개 변수가 있어도 리소스 쿼리 문제를 해결하기 위해 만들어졌습니다. "RESTful"API를 활성화하기 위해 URI를 바꾸는 것은 위험하고 눈에 잘 띄지 않는 것 같습니다. 특히 URI에서 매개 변수의 다양한 순열을 처리하기 위해 복잡한 매핑을 작성해야하기 때문입니다. 더 나은 방법은 URI에 이미 세미콜론을 사용한다는 기존 개념을 사용하는 것입니다 : doriantaylor.com/policy/http-url-path-parameter-syntax
— Anatoly G
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.