[rest] REST 중첩 자원에 대한 모범 사례는 무엇입니까?

내가 말할 수있는 한, 개별 자원마다 하나의 표준 경로 있어야 합니다. 다음 예제에서 좋은 URL 패턴은 무엇입니까?

나머지 회사를 예로 들어 보겠습니다. 이 가상의 예에서 각 회사 0 개 이상의 부서를 소유 하고 각 부서 0 개 이상의 직원을 소유 합니다.

관련 회사 없는 부서 는 존재할 수 없습니다 .

관련 부서 없는 직원 은 존재할 수 없습니다 .

이제 리소스 패턴을 자연스럽게 표현했습니다.

  • /companies 회사 모음 -새 회사에 허용됩니다. 전체 컬렉션을 얻으십시오.
  • /companies/{companyId}개별 회사. GET, PUT 및 DELETE 허용
  • /companies/{companyId}/departments새 항목에 대해 POST를 승인합니다. (회사 내에 부서를 만듭니다.)
  • /companies/{companyId}/departments/{departmentId}/
  • /companies/{companyId}/departments/{departmentId}/employees
  • /companies/{companyId}/departments/{departmentId}/employees/{empId}

제약 조건이 주어지면 각 섹션에서 조금 깊게 중첩되면 이것이 의미가 있다고 생각합니다.

그러나 GET모든 회사의 모든 직원 을 나열하려면 ( ) 어려움이 따릅니다.

이에 대한 리소스 패턴은 /employees(모든 직원의 컬렉션)에 가장 밀접하게 매핑됩니다.

그렇다면 /employees/{empId}동일한 리소스를 얻는 두 개의 URI가 있기 때문에 내가 가져야한다는 것을 의미합니까 ?

또는 전체 스키마를 평탄화해야하지만 직원이 중첩 된 최상위 개체임을 의미합니다.

기본 수준 /employees/?company={companyId}&department={deptId}에서 가장 깊게 중첩 된 패턴과 동일한 직원보기를 반환합니다.

다른 리소스 가 리소스를 소유 하지만 별도로 쿼리 할 수 있는 URL 패턴에 대한 모범 사례는 무엇입니까 ?



답변

당신이 한 일은 맞습니다. 일반적으로 동일한 리소스에 대한 많은 URI가있을 수 있습니다. 그렇게하지 말아야 할 규칙은 없습니다.

그리고 일반적으로 항목에 직접 액세스하거나 다른 것의 하위 세트로 액세스해야 할 수도 있으므로 구조가 나에게 적합합니다.

직원이 부서에서 액세스 할 수 있기 때문에 :

company/{companyid}/department/{departmentid}/employees

회사에서도 액세스 할 수 없다는 의미는 아닙니다.

company/{companyid}/employees

그 회사의 직원을 반환합니다. 그것은 소비하는 고객이 필요로하는 것에 달려 있습니다-그것이 당신이 디자인 해야하는 것입니다.

그러나 모든 URL 핸들러가 동일한 백업 코드를 사용하여 요청을 충족시켜 코드를 복제하지 않기를 바랍니다.


답변

중첩 및 비 중첩 엔드 포인트 디자인 전략을 모두 시도했습니다. 나는 그것을 발견했다 :

  1. 중첩 된 리소스에 기본 키가 있고 부모 기본 키가없는 경우 시스템에 실제로는 필요하지 않더라도 중첩 구조를 통해이를 가져와야합니다.

  2. 중첩 된 엔드 포인트에는 일반적으로 중복 엔드 포인트가 필요합니다. 다시 말해, 부서 전체의 직원 목록을 얻을 수 있도록 추가 / 종업원 엔드 포인트가 더 자주 필요합니다. / 직원이있는 경우 / companies / departments / employees가 정확히 무엇을 구매합니까?

  3. 중첩 끝점은 멋지게 발전하지 않습니다. 예를 들어 지금 직원을 검색 할 필요는 없지만 나중에 직원을 검색 할 수 있으며 내포 구조가있는 경우 다른 엔드 포인트를 추가 할 수밖에 없습니다. 중첩되지 않은 디자인에서는 더 많은 매개 변수를 추가하기 만하면됩니다.

  4. 때때로 자원에는 여러 유형의 부모가있을 수 있습니다. 여러 엔드 포인트가 모두 동일한 자원을 리턴합니다.

  5. 중복 엔드 포인트는 문서를 쓰기 어렵게 만들고 API를 배우기 어렵게합니다.

