태그 보관물: api

api

URI 대 쿼리 문자열로 REST API 디자인 이상의 부모에게 매핑 할 수 있습니다.

다음과 같은 세 가지 리소스가 있다고 가정 해 봅시다.

Grandparent (collection) -> Parent (collection) -> and Child (collection)

위의 내용은 다음과 같은 리소스 간의 관계를 보여줍니다. 각 조부모는 하나 이상의 부모에게 매핑 할 수 있습니다. 각 부모는 하나 이상의 자녀에게 매핑 될 수 있습니다. 하위 리소스에 대한 검색을 지원하지만 필터 기준을 사용하는 기능을 원합니다.

내 고객이 조부모에 대한 id 참조를 전달하면 해당 조부모의 직계 후손 인 아동 만 검색하려고합니다.

내 고객이 부모에게 id 참조를 전달하면 부모의 직계 후손 인 아동에 대해서만 검색하고 싶습니다.

나는 다음과 같은 것을 생각했다.

GET /myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}

GET /myservice/api/v1/parents/{parentID}/children?search={text}

위의 요구 사항에 대해 각각

그러나 나는 또한 다음과 같이 할 수 있습니다 :

GET /myservice/api/v1/children?search={text}&grandparentID={id}&parentID=${id}

이 디자인에서는 클라이언트가 쿼리 문자열에서 grandparentID 또는 parentID 중 하나 또는 둘 다를 전달할 수 있습니다.

내 질문은 :

1) 어떤 API 디자인이 더 RESTful하고 왜 그럴까요? 의미 적으로, 그들은 같은 방식으로 의미하고 행동합니다. URI의 마지막 리소스는 “children”이며 클라이언트가 children 리소스에서 작동하고 있음을 나타냅니다.

2) 고객의 관점에서 이해 성과 디자이너의 관점에서 유지 보수 측면에서 각각의 장단점은 무엇입니까?

3) 리소스에 대한 “필터링”외에 실제로 쿼리 문자열이 무엇입니까? 첫 번째 방법을 사용하면 필터 매개 변수가 쿼리 문자열 매개 변수 대신 경로 매개 변수로 URI 자체에 포함됩니다.

감사!



답변

먼저

따라 RFC 3986 §3.4 (통일 자원 식별자가 § (구문 구성 요소) | 조회

3.4 질의

쿼리 구성 요소에는 경로 구성 요소 (섹션 3.3)의 데이터와 함께 URI 체계 및 명명 권한 (있는 경우) 범위 내에서 리소스를 식별하는 비 계층 데이터가 포함됩니다.

쿼리 구성 요소는 비 계층 데이터를 검색하기위한 것입니다. 가계도보다 본질적으로 더 계층적인 것들이 거의 없습니다! Ergo- 인터넷에서 시스템을 개발하고 형식, 프로토콜 및 프레임 워크를 준수하기 위해 “REST-y”인지 여부에 관계없이이 정보를 식별하기 위해 쿼리 문자열을 사용해서는 안됩니다.

REST는이 정의와 관련이 없습니다.

특정 질문을 해결하기 전에 “search”의 쿼리 매개 변수 이름이 잘못되었습니다. 쿼리 세그먼트를 키-값 쌍의 사전으로 취급하는 것이 좋습니다.

쿼리 문자열을보다 적절하게 정의 할 수 있습니다.

?first_name={firstName}&last_name={lastName}&birth_date={birthDate} 기타

특정 질문에 대답하려면

1) 어떤 API 디자인이 더 RESTful하고 왜 그럴까요? 의미 적으로, 그들은 같은 방식으로 의미하고 행동합니다. URI의 마지막 리소스는 “children”이며 클라이언트가 children 리소스에서 작동하고 있음을 나타냅니다.

나는 이것이 당신이 믿는 것처럼 명확한 컷이라고 생각하지 않습니다.

이 자원 인터페이스 중 어느 것도 RESTful이 아닙니다. RESTful 아키텍처 스타일 의 주요 전제 조건은 애플리케이션 상태 전이가 서버에서 하이퍼 미디어로 통신되어야한다는 것입니다. 사람들은 URI 구조에 대해 어떤 식 으로든 “RESTful URIs”를 만들려고 노력했지만 REST에 관한 공식 문헌은 실제로 이에 대해 거의 말할 것이 없다. 내 개인적인 의견은 REST에 관한 많은 메타 정보가 오래되고 나쁜 습관을 깰 의도로 출판되었다는 것입니다. (정말로 “RESTful”시스템을 구축하는 것은 실제로 상당한 작업입니다. 업계는 “REST”로 빛을 발하며 비 관념적인 자격 및 제한 사항에 대한 일부 직교 문제를 보완했습니다.)

