[api] 상속을 사용하여 RESTful API를 모델링하는 방법은 무엇입니까?

RESTful API를 통해 노출해야하는 객체 계층 구조가 있는데 내 URL이 어떻게 구조화되어야하고 무엇을 반환해야하는지 잘 모르겠습니다. 모범 사례를 찾을 수 없습니다.

동물에서 물려받은 개와 고양이가 있다고 가정 해 보겠습니다. 나는 개와 고양이에 대한 CRUD 작업이 필요합니다. 나는 또한 일반적인 동물에 대한 수술을 할 수 있기를 원합니다.

내 첫 번째 아이디어는 다음과 같이하는 것이 었습니다.

GET /animals        # get all animals
POST /animals       # create a dog or cat
GET /animals/123    # get animal 123

문제는 / animals 컬렉션이 이제 정확히 동일한 구조 (개와 고양이)를 갖지 않는 개체를 반환하고 가져올 수 있으므로 “일관되지 않음”입니다. 서로 다른 속성을 가진 개체를 반환하는 컬렉션을 갖는 것이 “휴식”으로 간주됩니까?

또 다른 해결책은 다음과 같이 각 구체적인 유형에 대한 URL을 만드는 것입니다.

GET /dogs       # get all dogs
POST /dogs      # create a dog
GET /dogs/123   # get dog 123

GET /cats       # get all cats
POST /cats      # create a cat
GET /cats/123   # get cat 123

그러나 이제는 개와 고양이의 관계가 사라졌습니다. 모든 동물을 회수하려면 개와 고양이 자원을 모두 조회해야합니다. URL의 수도 새로운 동물 하위 유형마다 증가합니다.

또 다른 제안은 다음을 추가하여 두 번째 솔루션을 확장하는 것입니다.

GET /animals    # get common attributes of all animals

이 경우 반환 된 동물은 모든 동물에 공통적 인 속성 만 포함하고 개별 및 고양이 별 속성을 삭제합니다. 이렇게하면 세부 사항은 적지 만 모든 동물을 검색 할 수 있습니다. 반환 된 각 객체에는 상세하고 구체적인 버전에 대한 링크가 포함될 수 있습니다.

의견이나 제안이 있으십니까?



답변

내가 제안 할게:

  • 리소스 당 하나의 URI 만 사용
  • 특성 수준에서만 동물 구분

동일한 리소스에 여러 URI를 설정하는 것은 혼란과 예상치 못한 부작용을 일으킬 수 있으므로 결코 좋은 생각이 아닙니다. 따라서 단일 URI는 /animals.

“기본”수준에서 개와 고양이의 전체 컬렉션을 처리하는 다음 과제는 이미 /animalsURI 접근 방식 을 통해 해결되었습니다 .

개와 고양이와 같은 특수 유형을 처리하는 마지막 과제는 미디어 유형 내에서 쿼리 매개 변수와 식별 속성을 조합하여 쉽게 해결할 수 있습니다. 예를 들면 :

GET /animals( Accept : application/vnd.vet-services.animals+json)

{
   "animals":[
      {
         "link":"/animals/3424",
         "type":"dog",
         "name":"Rex"
      },
      {
         "link":"/animals/7829",
         "type":"cat",
         "name":"Mittens"
      }
   ]
}
  • GET /animals -모든 개와 고양이를 얻고 Rex와 Mittens를 모두 반환합니다.
  • GET /animals?type=dog -모든 개를 가져오고 Rex 만 반환합니다.
  • GET /animals?type=cat -모든 고양이를 얻고, 장갑 만

그런 다음 동물을 만들거나 수정할 때 관련된 동물의 유형을 지정하는 것은 호출자에게 있습니다.

미디어 유형: application/vnd.vet-services.animal+json

{
   "type":"dog",
   "name":"Fido"
}

위의 페이로드는 POST또는 PUT요청 으로 보낼 수 있습니다 .

위의 체계는 REST를 통한 OO 상속과 기본적으로 유사한 특성을 제공하며, 주요 수술이나 URI 체계의 변경없이 추가 전문화 (예 : 더 많은 동물 유형)를 추가 할 수있는 기능을 제공합니다.


답변

이 질문은 OpenAPI의 최신 버전에 도입 된 최근 개선 사항의 지원을 통해 더 잘 대답 할 수 있습니다.

oneOf, allOf, anyOf와 같은 키워드를 사용하여 스키마를 결합하고 JSON 스키마 v1.0 이후 검증 된 메시지 페이로드를 얻을 수있었습니다.

https://spacetelescope.github.io/understanding-json-schema/reference/combining.html

그러나 OpenAPI (이전 Swagger)에서는 키워드 판별 자 (v2.0 +) 및 oneOf (v3.0 +)를 통해 스키마 구성이 향상되어 다형성을 진정으로 지원합니다.

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaComposition

상속은 oneOf (하위 유형 중 하나를 선택)와 allOf (유형과 하위 유형 중 하나를 결합)의 조합을 사용하여 모델링 할 수 있습니다. 다음은 POST 메서드에 대한 샘플 정의입니다.