요컨대, 중첩되지 않은 디자인은보다 유연하고 간단한 엔드 포인트 스키마를 허용하는 것으로 보입니다.


답변

질문에서 내가 한 일을 더 많은 사람들이 볼 수있는 대답으로 옮겼습니다.

내가 한 것은 중첩 된 끝점에 생성 끝점 을 두는 것입니다 . 항목을 수정하거나 쿼리하기위한 표준 끝점 은 중첩 된 리소스아닙니다 .

따라서이 예에서 (자원을 변경하는 엔드 포인트 만 나열)

  • POST /companies/ 새 회사를 만들면 만든 회사에 대한 링크가 반환됩니다.
  • POST /companies/{companyId}/departments 부서를 넣을 때 새 부서가 생성되면 /departments/{departmentId}
  • PUT /departments/{departmentId} 부서를 수정하다
  • POST /departments/{deparmentId}/employees 새 직원을 생성하여 /employees/{employeeId}

따라서 각 컬렉션에 대한 루트 수준 리소스가 있습니다. 그러나 작성소유 오브젝트에 있습니다.


답변

위의 답변을 모두 읽었지만 일반적인 전략이없는 것 같습니다. Microsoft Documents의 Design API 모범 사례에 대한 좋은 기사를 찾았습니다 . 나는 당신이 참조해야한다고 생각합니다.

보다 복잡한 시스템에서는 클라이언트가 여러 수준의 관계를 탐색 할 수있는 URI를 제공하려는 유혹이있을 수 있습니다. /customers/1/orders/99/products.그러나 이러한 수준의 복잡성은 유지 관리가 어려울 수 있으며 향후 리소스 간의 관계가 변경 될 경우 융통성이 없습니다. 대신 URI를 비교적 단순하게 유지하십시오 . 응용 프로그램에 리소스에 대한 참조가 있으면이 참조를 사용하여 해당 리소스와 관련된 항목을 찾을 수 있어야합니다. 앞의 조회를 URI /customers/1/orders로 대체하여 고객 1의 모든 주문 /orders/99/products을 찾은 다음 이 주문에서 제품을 찾을 수 있습니다.

.

보다 복잡한 URI를 요구하지 마십시오
collection/item/collection.


답변

URL이 REST와 무관하게 보이는 방식. 무슨 일이든 상관 없습니다 실제로는 “구현 세부 사항”입니다. 변수 이름을 지정하는 것과 같습니다. 그들이 독특하고 내구성이 있어야합니다.

이것에 너무 많은 시간을 낭비하지 말고 선택하고 일관성을 유지하십시오. 예를 들어 계층 구조를 사용하는 경우 모든 리소스에 대해 수행합니다. 코드의 명명 규칙과 같은 쿼리 매개 변수 등을 사용하는 경우.

왜 그래? 내가 “RESTful”API를 탐색 할 수있는 한 ( “애플리케이션 상태 엔진의 하이퍼 미디어”) API 클라이언트는 URL의 길이에 대해 신경 쓰지 않습니다. 유효한 (디버그가 없으며 디버깅을위한 경우를 제외하고는 “친숙한 URL”을 읽어야하는 사람이 없습니다 …)

REST API에 URL이 얼마나 훌륭하고 이해할 수 있는지는 코드의 변수 이름처럼 API 클라이언트가 아니라 API 개발자로서 흥미로울 것입니다.