REST 문서에 따르면 애플리케이션 프로토콜로 HTTP를 사용하려는 경우 프로토콜 스펙의 공식 요구 사항을 준수해야하며 “가는대로 http를 작성하고 여전히 http를 사용하고 있다고 선언 할 수 없습니다” ; 자원을 식별하기 위해 URI를 사용하려는 경우 URI / URL에 대한 스펙의 공식 요구 사항을 준수해야합니다.

귀하의 질문은 위에 링크 된 RFC3986 §3.4에 의해 직접 해결됩니다. 이 문제에 대한 결론은 그 규격에 부합하는 URI는 시스템이 실제로하고 싶은 경우, “편안하고”API를 고려하는 것이 부족에도 불구하고 “편안하고”당신은 당신이를 통해 계층 적 데이터를 식별 할 수없는, HTTP와 URI를 사용하는 다음과 같은 이유로 쿼리 문자열 :

3.4 질의

쿼리 구성 요소에 비 계층 데이터가 포함되어 있습니다.

… 그만큼 간단합니다.

2) 고객의 관점에서 이해 성과 디자이너의 관점에서 유지 보수 측면에서 각각의 장단점은 무엇입니까?

처음 두 사람의 “프로”는 그들이 올바른 길 을 가고 있다는 것 입니다. 세 번째 것의 “단점”은 그것이 잘못 평평한 것처럼 보입니다.

이해 및 유지 관리 가능성에 관한 한, 이는 주관적이며 클라이언트 개발자의 이해 수준과 디자이너의 디자인에 달려 있습니다. URI 사양은 URI의 형식을 지정하는 방법에 대한 결정적인 답변입니다. 계층 적 데이터는 경로와 경로 매개 변수로 표시되어야합니다. 비 계층 적 데이터는 쿼리에 표시되어야합니다. 조각의 의미론은 요청 된 표현의 미디어 유형에 따라 달라지기 때문에 조각이 더 복잡합니다. 따라서 질문의 “이해성”구성 요소를 해결하기 위해 처음 두 URI가 실제로 말하는 것을 정확하게 변환하려고 시도합니다. 그런 다음 유효한 URI로 달성하려는 말을 표현하려고 시도합니다.

동사 URI를 의미 적 의미로 변환
/myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}
이것은 조부모의 부모를 위해 자녀를 찾으 search={text}
십시오. URI로 말한 내용은 조부모의 형제를 검색하는 경우에만 일관됩니다. 당신의 “조부모, 부모님, 자녀들”과 함께 당신은 “조부모”가 부모에게 한 세대 올라가서 부모의 자녀를 보며 “조부모”세대로 돌아온 것을 발견했습니다.

/myservice/api/v1/parents/{parentID}/children?search={text}
이것은 {parentID}에 의해 식별 된 부모의 경우 원하는 것을 가진 것에 ?search={text}더 가깝고 전체 API를 모델링하는 데 사용될 수있는 부모-자식 관계를 나타냅니다. 이러한 방식으로 모델링하기 위해, “grandparentId”가있는 경우, 자신이 가지고있는 ID와보고자하는 가족 그래프의 일부 사이에 간접 계층이 있음을 인식해야하는 부담이 고객에게 부과됩니다. “grandparentId”로 “자식”을 찾으려면 /parents/{parentID}/children서비스를 호출 한 다음 반환 된 자식을 찾아 자녀의 개인 식별자를 검색하십시오.

URI로 요구 사항 구현
트리를 걸을 수있는보다 확장 가능한 리소스 식별자를 모델링하려는 경우이를 달성 할 수있는 몇 가지 방법을 생각할 수 있습니다.

1) 첫 번째는 이미 언급 한 것입니다. “사람”의 그래프를 복합 구조로 나타냅니다. 각 사람은 부모 경로를 통해 위에있는 세대와 어린이 경로를 통해 아래에있는 세대에 대해 언급합니다.

/Persons/Joe/Parents/Mother/Parents
조의 어머니 조부모를 잡는 방법이 될 것입니다.

/Persons/Joe/Parents/Parents
조의 조부모를 모두 잡는 방법이 될 것입니다.

/Persons/Joe/Parents/Parents?id={Joe.GrandparentID}
Joe의 조부모가 당신이 가지고있는 식별자를 가지고있을 것입니다.