paths:
  /animals:
    post:
      requestBody:
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/Dog'
              - $ref: '#/components/schemas/Cat'
              - $ref: '#/components/schemas/Fish'
            discriminator:
              propertyName: animal_type
     responses:
       '201':
         description: Created

components:
  schemas:
    Animal:
      type: object
      required:
        - animal_type
        - name
      properties:
        animal_type:
          type: string
        name:
          type: string
      discriminator:
        property_name: animal_type
    Dog:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            playsFetch:
              type: string
    Cat:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            likesToPurr:
              type: string
    Fish:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            water-type:
              type: string


답변

나는 개와 물고기의 목록을 반환하는 / animals를 찾으러 갈 것입니다.

<animals>
  <animal type="dog">
    <name>Fido</name>
    <fur-color>White</fur-color>
  </animal>
  <animal type="fish">
    <name>Wanda</name>
    <water-type>Salt</water-type>
  </animal>
</animals>

유사한 JSON 예제를 쉽게 구현할 수 있어야합니다.

클라이언트는 항상 “이름”요소 (공통 속성)에 의존 할 수 있습니다. 그러나 “type”속성에 따라 동물 표현의 일부로 다른 요소가 있습니다.

이러한 목록을 반환하는 데 본질적으로 RESTful 또는 unRESTful은 없습니다. REST는 데이터를 나타내는 특정 형식을 규정하지 않습니다. 데이터에 어떤 표현이 있어야 하며 해당 표현의 형식은 미디어 유형 (HTTP에서 Content-Type 헤더)에 의해 식별됩니다.

사용 사례에 대해 생각해보십시오. 혼합 동물 목록을 표시해야합니까? 그럼 혼합 동물 데이터 목록을 반환합니다. 개 목록 만 필요합니까? 글쎄, 그런 목록을 만드십시오.

/ animals? type = dog 또는 / dogs를 수행하는지 여부는 URL 형식을 규정하지 않는 REST와 관련이 없습니다. 이는 REST 범위 밖의 구현 세부 사항으로 남겨집니다. REST는 리소스에 식별자가 있어야한다고 만 명시합니다. 형식은 신경 쓰지 마세요.

RESTful API에 더 가까워 지려면 하이퍼 미디어 링크를 추가해야합니다. 예를 들어 동물 세부 사항에 대한 참조를 추가하면 다음과 같습니다.

<animals>
  <animal type="dog" href="https://stackoverflow.com/animals/123">
    <name>Fido</name>
    <fur-color>White</fur-color>
  </animal>
  <animal type="fish" href="https://stackoverflow.com/animals/321">
    <name>Wanda</name>
    <water-type>Salt</water-type>
  </animal>
</animals>

하이퍼 미디어 링크를 추가하면 클라이언트 / 서버 커플 링을 줄일 수 있습니다. 위의 경우 URL 구성의 부담을 클라이언트에서 제거하고 서버가 URL 구성 방법 (정의에 따라 유일한 권한 임)을 결정하도록합니다.


답변

그러나 이제는 개와 고양이의 관계가 사라졌습니다.

사실, 그러나 URI는 객체 간의 관계를 결코 반영하지 않는다는 것을 명심하십시오.


답변

이것은 오래된 질문이라는 것을 알고 있지만 RESTful 상속 모델링에 대한 추가 문제를 조사하는 데 관심이 있습니다.

나는 항상 개는 동물이고 암탉이라고 말할 수 있습니다. 그러나 암탉은 알을 만들고 개는 포유류이므로 그렇게 할 수 없습니다. 같은 API

GET animals / : animalID / eggs

동물의 모든 아형이 알을 가질 수 있음을 나타 내기 때문에 일관성이 없습니다 (Liskov 치환의 결과로). 모든 포유류가이 요청에 ‘0’으로 응답하면 대체가있을 수 있지만 POST 메서드도 활성화하면 어떻게됩니까? 내일 크레페에 개 알이 있을까 두려울 까?

이러한 시나리오를 처리하는 유일한 방법은 가능한 모든 ‘파생 리소스’간에 공유되는 모든 하위 리소스를 집계하는 ‘수퍼 리소스’를 제공 한 다음이를 필요로하는 각 파생 리소스에 대한 전문화를 제공하는 것입니다. 죄송합니다

GET / animals / : animalID / sons GET / hens / : animalID / eggs POST / hens / : animalID / eggs

여기서 단점은 누군가가 개 ID를 전달하여 암탉 수집의 인스턴스를 참조 할 수 있지만 개는 암탉이 아니므로 이유 메시지와 함께 응답이 404 또는 400이면 정확하지 않을 것입니다.

내가 잘못?


답변

네, 틀 렸습니다. 또한 관계는 예를 들어이 다형성 방식으로 OpenAPI 사양에 따라 모델링 될 수 있습니다.

Chicken:
  type: object
  discriminator:
    propertyName: typeInformation
  allOf:
    - $ref:'#components/schemas/Chicken'
    - type: object
      properties:
        eggs:
          type: array
          items:
            $ref:'#/components/schemas/Egg'
          name:
            type: string


답변