검색을위한 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.