“모자 / 부모 / 부모”패턴에서 분기 식별이 없기 때문에 서버에서 df를 강제 실행하여 작업에 따라 성능에 불이익이있을 수 있습니다. 임의의 수의 세대를 지원하는 능력. 어떤 이유로 8 세대를 조회하려는 경우이를 다음과 같이 나타낼 수 있습니다.

/Persons/Joe/Parents/Parents/Parents/Parents/Parents/Parents/Parents/Parents?id={Joe.NotableAncestor}

그러나 이것은 경로 매개 변수를 통해이 데이터를 나타내는 두 번째 지배적 인 옵션으로 이어집니다.


2) 경로 매개 변수를 사용하여 “계층 구조 쿼리”소비자에 대한 부담을 덜어주고 이해하기 쉬운 API를 갖도록 다음 구조를 개발할 수 있습니다.

147 세대를 되돌아 보려면이 매개 변수를 경로 매개 변수로 표시하면

/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor}

조부모에게서 조를 찾으려면 조의 Id에 대해 알려진 세대 수의 그래프를 볼 수 있습니다.
/Persons/JoesGreatGrandparent/Children;generations=3?id={Joe.Id}

이러한 접근 방식에서 가장 주목할 점은 식별자와 요청에 추가 정보가 없으면 첫 번째 URI가 Joe.NotableAncestor의 식별자를 사용하여 Joe에서 Person 147 세대를 검색한다는 것을 예상해야합니다. 두 번째는 Joe를 검색해야합니다. 실제로 원하는 것은 호출 클라이언트가 전체 노드 세트와 루트 Person과 URI의 최종 컨텍스트 사이의 관계를 검색 할 수 있다고 가정하십시오. 동일한 URI (일부 추가 데코레이션 사용) text/vnd.graphviz를 사용하여 요청시 수락 .dot표시 (그래프 표시를 위한 IANA 등록 미디어 유형 )를 설정할 수 있습니다 . 그런 다음 URI를 다음으로 변경하십시오.

/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor.Id}#directed

HTTP 요청 헤더
Accept: text/vnd.graphviz
를 사용하면 클라이언트가 Joe와 147 세대 사이의 세대 계층 구조에 대한 지시 그래프를 원한다는 것을 명확하게 전달할 수 있습니다.

text / vnd.graphviz에 조각에 대해 사전 정의 된 의미가 있는지 확실하지 않습니다. 명령 검색에서 아무것도 찾을 수 없습니다. 해당 매체 유형에 실제로 사전 정의 된 조각 정보가있는 경우 해당 의미론을 따라 적합한 URI를 작성해야합니다. 그러나 이러한 의미가 사전 정의되어 있지 않은 경우 URI 사양에 따르면 조각 식별자의 의미가 제한되지 않고 서버에 의해 정의되어이 사용법이 유효합니다.


3) 리소스에 대한 “필터링”외에 실제로 쿼리 문자열이 무엇입니까? 첫 번째 방법을 사용하면 필터 매개 변수가 쿼리 문자열 매개 변수 대신 경로 매개 변수로 URI 자체에 포함됩니다.

필자는이 문제를 이미 철저히 극복했다고 생각하지만 쿼리 문자열은 “필터링”리소스가 아닙니다. 비 계층 적 데이터에서 리소스 를 식별 하기 위한 것입니다. 당신이 이동하여 경로 계층 구조를 드릴 다운 한 경우
/person/{id}/children/와 사용자가 확인하고자하는 특정 아동 또는 특정 아이들의 세트를, 당신은 당신이 식별하는 집합에 적용 몇 가지 속성을 사용하고는 쿼리 내부에 포함됩니다.


답변

여기가 잘못되었습니다.

고객이 ID 참조를 전달하면

REST 시스템에서 클라이언트는 ID로 방해받지 않아야합니다. 클라이언트가 알아야 할 유일한 리소스 식별자는 URI 여야합니다. 이것이 “균일 인터페이스”의 원리입니다.

클라이언트가 시스템과 어떻게 상호 작용하는지 생각해보십시오. 사용자가 조부모 목록을 탐색하기 시작하고 조부모의 자녀 중 하나를 선택하여로 이동한다고 가정 해 봅시다 /grandparent/123. 클라이언트가의 하위 항목을 검색 할 수 있어야하는 경우 /grandparent/123“HATEOAS”에 따라 쿼리를 수행 할 때 /grandparent/123반환 된 항목은 검색 인터페이스에 URL을 반환해야합니다. 이 URL에는 이미 포함 된 현재 조부모가 필터링하는 데 필요한 모든 데이터가 있어야합니다.