가장 중요한 것은 API 클라이언트가 미디어 유형을 해석하는 방법을 알고 있다는 것입니다. 예를 들어 다음을 알고 있습니다.

  • 미디어 유형에는 사용 가능한 / 관련 링크를 나열하는 링크 속성이 있습니다.
  • 각 링크는 관계로 식별됩니다 (브라우저가 link [rel = “stylesheet”]가 해당 스타일 시트를 의미하거나 rel = favico가 favicon에 대한 링크임을 의미 함)
  • 이러한 관계의 의미를 알고 있습니다 ( “회사”는 회사 목록을 의미하고 “검색”은 자원 목록을 검색하기위한 템플릿 URL을 의미하고 “부서”는 현재 자원의 부서를 의미)

아래는 HTTP 교환의 예입니다 (작성하기 쉬우므로 본문이 yaml에 있음).

의뢰

GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml

응답 : 주요 자원 (회사, 사람 등 무엇이든)에 대한 링크 목록

HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml

# body: this is your API's entrypoint (like a homepage)
links:
  # could be some random path https://api.acme.local/modskmklmkdsml
  # the only thing the API client cares about is the key (or rel) "companies"
  companies: https://api.acme.local/companies
  people: https://api.acme.local/people

요청 : 회사 링크 (이전 응답의 body.links.companies 사용)

GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml

응답 : 회사 (항목 아래)의 일부 목록에있는 리소스에는 다음 두 회사 (body.links.next)를 검색하는 다른 링크 (템플릿)를 얻는 링크 (body.links.search)와 같은 관련 링크가 포함되어 있습니다.

HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml

# body: representation of a list of companies
links:
  # link to the next page
  next: https://api.acme.local/companies?page=2
  # templated link for search
  search: https://api.acme.local/companies?query={query}
# you could provide available actions related to this resource
actions:
  add:
    href: https://api.acme.local/companies
    method: POST
items:
  - name: company1
    links:
      self: https://api.acme.local/companies/8er13eo
      # and here is the link to departments
      # again the client only cares about the key department
      department: https://api.acme.local/companies/8er13eo/departments
  - name: company2
    links:
      self: https://api.acme.local/companies/9r13d4l
      # or could be in some other location !
      department: https://api2.acme.local/departments?company=8er13eo

따라서 URL의 경로 부분을 구성하는 방법으로 링크 / 관계로 이동하면 API 클라이언트에 아무런 가치가 없습니다. 그리고 URL 구조를 문서로 고객에게 전달하는 경우 REST를 수행하지 않는 것입니다 (또는 ” Richardson의 성숙도 모델 “에 따른 레벨 3 이상 ).


답변

나는 이런 종류의 길에 동의하지 않는다

GET /companies/{companyId}/departments

부서를 원한다면 / departments 리소스를 사용하는 것이 좋습니다

GET /departments?companyId=123

companies테이블과 테이블이 있고 departments사용하는 프로그래밍 언어로 매핑하는 클래스 가 있다고 가정합니다 . 또한 부서를 회사 이외의 다른 엔티티에 연결할 수 있다고 가정하므로 / departments 자원은 간단하며 자원을 테이블에 맵핑하는 것이 편리하며 재사용 할 수 있으므로 많은 엔드 포인트가 필요하지 않습니다.

GET /departments?companyId=123

예를 들어 어떤 종류의 검색이든

GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.

부서를 만들려면

POST /departments

리소스를 사용해야하고 요청 본문에 회사 ID가 포함되어야합니다 (부서가 한 회사에만 연결될 수있는 경우).


답변

Rails는이를위한 솔루션을 제공합니다 : 얕은 네 스팅 .

알려진 리소스를 직접 처리 할 때 여기에 다른 답변에서 논의 된 것처럼 중첩 된 경로를 사용할 필요가 없기 때문에 이것이 좋습니다.