링크가 보이는 여부 /grandparent/123?search={term}/parent?grandparent=123&search={term}또는 /parent?grandparentTerm=someterm&someothergplocator=blah&search={term}REST에 따라 하찮은이다. 다른 URL {term}을 사용하더라도 모든 URL에 동일한 수의 매개 변수가있는 방식에 주목하십시오 . 기본 구현이 크게 다를 수 있지만 리소스 간의 논리적 관계가 동일하기 때문에 이러한 URL 중 하나를 전환하거나 특정 조부모에 따라 URL을 혼합하여 클라이언트가 중단되지 않을 수 있습니다.

대신 /grandparent/{grandparentID}?search={term}한 방향으로 갈 때 /children?parent={parentID}&search={term}a) 다른 방향으로 갈 때 필요한 서비스를 작성했다면 클라이언트가 개념적으로 유사한 다른 관계에 대해 서로 다른 것을 보간해야하기 때문에 너무 많은 결합입니다.

실제로 함께 /grandparent/123?search={term}가거나 /parent?grandparent=123&search={term}맛의 문제 인지 여부와 현재 구현이 더 쉬운 지 여부. URL 전략을 변경하거나 다른 부모-자녀 관계에 다른 전략을 사용하는 경우 클라이언트를 수정하지 않아도됩니다.


답변

사람들이 왜 URL에 ID 값을 넣는 것이 REST API를 의미한다고 생각하는지 모르겠습니다. REST는 동사를 처리하고 리소스를 전달하는 것에 관한 것입니다.

따라서 새로운 사용자를 PUT하려면 상당한 양의 데이터를 보내야하며 POST http 요청이 이상적이므로 키 (예 : 사용자 ID)를 보내더라도 사용자 데이터를 보내 게됩니다. (예 : 이름, 주소) POST 데이터.

이제 리소스 식별자를 URI에 넣는 것이 일반적인 관용어이지만, 이것은 “URI가 아닌 경우 REST가 아닌”표준 형식보다 더 많은 규칙입니다. 기억 원래 논문 REST의 정말 클라이언트 – 서버에서 HTTP (하지만, 분명히, HTTP는 REST를 구현하는 우리의 주요 형태이다)의 확장이 아니라 뭔가 데이터를 처리하기 위해, 모두의 관용구를 HTTP를 언급하지 않는다 .

예를 들어 Fielding은 학술 논문 요청을 예로 사용합니다. “맥주 마시기에 관한 Dr. John의 논문”리소스를 검색하려고하지만 초기 버전 또는 최신 버전을 원할 수도 있으므로 리소스 식별자는 단일 ID로 쉽게 참조 할 수없는 것일 수 있습니다. URI에 배치됩니다. REST는이를 가능하게하며 그 뒤에 의도 된 의도는 다음과 같습니다.

REST는 대신 식별되는 개념의 특성에 가장 적합한 자원 ID를 선택하여 작성자에게 의존합니다.

따라서 정적 URI를 사용하여 부모를 검색하지 못하게하고 쿼리 문자열에 검색어를 전달하여 정확한 사용자를 식별합니다. 이 경우 식별하는 ‘자원’은 조부모의 집합이므로 URI에는 URI의 일부로 ‘조부모’가 포함됩니다. REST에는 사용자의 표현을 결정하기 위해 설계된 ‘제어 데이터’개념이 포함됩니다. 리소스가 검색됩니다-이것들에 주어진 예는 캐시 제어뿐만 아니라 버전 제어입니다. 따라서 Dr John의 우수한 논문에 대한 나의 요청은 URI의 일부가 아닌 제어 데이터로 버전을 전달함으로써 구체화 될 수 있습니다.

일반적으로 언급되지 않은 REST 인터페이스의 예는 SMTP 라고 생각합니다 . 메일 메시지를 작성할 때 메일 메시지의 각 부분에 대한 자원 데이터와 함께 동사 (FROM, TO 등)를 보냅니다. http 동사를 사용하지 않지만 자체 세트를 사용하더라도 RESTful입니다.

URI에 리소스 식별이 필요하지만 ID 참조 일 필요는 없습니다. 이것은 제어 데이터, 쿼리 문자열 또는 POST 데이터로도 행복하게 보낼 수 있습니다. REST API에서 실제로 식별하는 것은 URI에 이미있는 아이를 쫓고 있다는 것입니다.

그래서 내 생각에 REST의 정의를 읽으면 자식 리소스를 요청하고 제어 데이터를 쿼리 문자열 형식으로 전달하여 반환 할 리소스를 결정합니다. 결과적으로 조부모 또는 부모에 대한 URI 요청을 할 수 없습니다. 당신이 원하는 아이들이 너무 용어 부모 / 조부모를 반환 또는 ID가 확실히 같은 URI에 있으면 안됩니다. 아이들은 있어야합니다.


답변

많은 사람들이 REST가 무엇을 의미하는지 등에 대해 이미 이야기했습니다. 그러나 실제 문제, 즉 디자인을 다루는 사람은 없습니다.

조부모가 아버지와 다른 이유는 무엇입니까? 둘 다 아이를 가질 수있는 아이를 가지고 있습니다.

결국 그들은 모두 ‘인간적’입니다. 아마 당신의 코드에도 있습니다. 그래서 그것을 사용하십시오 :

GET /<api-endpoint>/humans/<ID>

인간에 대한 유용한 정보를 반환합니다. (이름과 물건)

GET /<api-endpoint>/humans/<ID>/children

분명히 자식 배열을 반환합니다. 자식이 없으면 빈 배열이 좋습니다.

예를 들어 ‘hasChildren’플래그를 쉽게 추가 할 수 있습니다. 또는 ‘hasGrandChildren’.

더 똑똑하지 않다고 생각하십시오


답변

모든 grandparentID가 자신의 URL을 가져 오기 때문에 다음은 RESTful입니다. 이런 식으로 리소스가 고유 한 방식으로 식별됩니다.

GET /myservice/api/v1/grandparents/{grandparentID}
GET /myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}

조회 매개 변수 검색은 해당 자원의 컨텍스트에서 검색을 실행하는 좋은 방법입니다.

패밀리가 커지면 시작 / 제한을 쿼리 옵션으로 사용할 수 있습니다. 예를 들면 다음과 같습니다.

GET /myservice/api/v1/grandparents/{grandparentID}/children?start=1&limit=50

개발자는 고유 한 URL / URI를 가진 다른 리소스를 사용하는 것이 좋습니다. 쿼리 매개 변수도 생략 할 수있을 때만 사용해야한다고 생각합니다.

아마도 이것은 http://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling 과 그렇지 않으면 Roy T Fielding의 원래 박사 학위 논문 https://www.ics.uci.edu를 잘 읽었을 것입니다 . /~fielding/pubs/dissertation/fielding_dissertation.pdf 개념을 잘 설명하고 완벽하게 설명합니다.


답변

내가 갈게

/myservice/api/v1/people/{personID}/descendants/2?search={text}

이 경우 모든 접두사는 유효한 자원입니다.

  • /myservice/api/v1/people: 모든 사람들
  • /myservice/api/v1/people/{personID}: 완전한 정보를 가진 한 사람 (조상, 형제 자매, 후손 포함)
  • /myservice/api/v1/people/{personID}/descendants: 한 사람의 자손
  • /myservice/api/v1/people/{personID}/descendants/2: 한 사람의 손자

가장 좋은 대답은 아니지만 적어도 나에게는 의미가 있습니다.


답변

많은 사람들이 이미 URL 형식이 RESTful 서비스의 맥락에서 중요하지 않다고 이미 지적한 바 있습니다. 원래의 글에서 옹호 된 REST의 중요한 측면은 ‘리소스’라는 개념이었습니다. .URL을 디자인 할 때 염두에 두어야 할 한 가지 측면은 ‘리소스’가 단일 테이블의 행이 아니라는 것입니다. 오히려 오히려 표현입니다. . 및 그 표현의 상태를 변경하고 (저장소의 효과적인 매체를 효과적으로 변경하는 데) 사용할 수 있습니다. 그리고 주어진 리소스는 비즈니스 상황에서만 의미가있을 수 있습니다.

귀하의 예에서 / myservice / api / v1 / grandparents / {grandparentID} / parents / children? search = {text}

/ myservice / api / v1 / siblingsOfGrandParents? search =.를 줄이면보다 의미있는 리소스가 될 수 있습니다.

이 경우 ‘siblingsOfGrandParents’를 리소스로 선언 할 수 있습니다. 이렇게하면 URL이 간단 해집니다.

다른 사람들이 지적했듯이 URL에서보다 명시적인 형식으로 도메인 객체 사이의 모든 계층 적 관계 유형에 적합해야한다는 잘못된 오도가 널리 퍼져 있습니다. 도메인 객체와 자원과 모든 관계를 나타냅니다 … 질문은 오히려 믿어야합니다 … URL을 통해 그러한 관계를 드러 낼 필요가 있습니까? 특히 경로 세그먼트 … 아마도 아닙니다.